参考了这篇知乎
保护模式
操作系统从开机到开始运行所经历的:
引导 $\rightarrow$ 加载内核进入内存 $\rightarrow$ 跳入保护模式 $\rightarrow$ 开始执行内核
引导扇区(Boot Sector)
引导扇区是整个软盘的第0个扇区, 在引导扇区中有一个重要的数据结构叫BPB(BIOS Parameter Block). 在引导扇区中, 以BPB_开头的域属于BPB, 以BS_开头的域不属于BPB, 只是引导扇区的一部分
引导程序(Boot Loader)
Boot Loader is a small program that places the operating system (OS) of a computer into memory. When a computer is powered-up or restarted, the basic input/output system (BIOS) performs some initial tests, and then transfers control to the Master Boot Record (MBR) where the boot loader resides. Most new computers are shipped with boot loaders for some version of Microsoft Windows or the Mac OS. If a computer is to be used with Linux, a special boot loader must be installed.
实模式
![8086下的寄存器](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/image-20230427174724710.png)
实模式
实模式是早期IBM PC兼容机使用的工作模式
- 物理地址 = 基址(段值) << 4 + 偏移量
但是
实模式下的中断
保护模式
保护模式是Intel 80386处理器后引入的一种新工作模式
保护模式为了实现对虚拟内存的支持, 引入了段描述符 (Segment Descriptor) 与描述符表 (Descriptor Table) 的概念. 描述符表记录了内存空间中每个段的信息, 并且以表格的形式呈现. 其中的每一个表项, 为一个段描述符. 每个描述符占 64 个bit
![段描述符的数据结构](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/v2-67e197557d184ab5524f291b9702e5f6_1440w.webp)
描述符表有多种类型, 并不呈并列关系:
- GDT: Global Descriptor Table: 系统级别的描述符表, 存放一些公用的描述符 (比方说系统段描述符), 和包含各进程 LDT 首地址的描述符.
- LDT: Local Descriptor Table: 进程级别的描述符表, 存放本进程内使用的描述符.
- IDT: Interrupt Descriptor Table (中断描述符表): 存储各种中断
异常和陷阱事件的处理程序 (也称为中断服务例程).、
在这里我们主要研究 GDT 和 LDT. 为了索引 GDT 和 LDT, 我们引入了两个专用的寄存器:
- GDTR: 48位寄存器
高 32 位放置GDT首地址, 低16位放置GDT限长 (要想查询系统级别的公用的描述符, 进程需要从 GDTR 寄存器中获得 GDT 的首地址, 向它发起查询. ), - LDTR: 16位寄存器
放置一个特殊的选择子, 用于查找当前进程的 LDT 首地址. (要想查询当前进程的描述符, 进程从 LDTR 寄存器中获得 LDT 的首地址, 向它发起查询.),
GDTR / LDTR 中存储的数据结构叫做选择子 (Selector), 用来指向 DT 中的一个表项.
-
[4, 16) 用于表示一个偏移量, 指向了GDT或LDT中的某个段描述符.
-
[3, 4) TI 为0说明指向GDT, 否则指向LDT
-
[0, 3) Request Privilege Level (请求特权级)
![img](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/v2-b1d5012ea6cf544ccd3a5411271d50b1_r.jpg)
LDT 和 GDT 从本质上说是相同的, 但是 LDT 嵌套在GDT 之中. LDTR 记录 LDT 的起始位置. 与 GDTR 不同, LDTR 的内容是一个段选择子. 由于 LDT 本身同样是一段内存
使用 GDT 索引物理地址
![这个图丑是丑点但是还蛮形象的](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/image-20230427183259692.png)
使用 LDT 索引物理地址
![img](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/LDT%E6%9F%A5%E8%AF%A2%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80.jpg)
具体来说, 保护模式下的寻址过程 (逻辑地址 $\to$ 物理地址) 如下:
- 解析逻辑地址
在保护模式下: 程序员使用的是逻辑地址, 需要将其转换为物理地址, 这个过程由硬件中的内存管理单元。 Memory Management Unit, MMU( 完成) 。 - 分段
分段是指将线性地址: 即逻辑地址( 划分为不同的段) 每个段具有特定的属性和权限, 例如代码, 数据、 堆栈等、 这个过程由操作系统中的段描述符表。 Segment Descriptor Table( 控制) 。 - 段选择器
为了访问某个段: 需要使用一个称为段选择器的值, 它实际上是一个索引, 指向段描述符表中的一个条目, 这个过程由CPU中的段寄存器完成。 。 - 计算物理地址
通过组合段基址和偏移量来计算出物理地址: 其中段基址是段描述符表中的一个字段。 而偏移量则是程序员在代码中使用的相对地址, 。 - 访问内存
最后一步是使用计算出的物理地址来访问内存中的数据: 。
接下来我们研究IDT:
为了索引 IDT, 我们引入一个专门的寄存器叫做 IDTR: IDT表可以驻留在线性地址空间的任何地方
IDT在保护模式下用来存储各种类型的中断描述符. IDT存储的中断描述符总共有三种: 任务门
![](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/intgate-20230525162706859.jpg)
主要包含段选择子, 偏移量, 一些类型信息, 一些属性信息.
保护模式下的中断
保护模式下中断程序地址如何得到?
- 首先
我们先从IDTR 寄存器中获取到中断描述符表对应的段基址和段限长, 这就得到了中断描述符表, 。 - 然后
我们用中断类型码 × 8得到相应的中断描述符的存储起始地址的偏移量, 这就得到了中断类型码对应的中断门 (根据定义, 中断门是一种中断描述符), - 最后
我们从中断门中得到段选择符和偏移量, 以段选择符为段选择子, 再根据第2位的情况, 从GDT或LDT得到相应的段描述符, 结合偏移量, 得到相应中断处理程序的起始地址, 。