在bootloader中远程跳转gdt

时间:2014-06-01 09:35:13

标签: assembly x86 bootloader gdt

flush_gdt:
    lgdt [gdtr]
    jmp 0x08:complete_flush

complete_flush:
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    ret

我无法理解这段代码的作用。 flush_gdt是一个标签,然后lgdt [gdtr]48-bit指针加载到gdtr注册表中,之后加载jmp 0x08:complet_flush

jmp指令有什么作用?然后我们为什么要将0x10移动到ax,然后移动到其他寄存器

1 个答案:

答案 0 :(得分:16)

x86支持两种虚拟内存方案(read about it here):

  • 细分,必须使用细分表GDT进行管理。
  • 分页,可选,使用页面表管理,PDT。

大多数操作系统都希望使用分页而不想进行分段,但必须禁用分段。

所以诀窍是禁用它的效果,因为它不存在。这通常可以通过创建4个大的重叠段描述符(在空段旁边)来完成:

  • 段索引0:空段描述符
  • 段索引1:特权(内核)模式的代码段描述符
  • 段索引2:特权(内核)模式的数据段描述符
  • 段索引3:非特权(用户)模式的代码段描述符
  • 段索引4:非特权(用户)模式的数据段描述符

所有这些段从0x00000000开始到0xffffffff,因此您最终会得到重叠的大段,即特权代码和数据,以及同时非特权代码和数据。这应该打开虚拟内存并禁用分段效果。

处理器使用细分选择器(细分寄存器csdsss ...)找出正确的细分(再一次,细分是必须的)。< / p>

每个段选择器都是16位大小,并具有以下布局(source):

enter image description here

  • 前两位表示权限级别,x86支持4个级别,但实际只使用了其中两个级别(00最高,11最低级别。

  • 第三位表示应该使用该表,主要是0,GDT。

  • 其余13位表示段索引。

如果您解释0x08中加载的cs,它将是二进制的:

0000000000001     0         00
index 1 (code)   GDT    privileged

以及0x10ds,...中加载的ss

0000000000010     0         00
index 2 (data)   GDT    privileged

如果您阅读了任何用户模式计划的细分选择器,您会看到cs值为270x1b),这意味着:

0000000000011     0         11
index 3 (code)   GDT   non-privileged

数据选择器dsss,...应存储35(0x23):

0000000000100     0         11
index 4 (data)   GDT   non-privileged

数据段选择器(寄存器)可以使用简单的mov指令轻松修改,但cs不能与mov一起使用,因此您使用{{1}将段配置加载到代码段选择器中。