热门关键字:  ubuntu  分区  函数  Fedora  linux系统进程

当前位置 :| 主页>Linux教程>内核研究>

Linux进程:Linux切换机制主流程

来源: 作者: 时间:2008-08-07 Tag: 点击:
Linux切换并没有使用X86CPU的切换方法,Linux切换的实质就是cr3切换(内存空间切换,在switch_mm函数中)+ 寄存器切换(包括EIP,ESP等,均在switch_to函数中)。这里我们讲述下switch_to主流程:

在switch_mm函数中将new_task->pgd设置到cr3寄存器中,实现页表切换,由于每个进程3- 4G的页表映射机制完全一样(从内核页表中直接复制过来的),故这里虽然切换了pgd,但是并无影响,只是在任务回到用户空间中时,才会发生变化,因为每个任务在0-3G中的页表映射都是各自独立的;
压入esi edi ebp到cur_task堆栈中;
将esp寄存器中的值保存到cur_task.task_struct.thread.esp中,也就是将cur_task切换时的堆栈指针保存起来;
将new_task.task_struct.thread.esp 中的值设置到esp寄存器中,这里的new_task.task_struct.thread.esp中的值就是new_task上一次被换出时的堆栈指针,现在被恢复了,2和3结合实现了从cur_task到new_task的堆栈切换;
将1f地址设置到cur_task.task_struct.thread.eip中,当下次cur_task恢复运行时,将会从1f处开始运行,下面阐述了这种原理;
将new_task.task_struct.thread.eip 压入到new_task的堆栈中,这里new_task.task_struct.thread.eip的值就是1f,因为从4中可知,new_task 上一次被换出时,其也是和现在的cur_task类似,1f地址被设置到new_task.task_struct.thread.eip中;
随后CPU跳转到__switch_to函数(注意,在__switch_to中,做了一件非常重要的事情就是让init_tss.esp0= new_task.task_struct.esp0,原因见【C.Linux进程:Linux进程管理和X86进程管理的结合】一文)中开始执行,注意这里使用的是jmp,不是call,call会pusheip,而jmp不会,由于__switch_to是函数,当CPU执行完该函数后,最后一条指令必然为iret,该指令会popeip,从5中可以知道,此时new_task堆栈中的镜像为[......., esi,edi,ebp,eip(&1f)],故popeip将值eip(&1f)设置到eip寄存器中,这样当iret执行完毕后, CPU将从eip处继续执行,也就是从1f处继续执行;;
此时已经在new_task的执行环境中了,pop ebp, pop edi, popesi,回到schedule函数中,当返回用户空间中时,由于new_task用户空间的eip,ss,esp等均被从new_task的堆栈中弹出到对应寄存器中,从而new_task得以顺利执行;

switch_to中cur_task寄存器保存、new_task寄存器恢复的几个问题:

GCC在编译该段代码时,会注意到EAX,EBX,EDX在这里被使用,因此此处无需要显示的用汇编语句来保存这三个寄存器,GCC在编译时会自动考虑添加对这些寄存器的保护;
最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册