在最近的学习中,我试着把自己学习的知识点先记录在本子上,然后总结所学。
在之前有一段时间比较迷茫,因为感觉大部分的博客都是在抄书,在思考博客抄书究竟有什么价值,东抄抄,西抄抄还不如看书呢。最后总结发现,博客不是不可以抄书,因为我还是学生,更多的学习途径是看书,所以难免会不自觉的去抄书,最后发现,我觉得可以更多的是对书本上知识的总结,对所学知识的回顾,并将它写出来。好了闲话不多说了,还是进入主题吧。
由实模式进入保护模式
首先,我们先考虑为什么需要从实模式进入保护模式呢,难道我们不能直接就进入保护模式么。
实际上,这是为了确保传统操作系统的向前兼容性,因为所有的X86CPU都在实模式下开机,在任何保护模式的特性可用之前,它们都必须由某些程序手动的切换到保护模式,这便是操作系统在开机时通常必须完成的第一件任务。
其次,让我们说一说实模式与保护模式的不同:
我觉得实模式与保护模式最大的不同之处就是进程内存空间(安全性增加)是否受保护。
实模式:用CS:IP(即物理地址=左移4位的段地址+偏移地址)模式的寻址方式来进行寻址,因为实模式是16位寻址,所以其只能访问地址在1M以下的内存(称为常规内存)。可寻址任意地址,所有指令都相当于工作在特权级。
保护模式:通过段页式管理进行寻址,保护模式是32位寻址,它可以访问4G的内存(称为扩展内存)。支持多任务,可依靠硬件用一条指令即可实现任务切换,不同任务可工作在 不同的优先级下,操作系统工作在最高优先级0上,应用程序则运行 在较低优先级 上。从实模式到保护模式,需要建立GDT、IDT等数据表,然后通过修改控制寄存 器CR0的控制位(位0)来实现。 引入了特权级,有4个安全级别,内存操作时有相应的特权级检查,因为存在分页功能,因此有虚拟地址和物理地址的区别;
由实模式到保护模式执行的步骤:
计算GDT所在的逻辑地址段;
创建空描述符(处理器要求),创建代码段描述符,创建数据段描述符,创建堆栈段描述符;
初始化描述符表寄存器(GDTR)。(修改描述符表的界限,将GDT界限值和GDT基地址加载到GDTR寄存器中);
打开A20;
设置PE位;
进入保护模式(清流水线并串型化处理处理器,用jmp ……实现)。
以上便是由实模式进入保护模式的超简化步骤。具体细节请细读《X86汇编 从实模式到保护模式》第十一章。
程序的动态加载和执行
上面讲了大概由实模式转换到保护模式的步骤,但是举例程序的执行,还缺少了我们熟知的操作系统。
操作系统当然不能放到引导扇区中,毕竟它实在是太大了,毕竟引导扇区只有512字节。计算级首先从主引导程序开始执行,主引导程序负责加载内核,并转交控制权。然后,内核负责加载用户程序,并提供各种例程给用户程序调用。
程序加载和执行
(1)计算机启动后,先进行实模式到保护模式的转换步骤。(上面提到过)。
(2)加载内核
从硬盘中将内核程序读入内存;
从读来的内核代码的头部建立相应的代码段,数据段,公共段;
重新加载GDTR,使上面添加的段生效。
(3)转移执行权到内核
加载用户程序;
从硬盘读取用户程序到内存(需要相应的内存分配);
对用户程序各段进行重定位,添加用户程序。
对内和来说维护一个CSALT(第二部分的例程地址入口包括4字节的偏移地址和2字节的段选择字),用户程序维护一个USALT。(SALT为符号-地址对照表,当用户程序加载以后,内核应该根据这些符号名来回填他们对应的入口地址,这称为符号地址的重定位,重定位的过程就是字符串匹配和比较的过程)。
(图中左为CSALT右为USALT)
(4)进行完匹配后内核将执行权交给用户。
具体细节请细读《X86汇编 从实模式到保护模式》第十二章。
部分参考:x86 实模式与保护模式
对于GDT和LDT需要进一步了解的话GDT(全居描述符表)和LDT(局部描述符表)