我最近对内核开发着迷,并开始使用OSDev Wiki上的裸骨教程。实现Hello World示例后,我继续尝试创建全局描述符表。从各种来源网上我拼凑了GDT的一些代码,最终失败了。我的实现是否有问题,如果不能立即明确,是否有任何来源可以提供更多信息?
简而言之,使用GRUB无法加载以下带有GDT的内核实现。我正在使用gcc
和as
进行编译,可以提供所需的任何其他信息。
boot.s
.section .text
.global _start
.type _start, @function
_start:
movl $stack_top, %esp
call kernel_main
cli
hlt
.Lhang:
jmp .Lhang
.size _start, . - _start
.global gdt_flush
gdt_flush:
cli
movl -4(%esp), %eax
lgdt (%eax)
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss //the inclusion of this line or the following
jmp $0x08, $.flush //prevents the kernel from loading
.flush:
ret
.section .bootstrap_stack
stack_bottom:
.skip 16384
stack_top:
kernel.c
void kernel_main() {
gdt_install();
...
}
gdt.c
struct gdt_entry {
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
}__attribute__((packed));
struct gdt_ptr {
uint16_t limit;
uint32_t base;
}__attribute__((packed));
struct gdt_entry gdt[3];
struct gdt_ptr gp;
extern void gdt_flush(struct gdt_ptr *);
void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
gdt[num].base_low = (base & 0xFFFF);
gdt[num].base_middle = (base >> 16) & 0xFF;
gdt[num].base_high = (base >> 24) & 0xFF;
gdt[num].limit_low = (limit & 0xFFFF);
gdt[num].granularity = (limit >> 16) & 0x0F;
gdt[num].granularity |= (gran & 0x0F);
gdt[num].access = access;
}
void gdt_install() {
gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
gp.base = (uint32_t) &gdt;
gdt_set_gate(0, 0, 0, 0, 0);
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
gdt_flush(&gp);
}
答案 0 :(得分:2)
似乎有几个问题。我没有检查你的GDT条目的具体位(这是他自己必须手工制作英特尔手册的工作)。
首先(现在不会引起问题,但将来可能会出现问题)是您指定并使用4字节宽限制,尽管GDT仅适用于20位。您应该更改gdt_install
函数以仅传递20位限制并将其记录在注释中以备将来使用。另一个解决方案当然是将参数转换为十二位,但这样做的意义不大,下次回到GDT管理时可能会有不同的解释。
第二件似乎不正确的是获取gdt_flush
参数的方式。堆栈向下增长,因此最后推送的项目位于(%esp)
(由call
指令推送的返回地址),您想要的参数位于4(%esp)
。
我假设你已经处于保护模式并且已经通过引导加载程序设置了实际GDT,所以我看不出任何明显的原因导致另一个远程跳转(至少消耗三个时钟),尽管它并不总是是的,代码段直接放在空段之后。 我不喜欢跳转的是用作跳转目的地的标签。我建议检查它,因为它是一个需要绝对值的远程跳跃。