0

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

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

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

4

1 回答 1

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将无效,直到下一次加载到段寄存器中。

于 2016-10-15T09:37:45.523 回答