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,然后移动到其他寄存器
答案 0 :(得分:16)
x86支持两种虚拟内存方案(read about it here):
大多数操作系统都希望使用分页而不想进行分段,但必须禁用分段。
所以诀窍是禁用它的效果,因为它不存在。这通常可以通过创建4个大的重叠段描述符(在空段旁边)来完成:
所有这些段从0x00000000
开始到0xffffffff
,因此您最终会得到重叠的大段,即特权代码和数据,以及同时非特权代码和数据。这应该打开虚拟内存并禁用分段效果。
处理器使用细分选择器(细分寄存器cs
,ds
,ss
...)找出正确的细分(再一次,细分是必须的)。< / p>
每个段选择器都是16位大小,并具有以下布局(source):
前两位表示权限级别,x86支持4个级别,但实际只使用了其中两个级别(00
最高,11
最低级别。
第三位表示应该使用该表,主要是0
,GDT。
如果您解释0x08
中加载的cs
,它将是二进制的:
0000000000001 0 00
index 1 (code) GDT privileged
以及0x10
,ds
,...中加载的ss
:
0000000000010 0 00
index 2 (data) GDT privileged
如果您阅读了任何用户模式计划的细分选择器,您会看到cs
值为27
(0x1b
),这意味着:
0000000000011 0 11
index 3 (code) GDT non-privileged
数据选择器ds
,ss
,...应存储35(0x23
):
0000000000100 0 11
index 4 (data) GDT non-privileged
数据段选择器(寄存器)可以使用简单的mov
指令轻松修改,但cs
不能与mov
一起使用,因此您使用{{1}将段配置加载到代码段选择器中。