
iret指令,用户栈就切过来了,PC指针也切过去了
实现过程


前面的东西都是用户态的,所以需要把用户态的东西在内核态中保存起来
将来返回的时候还需要用到
按照老师的意思,这里严格来说仍然处于用户态,在做进入内核态的准备工
首先会将当前用户态的寄存器等数据放入内核栈中(保存现场),push%ds…%fs,pushl%edx等等,要把用户态的信息保存,因为以后还要返回
切换有五段论,第一段是中断入口,实际上就是建立内核栈与用户栈之间的关联
之后进入内核,在内核中会执行,在执行的时候会发现,某些进程/线程可以不执行,比如说在内核当中发现某进程是启动磁盘读,那可以不让你读,这个时候就会引发切换,所以说在内核中的时候会判断一个事件来引发切换,判断这个事件来引发切换,这就是内核级线程五段论之间的中间三段,在sys_fork执行过程当中,会发现不要执行,但是sys_read之类发现磁盘已经读写了,必须等待。
sys_fork在执行的过程中被打断调度切换的可能性比较小(但也是有可能的)(因为可能判断这个操作不要执行,比如读操作),sys_read和sys_wite的可能性比较大,因为已经启动磁盘读写了,必须等待
iret完成用户栈到内核栈的切换cmp $0, state(%eax)中的0,state非0意味着阻塞,阻塞了得重新调用)是在什么时候设置的?应该是在sys_fork、sys_write等这些系统调用的功能性代码内部设置的
ret_from_sys_call这个地址压入栈中c函数schedule,在schedulel函数运行到最后的右括号时,就会从栈中取出返回地址ret_from_sys_callschedule函数的右括号,就会回到ret_from_sys_call标号的位置reschedule的时候,老师说schedule执行完后,会回到ret_from_sys_call,感觉这里讲得不是很精细,schedule执行完后应该会切换到另一个线程(另一个线程在之前陷入内核时不一定是系统调用吧?),除非调度的结果仍然是当前线ret_from_sys_call标号的位置
pop是哪里来的?是ret_from_sys_call这里来的,所以这个代码一定要执行ret_from_sys_call,和之前_system_call的指令对应,按照倒序pop恢复寄存器等现场信息,最后是iret指令,iret之后,肯定就是切换到下一个内核级线程(下一个进程)ret_from_sys_call这部分代码,是在下次调度到这个线程的时候才会执行,或者可以把这里讲的ret_from_sys_cal看成是属于切换后的线程的(这个线程当初也是通过某个系统调用陷入内核的)schedule引发的东西:找下一个内核级线程,即为调度next是调度后的下一个内核级线程的TCBswitch_to切换switch_to,怎么做到的呢?switch_to在linux0.11的TSS实现方案ljmp %0\n\t即可进行切换switch_to中关键是ljmp %0ljmp是长跳转指令,实际上是跳转segment,每个段都要有个段描述符

下图中,ljmp指令是长跳转指令,即TSS段的跳转切换,使用TR寄存器+GDT表,在上一张图中画了,TR是TSS段的选择符,拿这个选择符去查GDT表,找到对应的TSS描述符,这个TSS描述符指向了TSS的内容。下图中,n表示调度选择的下一个进程编号,那么TSS(n)就是下一个进程对应的cs,指向下一个进程的TSS后,就把其中的数据赋给寄存器等,恢复现场

int,ljmp,iret(1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

??4 就是call _copy_process的时候的PC,对应指令addl $20, %esp??2 就是call _sys_fork的时候的PC,翻到上面的图可以看到,对应的指令是pushl %eaxint 0x80中断到call _sys_fork之前就准备好的,右部分的内容是进入_sys_fork后才准备的参数
copy_process的细节:创建子进程的栈
copy_process的细节:执行前准备



加油