我正在研究一个遵循多重引导规范的简单内核。这是针对一个类项目,所以我无法直接发布我的代码,但对于我的问题,只需说我们正在使用multiboot sample code的修改版本即可。
我正在尝试将全局描述符表寄存器(GDTR)设置为指向适当的地址。为了做到这一点,我一直在关注OSDev wiki中的GDT Tutorial。在本教程中,他们的平面保护模式示例代码只是从堆栈中加载两个值并将它们放入GDTR。这让我感到困惑,因为我认为GDTR应该在初始化堆栈之前设置。如果内核尚未初始化,我不知道ESP指向何处。我想在跳转到boot.S中的任何代码之前,GRUB可能会将其设置为某些内容,但我无法找到任何建议的文档。
tl; dr - 为什么OSDev GDT Tutorial在加载全局描述符表的地址和大小时从相对于ESP的地址检索数据?
答案 0 :(得分:1)
如果没有正确设置GDT,你无法在保护模式下做很多事情,GRUB显然必须不仅为你而且为自己做。单词
'CS'必须是32位读/执行代码段,偏移量为'0',限制为'0xFFFFFFFF'。
意味着GDT具有正确设置的代码段描述符,并且CS寄存器加载了选择此描述符的选择器。
setGdt子例程接受堆栈上的参数。这使得从C代码调用它很方便(32位x86 C / C ++编译器,如gcc和Microsoft Visual C ++,其他几个支持这种调用约定;请参阅cdecl)。
但是,在调用setGdt之前,甚至在将参数推送到堆栈之前,您需要设置堆栈,因为这种语言:
'ESP'操作系统映像必须在需要时立即创建自己的堆栈。
请注意,该页面的boot.S文件中的示例代码执行此操作:
/* The size of our stack (16KB). */
#define STACK_SIZE 0x4000
...
multiboot_entry:
/* Initialize the stack pointer. */
movl $(stack + STACK_SIZE), %esp
...
/* Our stack area. */
.comm stack, STACK_SIZE
应该是不言自明的。
现在,当您将选择器加载到段寄存器中时,段基址和段限制(以及段访问权限)将缓存在CPU中。因此,在下一次加载到段寄存器之前,更改运行代码下的GDT或GDTR 将无效。