分类: LINUX
2009-03-10 15:19:12
#define switch_to(divv,next,last) do { \ asm volatile("pushl %%esi\n\t" \ //将divv进程的相关寄存器值 "pushl %%edi\n\t" \ //包括esi edi ebp等压栈 "pushl %%ebp\n\t" \ "movl %%esp,%0\n\t" /* save ESP */ \ //保存旧进程的esp栈顶指针到divv->thread.esp里 "movl %3,%%esp\n\t" /* restore ESP */ \ //取出next->thread.esp新进程栈顶指针到esp里,从此内核对next的内核态 //堆栈进行操作,因此这条指令执行从divv到next的真正的上下文切换 "movl $1f,%1\n\t" /* save EIP */ \ //在divv->thread.eip中保存标号为1的地址,该进程恢复执行时执行这指令 "pushl %4\n\t" /* restore EIP */ \ // 取得next->thread.eip压栈 "jmp __switch_to\n" \ // __switch_to()函数执行进一步处理 "1:\t" \ "popl %%ebp\n\t" \ "popl %%edi\n\t" \ "popl %%esi\n\t" \ //先恢复上次被切换走时保存的寄存器值,再从__switch_to()中返回 :"=m" (divv->thread.esp),"=m" (divv->thread.eip), \ "=b" (last) \ /* *因为进程切换后,恢复的栈上的divv信息不是刚被切换 *走的进程描述符,因此此处使用ebx寄存器传递该值给divv */ :"m" (next->thread.esp),"m" (next->thread.eip), \ "a" (divv), "d" (next), \ "b" (divv)); \ } while (0) |
void __switch_to(struct task_struct *divv_p, struct task_struct *next_p) { struct thread_struct *divv = &divv_p->thread, *next = &next_p->thread; struct tss_struct *tss = init_tss + smp_processor_id(); unlazy_fpu(divv_p); /* *执行unlazy_fpu()宏产生的代码,如果divv使用了浮点计算, *则将FPU内容保存在task_struct::thread中 */ /* * Reload esp0, LDT and the page table pointer: */ tss->esp0 = next->esp0; /* *用新进程的esp0(task_struct::thread中)更新init_tss中相应位置的esp0 */ /* * Save away %fs and %gs. No need to save %es and %ds, as * those are always kernel segments while inside the kernel. */ asm volatile("movl %%fs,%0":"=m" (*(int *)&divv->fs)); asm volatile("movl %%gs,%0":"=m" (*(int *)&divv->gs)); /* *在老进程的task_struct::thread中保存当前的fs和gs寄存器, *然后从新进程的task_struct::thread中恢复fs和gs寄存器 * /* * Restore %fs and %gs. */ loadsegment(fs, next->fs);//恢复next的fs,gs loadsegment(gs, next->gs); /* * Now maybe reload the debug registers */ if (next->debugreg[7]){ loaddebug(next, 0); loaddebug(next, 1); loaddebug(next, 2); loaddebug(next, 3); /* no 4 and 5 */ loaddebug(next, 6); loaddebug(next, 7); } //更新IO操作许可权映射表ioperm if (divv->ioperm || next->ioperm) { if (next->ioperm) { /* * 4 cachelines copy ... not good, but not that * bad either. Anyone got something better? * This only affects processes which use ioperm(). * [Putting the TSSs into 4k-tlb mapped regions * and playing VM tricks to switch the IO bitmap * is not really acceptable.] */ memcpy(tss->io_bitmap, next->io_bitmap, IO_BITMAP_SIZE*sizeof(unsigned long)); tss->bitmap = IO_BITMAP_OFFSET; } else /* * a bitmap offset pointing outside of the TSS limit * causes a nicely controllable SIGSEGV if a process * tries to use a port IO instruction. The first * sys_ioperm() call sets up the bitmap properly. */ tss->bitmap = INVALID_IO_BITMAP_OFFSET; } } |
asmlinkage void schedule(void) { … … switch_to(divv, next, divv); … } |