什么是实模式与保护模式
简单说,实模式和保护模式最大的区别在寻址大小的区别。对于实模式,只能寻址 1M,每个段最多 64K,系统刚启动的时候就是实模式,不过很短暂,另一种是保护模式,对于 32 位系统,能够寻址 4G。
为什么要分成实模式与保护模式
因为历史原因,操作系统需要兼容之前的处理器。当系统刚刚启动的时候,CPU 是处于实模式的,这个时候和原来的模式是兼容的,只不过这个过程很短暂,很快切入到了保护模式而已。
我们知道x86 中最经典的一款处理器,8086 处理器,8086 的地址总线地址是 20 位。怎么凑够这 20 位呢?方法就是“起始地址 *16+ 偏移量”,也就是把 CS 和 DS 中的值左移 4 位,变成 20 位的,加上 16 位的偏移量,这样就可以得到最终 20 位的数据地址,这样他的寻址能力也就是2^20=1M。
由于偏移量只能是 16 位的,所以一个段最大的大小是 2^16=64k。在 而到了32 位处理器中,有 32 根地址总线,可以访问 2^32=4G 的内存。
所以在 32 位的系统架构下,前一种模式称为实模式,后一种模式称为保护模式。
寄存器类型
要了解操作系统的工作模式,首先要牢记寄存器的类型和作用,如下图所示:
段寄存器
我们知道每个进程都分代码段和数据段,为了指向不同进程的地址空间,有四个 16 位的段寄存器,分别是 CS、DS、SS、ES。
CS 就是代码段寄存器(Code Segment Register),通过它可以找到代码在内存中的位置。
DS (Data Segment)是数据段的寄存器,通过它可以找到数据在内存中的位置。
SS 是栈寄存器(Stack Register),栈是程序运行中一个特殊的数据结构,数据的存取只能从一端进行,秉承后进先出的原则,push 就是入栈,pop 就是出栈。
ES(Extra Segment):附加段寄存器,存放当前执行程序中一个辅助数据段的段地址。
通用寄存器
为了暂存数据,8086 处理器内部有 8 个 16 位的通用寄存器,也就是刚才说的 CPU 内部的数据单元,分别是 AX、BX、CX、DX、SP、BP、SI、DI。这些寄存器主要用于在计算过程中暂存数据。
这些寄存器比较灵活,其中 AX、BX、CX、DX 可以分成两个 8 位的寄存器来使用,分别是 AH、AL、BH、BL、CH、CL、DH、DL,其中 H 就是 High(高位),L 就是 Low(低位)的意思。
IP寄存器
还有一种寄存器叫IP (Instruction Pointer Register)寄存器,就是指令指针寄存器,指向代码段中下一条指令的位置。CPU 会根据它来不断地将指令从内存的代码段中,加载到 CPU 的指令队列中,然后交给运算单元去执行。
实模式与保护模式的切换
上面讲到了,系统刚启动的时候是实模式的,不过很快会进入保护模式,启动的过程比较复杂,我通过一个图总结:
从图中我们可以了解到系统启动的过程,主板家电后第一步会进入BIOS时期。这里ROM 是只读的,上面早就固化了一些初始化的程序,也就是 BIOS(Basic Input and Output System,基本输入输出系统)。
BIOS 完成任务后,会将 boot.img 从硬盘加载到内存中的 0x7c00 来运行。boot.img 先加载的是 core.img 的第一个扇区。如果从硬盘启动的话,这个扇区里面是 diskboot.img,对应的代码是 diskboot.S。boot.img 将控制权交给 diskboot.img 后,diskboot.img 的任务就是将 core.img 的其他部分加载进来,先是解压缩程序 lzma_decompress.img,再往下是 kernel.img,最后是各个模块 module 对应的映像。这里需要注意,它不是 Linux 的内核,而是 grub 的内核。这个时期我们称之为bootloader 时期。