在浅谈-计算机加电后的启动过程(一)中,已经谈了从开机后到实模式的过程, 这次我们继续浅谈一下保护模式下发生的事情。
这次我们先看看都发生了那些事, 然后在谈为什么会有这些事情。
总览
上一篇谈到了加载器, 加载器是从实模式过渡到保护模式的。
在加载器中,首先先建立全局描述符表。接下来准备进入保护模式。
进入保护模式的三要素:
- 打开A20
- 加载GDT
- 将cr0的pe位置为1
进入保护模式后,启用分页机制,然后开始加载内核。
实模式和保护模式
起初是没有实模式这一说法的。只是这种模式有很多缺点,然后为了克服这些缺点,就出现了保护模式,为了分离这两种不同的模式,就给前一种起名为实模式。
实模式的缺点:
- 实模式下操作系统和用户程序属于同一特权级。
- 用户程序所引用的地址都是指向真实的物理地址,也就是说逻辑地址等于物理地址。
- 用户程序可以自由修改段基址,可以随意的访问所有内存
- 访问超过 64KB 的内存区域时要切换段基址。
- 一次只能运行一个程序,无法充分利用计算机资源。
- 共 20 条地址线,最大可用内存为 1MB。
综上:实模式太危险, 所以引入了保护模式。
建立全局描述符表
全局描述符表(GDT):保护模式下内存段的登记表, 表里的每一项都是一个段描述符。想要访问哪一段内存,必须先在GDT中登记。
全局描述符: GDT中第0个段描述符不可用。
为什么称为全局描述符?
全局体现在多个程序都可以在里面定义自己的段描述符,是公用的。全局描述符表位于内存中, 需要用专门的寄存器指向它后, CPU 才知道它在哪里。这个专门的寄存器便是 GDTR。
段描述符, 段描述符就是一个结构体,大小为8个字节。用来描述这一个内存段的各个属性的。
段描述符详细信息如图:
上面为高32位,下面为低32位。
-
段描述符的低 32 位分为两部分,前 16 位用来存储段的段界限的前 0~15 位,后 16 位用来存储段基址的 0~15 位。
-
8~11 位是 type 字段,共 4 位,用来指定本描述符的类型。
-
一个段描述符,在 CPU 眼里分为两大类,要么描述的是系统段,要么描述的是数据段,这是由段描述符中的 S(第12位) 位决定的,用它指示是否是系统段。
-
段描述符的第 13~14 位是 DPL 字段, Descriptor Privilege Level,即描述符特权级,这是保护模式提供的安全解决方案,将计算机世界按权力划分成不同等级,每一种等级称为一种特权级。
-
段描述符的第 15 位是 P 字段, Present,即段是否存在。如果段存在于内存中, P 为 1,否则 P 为 0。P 字段是由 CPU 来检查的,如果为 0, CPU 将抛出异常,转到相应的异常处理程序段描述符的第 16~19 位是段界限的第 16~19 位。这样共 20 位的段界限就齐全啦。
-
段描述符的第 20 位为 AVL 字段,从名字上看它是 AVaiLable,可用的。不过这“可用的”是对用户来说的,也就是操作系统可以随意用此位。
-
段描述符的第 21 位为 L 字段,用来设置是否是 64 位代码段。 L 为 1 表示 64 位代码段,否则表示 32位代码段。这目前属于保留位,在我们 32 位 CPU 下编程,将其置为 0 便可。
-
描述符的第 22 位是 D/B 字段,用来指示有效地址(段内偏移地址)及操作数的大小。
-
段描述符的第 23 位是 G 字段, Granularity,粒度,用来指定段界限的单位大小。所以此位是用来配合段界限的,它与段界限一起来决定段的大小。若 G 为 0,表示段界限的单位是 1 字节,这样段最大是 2的 20 次方1 字节,即 1MB。若 G 为 1,表示段界限的单位是 4KB,这样段最大是 2 的 20 次方4KB 字节,即 4GB。
选择子:选择子“基本上”是个索引值。是在全局描述表中索引段描述符的。此时,全局描述符表就相当于是一个数组。而选择字则是下标。这样就能获得段描述符中的内容了。
选择子的作用主要是确定段描述符,确定描述符的目的,一是为了特权级、界限等安全考虑,最主要的还是要确定段的基地址。
由于段寄存器是 16 位,所以选择子也是 16 位,在其低 2 位即第 0~1 位,
用来存储 RPL,即请求特权级,可以表示 0、 1、 2、 3 四种特权级。此处可以理解为请求者的当前特权级,在选择子的第 2 位是 TI 位,即 Table Indicator,用来指示选择子是在 GDT 中,还是 LDT 中索引描述符。 TI为 0 表示在 GDT 中索引描述符, TI 为 1 表示在 LDT 中索引描述符。选择子的高 13 位,即第 3~15 位是描述符的索引值,用此值在 GDT 中索引描述符。前面说过 GDT 相当于一个描述符数组,所以此选择子中的索引值就是 GDT 中的下标。
由于选择子的索引值部分是 13 位,即 2 的 13 次方是 8192,故最多可以索引 8192 个段,这和 GDT中最多定义 8192 个描述符是吻合的。
进入保护模式的三要素
打开A20地址线
在实模式下,一共只有20根地址线,只能索引1MB内存,如果超过FFFFF,时,则进行进位 为100000,在计算机内部则看为00000, 地址回绕.
对于 80286 后续的 CPU,通过 A20Gate 来控制 A20 地址线。
如果 A20Gate 被打开,当访问到 0x100000~0x10FFEF 之间的地址时, CPU 将真正访问这块物理内存。
如果 A20Gate 被禁止, 当访问 0x100000~0x10FFEF 之间的地址时, CPU 将采用 8086/8088 的地址回绕。
综上:需要打开A20地址线
加载GDT
将在内存中建立号的GDT的地址存放到 GDTR(GDT 寄存器)中。
将CR0的PE位置为1
CRX系列寄存器为控制寄存器。
CR0的第0位为 PE位,若此位为0,则代表在实模式下运行, 若为1,则代表在保护模式下运行。
到此,计算机已经进入保护模式了。
接下来就是开启分页机制,加载内核。而这个分页机制要谈的也比较多。这里就先告一段落。