/*
* FIXME: This function should really be written in assembly. Actually
* requirement is that it does not touch stack, because %esp will be
* wrong during resume before restore_processor_context(). Check
* assembly if you modify this.
*
* SMP support:
* All SMP processors enter this routine during suspend. The one through
* which the suspend is initiated (which, for simplicity, is always CPU 0)
* sends the others here using an IPI during do_swsusp2_suspend_1. They
* remain here until after the atomic copy of the kernel is made, to ensure
* that they don't mess with memory in the meantime (even just idling will
* do that). Once the atomic copy is made, they are free to carry on idling.
* Note that we must let them go, because if we're using compression, the
* vfree calls in the compressors will result in IPIs being called and hanging
* because the CPUs are still here.
*
* At resume time, we do a similar thing. CPU 0 sends the others in here using
* an IPI. It then copies the original kernel back, restores its own processor
* context and flushes local tlbs before freeing the others to do the same.
* They can then go back to idling while CPU 0 reloads pageset 2, cleans up
* and unfreezes the processes.
*
* (Remember that freezing and thawing processes also uses IPIs, as may
* decompressing the data. Again, therefore, we cannot leave the other processors
* in here).
*
* At the moment, we do nothing about APICs, even though the code is there.
*/
void do_swsusp_lowlevel(int resume)
{
// int xx_nr = 0;
if (!resume) {
//suspend code
do_swsusp2_suspend_1();
printk("save_processor_context.\n");
save_processor_context(); /* We need to capture registers and memory at "same time" */
printk("After save_processor_context.");
do_swsusp2_suspend_2(); /* If everything goes okay, this function does not return */
return;
}
printk("swapper_pg_dir = %#x\n",swapper_pg_dir); //0x802da000
/* We want to run from swapper_pg_dir, since swapper_pg_dir is stored in constant
* place in memory
*/
/*bob,this is not necessary for x86 and MIPS architecture
* especially,MIPS doesn't care PageTable, but care TLB
*/
// __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swapper_pg_dir)));
// asm volatile("movl %0,%%cr3"::"r" (__pa(swapper_pg_dir)));
/*
* Final function for resuming: after copying the pages to their original
* position, it restores the register state.
*
* What about page tables? Writing data pages may toggle
* accessed/dirty bits in our page tables. That should be no problems
* with 4MB page tables. That's why we require have_pse.
*
* This loops destroys stack from under itself, so it better should
* not use any stack space, itself. When this function is entered at
* resume time, we move stack to _old_ place. This is means that this
* function must use no stack and no local variables in registers,
* until calling restore_processor_context();
*
* Critical section here: no one should touch saved memory after
* do_swsusp2_resume_1; copying works, because nr_copy_pages,
* pagedir_resume, loop and loop2 are nosavedata.
*/
do_swsusp2_resume_1();
printk("after do_swsusp_resume_1() \n");
printk("Calling dump_stack() , file(%s),function(%s),line(%d) \n", __FILE__,__FUNCTION__,__LINE__);
dump_stack();
#if 1
state1 = swsusp_action;
state2 = swsusp_debug_state;
state3 = console_loglevel;
// c_loops_per_jiffy_ref = cpu_data->loops_per_jiffy;
// cpu_khz_ref = cpu_khz;
origrange = pagedir_resume.origranges.first;
copyrange = pagedir_resume.destranges.first;
origoffset = origrange->minimum;
copyoffset = copyrange->minimum;
origpage = (unsigned long *) (page_address(mem_map + origoffset));
copypage = (unsigned long *) (page_address(mem_map + copyoffset));
printk("origoffset=%d\n",origoffset);
printk("copyoffset=%d\n",copyoffset);
// printk("will loop \n");
#if 1
while (origrange) {
printk("in loop copy \n");
printk("Calling dump_stack() , file(%s),function(%s),line(%d) \n", __FILE__,__FUNCTION__,__LINE__);
dump_stack();
printk("================origoffset(%d), origrange->maximum=%d==============\n",origoffset,origrange->maximum);
printk("================copyoffset(%d),copyrange->maximum=%d=============\n\n",copyoffset,copyrange->maximum);
//copy page content from copy page into original page,this is in physical memory
for (loop=0; loop < (PAGE_SIZE / sizeof(unsigned long)); loop++)
*(origpage + loop) = *(copypage + loop);
/* use memcpy function */
//memcpy((char *)origpage,(char *)copypage,PAGE_SIZE);
if (origoffset < origrange->maximum) {
origoffset++;
origpage += (PAGE_SIZE / sizeof(unsigned long));
} else {
origrange = origrange->next;
if (origrange) {
origoffset = origrange->minimum;
origpage = (unsigned long *) (page_address(mem_map + origoffset));
printk("will to next chain\n");
printk("origrange->maximum=%d\n\n\n",origrange->maximum);
}
}
if (copyoffset < copyrange->maximum) {
copyoffset++;
copypage += (PAGE_SIZE / sizeof(unsigned long));
} else {
copyrange = copyrange->next;
if (copyrange) {
copyoffset = copyrange->minimum;
copypage = (unsigned long *) (page_address(mem_map + copyoffset));
}
}
}
#endif
printk("will restore_processor_context() \n");
restore_processor_context();
//flush TLB ,bob
//__flush_tlb_all();
printk("will flush_tlb_all() \n");
flush_tlb_all();
/* Get other CPUs to restore their contexts and flush their tlbs. */
/*
swsusp_state &= ~FREEZE_SMP;
while (atomic_read(&swsusp_cpu_counter)) {
cpu_relax();
smp_mb();
}
*/
/* Ahah, we now run with our old stack, and with registers copied from
suspend time */
// cpu_data->loops_per_jiffy = c_loops_per_jiffy_ref;
// loops_per_jiffy = c_loops_per_jiffy_ref;
// cpu_khz = cpu_khz_ref;
swsusp_action = state1;
swsusp_debug_state = state2;
console_loglevel = state3;
printk("will into do_swsusp2_resume_2() \n");
do_swsusp2_resume_2();
#endif
}
|