问题描述
在 Real Mode 下,程序通过 Segment : Offset 方式,可以访问任意内存地址。
这种做法并不好,多个程序之间会相互干扰,带来不可预料的后果。
解决方法
引入保护模式(Protected Mode)。在 Protected Mode 下,依旧使用 Segment : Offset 来访问内存。
但是,此时的 Segment 称为段选择器(Segment Selector),而不是段地址(Segment Address)。当然,它们都是保存在段寄存器中的数值,只是数据结构与解释方法不同。
段选择器(Segment Selector)的值指向在描述符表(Descriptor Table)中的某个描述符(Segment Descriptor)。
而描述符(Segment Descriptor)定义了实际内存段的基地址、段界限(Offset 不能超过该界限)、各种访问属性及权限。
当程序指令访问内存时,比如 MOV [DS:BX], 0x0H 指令,处理器通过 Segment Selector 找到 Segment Descriptor 后,处理器通过 Segment Descriptor 的信息找到内存段,来检查程序是否能够访问该段。
段描述符(Segment Descriptor)
段描述符(Segment Descriptor)有很多种,长度为 8B(或者其他长度),描述内存段的基地址、边界(段长度)、类型权限等等其他属性。
因为类型不同,所以结构不同。
描述符表(Descriptor Table)
所有的 Segment Descriptor 放在一起,形成 描述符表(Descriptor Table)。
因为 Segment Descriptor 有很多种,所以 Descriptor Table 也有很多种
我们也不知道为什么不使用”段描述符表“,而使用”描述符表“。
描述符表寄存器(Descriptor Table Register)
处理器从程序中得到 Segment Selector 后,需要知道 Segment Descriptor,以从中找到对应的 Segment Descriptor,而 Segment Descriptor 的位置保存在 描述符表寄存器(Descriptor Table Register)中。
因为 Descriptor Table 有很多种,所以 Descriptor Table Register 也有很多种。
全局描述符表(Global Descriptor Table)
全局描述符表(Global Descriptor Table),是一种描述符表,比较重要,为整个软硬件系统服务。
该表可以位于内存中的任何位置(就是这么设计的,所以在 GDTR 中的线性基地址 32 bits)。但是,由于需要在进入 Protected Mode 前设置 GDT,此时处于 Real Mode,因此 GDTR 位于内存中 1MB 以下位置(除非在进入 Protected Mode 后重新设置)。
每个表项 8 字节,该表最大 2^16 字节,最多 8192 个表项。(就是这么设计的,所以在 GDTR 中的边界值的位数为 16 bits)
全局描述符的结构
G:Granularity bit. If 0 the limit is in 1 B blocks (byte granularity), if 1 the limit is in 4 KiB blocks (page granularity).
D/B:对于代码段,此位称之为“D”位。D=0,表示该段内的指令的偏移地址或操作数是 16-bit 的,并使用 IP 取指;D=1,表示该段内的指令的偏移地址或操作数是 32-bit 的,并使用 EIP 取指。对于栈段,此为称之为“B”位。B=0,将使用 SP 寄存器;B=1,将使用 ESP 寄存器。
L:64-bit 代码段标志,保留此为给 64-bit 处理器使用。对于 32-bit 模式,设置 L=0 即可。
AVL(Available):操作系统可以使用的位。
P(Present):该描述符指向的内存段是否存在于内存中。比如在内存紧张时,只建立该描述符,而该描述符指向的内存可能保存在交换分区。当处理器通过该描述符访问内存时,如果 P=0 将引发中断,由操作系统处理该中断(读取在交换分区中对应的数据到内存中)
DPL(Descriptor Privilege Level):该描述符的特权级别,0-4,其中 0 最高。
S:描述符类型。S=0,表示系统段;S=1,表示代码段或数据段(栈段也是数据段)。
TYPE:描述符的子类型。对于数据段,该四位为 XEWA;对于代码段,该四位为 XCRA。
全局描述符表寄存器(Global Descriptor Table Register)
全局描述符表寄存器(Global Descriptor Table Register),GDTR,用于保存 GDT 位置。
长度 48 bits:
1)00-15:16 bits,GDT 边界,即 GDT 的总字节数减一;
2)16-47:32 bits,GDT 线性基地址,即 GDT 在内存中的起始位置。
参考文献
Global Descriptor Table – OSDev Wiki