理论讲解:保护模式

1. 为什么需要保护模式

实模式(Real Mode)有严重的限制:

实模式保护模式
16位操作32位操作
只能访问1MB内存可访问4GB内存
没有内存保护有内存保护机制
没有特权级4个特权级(Ring 0-3)
程序可以随意覆盖任何内存错误的内存访问会触发异常

保护模式是所有现代操作系统的基础。

2. GDT(全局描述符表)

什么是GDT

GDT是保护模式下定义内存段的数据结构。每个表项(段描述符)8字节,描述一个内存段的属性。

为什么需要GDT

在保护模式下,段寄存器(CS、DS等)不再直接存放段基址,而是存放一个选择子(Selector),指向GDT中的某个表项。

实模式:  CS = 0x07C0
         物理地址 = 0x07C0 × 16 + 偏移

保护模式: CS = 0x08 (选择子,指向GDT第1项)
          物理地址 = GDT[1].base + 偏移

段描述符结构(8字节)

字节    位       内容
──────────────────────────────────
0-1    0-15     段界限(低16位)
2-3    16-31    段基址(低16位)
4      32-39    段基址(中8位)
5      40-47    访问字节
6      48-55    标志 + 段界限(高4位)
7      56-63    段基址(高8位)

访问字节(第5字节)详解

  7   6   5   4   3   2   1   0
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ P │ DPL   │ S │    Type       │
└───┴───┴───┴───┴───┴───┴───┴───┘

P   = Present(1=段有效)
DPL = Descriptor Privilege Level(0=内核, 3=用户)
S   = 描述符类型(1=代码/数据段, 0=系统段)
Type = 具体类型
  代码段: 1010 = Execute/Read
  数据段: 0010 = Read/Write

最小GDT配置

我们需要至少3个描述符:

  1. 空描述符(第0项,必须为空)
  2. 代码段描述符(覆盖全部4GB,可执行和读取)
  3. 数据段描述符(覆盖全部4GB,可读写)

这种配置叫做平坦内存模型(Flat Memory Model)——段基址=0,段界限=4GB,相当于没有分段。

3. 切换到保护模式的步骤

① 关闭中断 (CLI)
   - 保护模式的中断处理方式不同
   - 切换期间不能响应中断
       ↓
② 加载GDT (LGDT)
   - 告诉CPU GDT在哪里
       ↓
③ 设置CR0的PE位
   - CR0寄存器的第0位 = Protection Enable
   - 设为1进入保护模式
       ↓
④ 远跳转 (FAR JMP)
   - 刷新CPU流水线
   - 同时设置CS为代码段选择子
       ↓
⑤ 初始化段寄存器
   - DS, SS, ES, FS, GS 设为数据段选择子
       ↓
⑥ 设置栈指针
   - 32位模式下重新设置ESP
       ↓
⑦ 开始执行32位代码

4. 进入保护模式后的变化

不能再使用BIOS中断

BIOS中断是为实模式设计的。进入保护模式后:

  • ❌ int 0x10 打印字符
  • ❌ int 0x13 读取磁盘
  • ✅ 直接操作VGA显存(0xB8000)
  • ✅ 直接操作I/O端口

VGA文本模式显存

地址 0xB8000: 屏幕第(0,0)位置
  [字符] [属性] [字符] [属性] ...

属性字节:
  高4位: 背景颜色
  低4位: 前景颜色

  0x0F = 白色前景,黑色背景
  0x0A = 绿色前景,黑色背景

参考资料