自己动手写操作系统之进程
程序的运行从boot-->loader-->kernel这整个过程中代码都运行在特权级0(最高特权级),进程工作的特权级1(即低特权级),当然这是出于安全性的考虑,如果不考虑安全性,进程
完全可以工作在特权级0.
1. 第一个问题,要从高特权级向低特权级转变,怎么转变呢?这里用到一个人工模拟的中断返回(iretd),这里有个小疑问根据我的了解,iret和iretd都可以表示中断返回,书中是
用的iretd,不知道为什么,当然这并不影响我们对全局的了解,嗯,继续,首先我们要把将要运行在特权级1上的进程所需的寄存器准备好,这个准备好怎么理解呢,具体来说,
cs中保存的是将要从ring0跳转到ring1的进程A的选择子,ds,es,fs等原理一样(应该是数据段描述符),ip应该是进程A第一个条要执行的指令,按照顺序把它们压入栈中
2. 完成上一步一些数据结构是少不了的比如说书中的进程(PROGREE),TSS ,IDT,GDT等
3. 为了以后多进程的考虑我们要把每一个进程放到一个段中,即每个进程一个LDT,所以需要一个在全局描述符表中添加一个局部描述符,当然一个描述符对应一个选择子。
每个局部描述符所指的段中都有什么东西呢?想想看,程序运行需要代码段,需要堆栈,需要数据段,所以LDT中有两个描述符,分别是代码段描述符和数据段(堆栈段)描述符
4. 最后初始化TSS,TSS中只用到了两项,ring0的es和esp,为什么要用到这两项呢?这是在保存ring0状态时寄存器的值
5. 最后细说一下这个中断,其实很好理解,但是我表达的可能不是太好,当从ring1到ring0时,这时会读取TSS的值,TSS中只用到了两项,分别为es和esp,esp记录的是进程
表的位置,进程表位于特权级为0的段中(这个一定要注意),读取TSS的值后,esp就指向了进程表,这时把进程A的状态保存,其实就是把进程A所有的寄存器保存下来,这时候就
进入了ring0,这时就可以执行相应的中断处理,中断处理的内容当然可以包括进程调度,如果这个过程中用到堆栈的话,那么毫无疑问会破坏进程表,为什么呢?因为当压栈完成的
时候esp指向进程表的首地址处,所以此时进程堆栈操作的话会破坏堆栈(但也不是绝对,破坏了在复原就好了,不过这里是容易让人疏忽的地方),所以这里要把堆栈指向另一个位
置,然后在这个位置随意使用。 另外要说的一点事处在ring1的进程没有用到TSS
6. 最后说下《自己动手写操作系统》和linux0.12的区别,0.12是这样实现的,0.12用TSS保存进程的状态,0.12进程进程切换的时候用到了TSS描述符(其实0.12进程切换直接
或者间接都用到了TSS描述符),中断的时候用中断门和陷阱门(没有任务门),由于0.12是用TSS自动保存进程的状态所以中断/切换的时候就直接跳转到相应的处理函数,这里感
觉0.12设计还是要好的,因为用到了TSS的功能,毕竟这是硬件实现,速度上要快,而且要省心不少,《自己》中也用到了TSS,不过给人的感觉只是用到了一小部门功能