1
# Load the GDT.
mov $gdt_descriptor, %ecx
lgdt (%ecx)
mov $0x10, %cx
mov %cx, %ds
mov %cx, %es
mov %cx, %fs
mov %cx, %gs
mov %cx, %ss
ljmp $0x8, $1f
1:  mov $kernel_stack, %esp

我无法理解这段代码的作用。为什么在加载 GDT 后将 mov $0x10 移动到 cx 然后再移动到其他寄存器?ljmp 指令有什么作用?

4

1 回答 1

3

lgdt它从告诉 CPU的新 GDT 加载段描述符缓存(在 CPU 内部) 。

当您更改表条目或更改表指向的位置时,CPU 内的段描述不会自动更新。

您甚至可以使用 DS base=0 limit=4GiB 切换回实模式(ES 和 SS 相同),并在实模式下使用 32 位地址,直到下一条mov ds, r16pop ds指令覆盖缓存的段描述。(这被称为big / huge unreal mode,如果你也为 CS 这样做,那么它是巨大的,但这不太方便,因为实模式下的中断只保存 IP,而不是 EIP。)

ljmp是 a far jmp,它设置 CS(在这种情况下使用与数据描述符不同的描述符)。x86 不允许movpop设置 CS,只能跳远。推测 CPU 不会通过此跳转更改模式,否则 asm 源将需要使用.code32or.code16指令。

目标是1:标签,在f正向。因此,movto%esp使用 GDT 索引 1 中的任何代码段设置进行解码/运行。(段选择器的低 3 位是权限位,$8GDT 索引 1 和$0x10GDT 索引 2 也是如此。)

mov将to%ss与设置的指令分开%esp有点奇怪,因为 x86 会自动将中断推迟到to之后的指令。这使您可以在不使用/的情况下自动设置 SS:SP ,但可能此代码在已禁用中断的情况下运行。这段代码可能只在启动期间运行一次,因此只要设置新的 GDT 和 IDT 就需要禁用中断是有意义的。movSSclisti

于 2018-01-13T08:22:50.480 回答