5)模式转换

模式转换

接下来需要从现在的 16 位的实模式转变为之后 32 位的保护模式

保护模式的地址计算

1
2
3
4
5
6
lidt  idt_48      ; load idt with 0,0
lgdt gdt_48 ; load gdt with whatever appropriate

idt_48:
.word 0 ; idt limit=0
.word 0,0 ; idt base=0L

16位实模式下地址的计算方式是段基址左移四位,再加上偏移地址
当 CPU 切换到保护模式后,同样的代码,内存地址的计算方式就不一样了
ds 寄存器里存储的值,在实模式下叫做段基址,在保护模式下叫段选择子。段选择子里存储着段描述符的索引

通过段描述符索引,可以从全局描述符表 gdt 中找到一个段描述符,段描述符里存储着段基址。

段基址取出来,再和偏移地址相加,就得到了物理地址(准确说是线性地址,再经过分页转换后才是物理地址),整个过程如下:

总结一下就是,段寄存器(比如 ds、ss、cs)里存储的是段选择子,段选择子去全局描述符表中寻找段描述符,从中取出段基址。然后再加上偏移地址,就得到了最终的物理地址。

全局描述符表 gdt

操作系统把全局描述符表 gdt的位置信息存储在一个叫 gdtr 的寄存器中。

指令就是lgdt gdt_48, lgdt 就表示把后面的值(gdt_48)放在 gdtr 寄存器中,gdt_48 标签如下:

1
2
3
gdt_48:
.word 0x800 ; gdt limit=2048, 256 GDT entries
.word 512+gdt,0x9 ; gdt base = 0X9xxxx
  • **0x800**:GDT的界限是2048字节,表示最多可以有256个GDT条目。
  • **512+gdt0x9**:GDT的基地址是 0x9xxxx,具体地址通过将 512 加上某个基地址 gdt 来计算,即0x9020 + gdt
    setup.s 编译后是放在 0x90200 这个内存地址的,而 gdt 表示 setup.s 内的偏移量,所以要加上 0x90200 这个值,才能表示 gdt 这个标签在整个内存中的准确地址。

gdt 这个标签处,就是全局描述符表在内存中的真正数据了。

1
2
3
4
5
6
7
8
9
10
11
12
gdt:
.word 0,0,0,0 ; dummy

.word 0x07FF ; 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ; base address=0
.word 0x9A00 ; code read/exec
.word 0x00C0 ; granularity=4096, 386

.word 0x07FF ; 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ; base address=0
.word 0x9200 ; data read/write
.word 0x00C0 ; granularity=4096, 386

将这些数值按描述符结构映射:

  1. Limit 15:0: 0x07FF
  2. Base 15:0: 0x0000
  3. Base 23:16: 0x00
  4. Type: 0x9A
    • 二进制: 10011010
    • P: 1 (段存在)
    • DPL: 00 (特权级别 0)
    • S: 1 (代码段或数据段)
    • Type: 1010 (代码段,可读、可执行)
  5. Limit 19:16: 0x0
  6. AVL: 0
  7. D/B: 1 (32 位操作数)
  8. G: 1 (4KB 粒度)
  9. Base 31:24: 0x00

将这些部分组合起来,我们得到了一个描述 8MB(2048 个 4KB 页)的代码段描述符,基地址为 0。

所以这个 GDT 定义了两个段,一个是代码段,一个是数据段。每个段的大小都是 8MB,基地址都是 0,粒度为 4KB,运行在 32 位保护模式下。代码段是只读可执行的,而数据段是可读可写的。

第二个和第三个段描述符的段基址都是 0,也就是之后在逻辑地址转换物理地址的时候,通过段选择子查找到无论是代码段还是数据段,取出的段基址都是 0,那么物理地址将直接等于程序员给出的逻辑地址(准确说是逻辑地址中的偏移地址)

idtr 寄存器是中断描述符表,其原理和全局描述符表一样。发生中断时,CPU 会拿着中断号从中断描述符表里寻找中断处理程序的地址,找到以后,就会跳转到相应的中断程序去执行。


5)模式转换
https://carl-5535.github.io/2024/07/24/Linux0.11/5)模式转换/
作者
Carl Chen
发布于
2024年7月24日
许可协议