运行在特权级3

Published: by Creative Commons Licence

运行在特权级3

阅读并实践《一个操作系统的实现》和《操作系统真象还原》

最近学到用户进程这部分,但是在从特权级0用iret返回到特权级3这里一直出错,所以记录一下出错原因,自我反省。

  • 错误一:pop出来的值是0

在iret前会有一系列pop,可是我将esp值改为保存应pop出来的值的地址后,pop出来的值都是0,esp正常加4,可是保存的值绝对不是0,最后没办法,只能将应pop出来的值保存到栈上,然后在pop,这样就没有问题
发现是因为数据的段描述符中D/B位未设置,D/B位决定了操作数是16位还是32位,如果是数据段,并且D/B位未设置,那么push,pop都是操作sp而不是esp

  • 错误二:页目录项和页表项的U/S位

iret可以成功返回到特权级3的代码,可是特权级3的代码一运行就出错,跳到IDT异常里面,通过查看错误码,发现是第14号错误,也就是缺页异常,可是查看cr3寄存器,发现里面的值并没有改变,页目录项和页表项也没有改变,一直百思不得其解,后面在看了《操作系统真相还原》里面的相关部分,才发现页目录项和页表项的U/S位要置1,特权级3才能访问虚拟地址。

  • 错误三:eflags的IOPL位

解决上面的问题后运行发现,会在端口操作的时候出现问题,当然,这个就没有太纠结,直接知道应该是eflags的IOPL位没有设置好,设置IOPL为11后,成功运行

   call_gate

iret返回相关设置:

TSS结构设置:

  • 设置TSS描述符和TSS结构

1.在GDT中设置TSS描述符,其中基地址是TSS结构体的地址,范围可以是TSS结构体的大小,描述符的type字段应是二进制1001,S位为0。
2.TSS结构只要初始化ss0和esp0,因为现在暂时还用不到其他的特权级,而ss0和esp0是在发生中断是会使用到的堆栈地址,I/OMap Base Address可以设为TSS结构体大小,表示没有I/O许可位图。

   call_gate

堆栈设置:

  • 栈上保存要pop到各寄存器的值,以及eip,cs,eflags,esp,ss的值

eip,cs,eflags,esp,ss的值顺序应如下所示

   call_gate