保护模式初始化时的栈结构

Stack structure during protected mode initialization

我正在开发一个遵循多重引导规范的简单内核。这是一个 class 项目,所以我不能直接 post 我的代码,但对于我的问题,我们使用 multiboot sample code 的修改版本就足够了。

我正在尝试将全局描述符 table 寄存器 (GDTR) 设置为指向适当的地址。为此,我一直关注 OSDev wiki 中的 GDT Tutorial。在本教程中,他们的平面保护模式示例代码只是从堆栈中加载两个值并将它们放入 GDTR。这让我感到困惑,因为我认为 GDTR 应该设置为 before 堆栈被初始化。如果内核尚未初始化,我不知道 ESP 会指向哪里。我想 GRUB 可能会在跳转到 boot.S 中的任何代码之前将其设置为某些内容,但我无法找到任何文档来表明这一点。

tl;dr - 为什么 OSDev GDT Tutorial 在加载全局描述符 table 的地址和大小时从相对于 ESP 的地址检索数据?

无论如何,如果没有正确设置 GDT,您将无法在保护模式下做很多事情,而 GRUB 显然必须不仅为您而且为它自己做这件事。单词

‘CS’ Must be a 32-bit read/execute code segment with an offset of ‘0’ and a limit of ‘0xFFFFFFFF’.

暗示 GDT 具有正确设置的代码段描述符,CS 寄存器加载了选择该描述符的选择器。

setGdt 子例程在堆栈上接受其参数。这使得从 C 代码调用很方便(32 位 x86 C/C++ 编译器,例如 gcc 和 Microsoft Visual C++ 以及其他几个支持此调用约定;请参阅 cdecl)。

但是,在调用 setGdt 之前,甚至在将参数压入堆栈之前,由于这种语言,您需要设置堆栈:

‘ESP’ The OS image must create its own stack as soon as it needs one.

请注意,该页面的 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 运行 代码将不会生效,直到下一次加载到段寄存器中。