/* * 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 }
|