问题描述
最近,我决定尝试为我的基本操作系统内核使用 32 位代码而不是 16 位代码。我试图进入 32 位保护模式,但它似乎无法正常工作。我使用 NASM 进行构建,使用 qemu 进行调试,但是当我调试它时,qemu 窗口开始出现很多故障。
而且它似乎每半秒都会出现一致的突发故障。
这是我的内核代码:
bits 32
org 0x7E00
; attempting to enter 32 bit protected mode
cli
lgdt [gdtr]
mov eax,cr0
or al,1
mov cr0,eax
jmp 08h:kernel_main
gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdtr:
dw gdt_end - gdt_start
dd gdt_start
; main kernel code
kernel_main:
; display hi in grey at top of screen
mov dword [0xb8000],0x07690748
hlt
ret
times 1024-($-$$) db 0
它应该在屏幕顶部以灰色显示“Hi”,但这似乎不起作用。
我做了一些测试,发现这可能与我尝试进入 32 位保护模式的方式有关。我在网上到处搜索,但找不到任何有用的东西。
解决方法
仅将您的 bits 32
指令放在保护模式代码实际开始的位置。一旦发生这种情况,从 gdt_data 选择器加载段寄存器。您可能还想将 ESP
寄存器的高 16 位清零。
为了节省一些空间,您可以将 GDT 指针放在 NULL 描述符上。
请注意正确的 GDT 限制是 gdt_end - gdt_start - 1
bits 16
org 0x7E00
; attempting to enter 32 bit protected mode
cli
lgdt [gdtr]
mov eax,cr0
or al,1
mov cr0,eax
jmp 08h:kernel_main
gdt_start:
gdtr:
dw gdt_end - gdt_start - 1
dd gdt_start
dw 0
gdt_code:
dw 0xFFFF
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_data:
dw 0xFFFF
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end:
bits 32
kernel_main:
; main kernel code
mov eax,0x10
mov ds,eax
mov es,eax
mov fs,eax
mov gs,eax
mov ss,ax
movzx esp,sp
; Display hi in grey at top of screen
mov dword [0xB8000],0x07690748
jmp $
times 1024-($-$$) db 0
,
在远跳转到保护模式后,您必须初始化段寄存器。 把你的 kernel_main 改成这样
kernel_main:
mov eax,0x10
mov ds,eax
mov es,eax
mov fs,eax
mov gs,eax
mov ss,eax
; Display hi in grey at top of screen
mov dword [0xb8000],0x07690748
hlt
ret