我必须做错 GDT setup
并切换到 protected mode
因为它不断重启 .
这是我的 kernel.asm
应该设置 GDT
并切换到 protected mode
:
bits 16
jmp main
%include "gdt.inc"
main:
cli
xor ax,ax
mov ds,ax
mov es,ax
mov ax,0x9000
mov ss,ax
mov sp,0xffff
sti
call InstallGDT
cli
mov eax,cr0
or eax,1
jmp 08h:Stage3
bits 32
Stage3:
mov ax,0x10
mov ds,ax
mov ss,ax
mov es,ax
mov esp,90000h
Stop:
mov byte [0xb8000],'A'
cli
hlt
并且有 gdt.inc
:
bits 16
InstallGDT:
cli
pusha
lgdt [toc]
sti
popa
ret
gdt_data:
dd 0
dd 0
dw 0ffffh
dw 0
db 0
db 10011010b
db 11001111b
db 0
dw 0ffffh
dw 0
db 0
db 10010010b
db 11001111b
db 0
end_of_gdt:
toc:
dw end_of_gdt - gdt_data -1
dd gdt_data
我的 bootloader.asm
将10个扇区加载到 0x1000:0x000
然后跳到那里 .
我用命令测试代码:
nasm -f bin -o bootloader.bin bootloader.asm
nasm -f bin -o kernel.bin kernel.asm
cat bootloader.bin kernel.bin>OS.bin
qemu-system-i386 OS.bin
我的错在哪里?
1 回答
因为我只能假设你已经正确地将扇区读入存储器0x1000:0x0000,所以我只能指出
kernel.asm
和gdt.inc
中的潜在问题 .代码问题
If 你用
jmp 0x1000:0x0000
到达内核阶段(我怀疑是这种情况)然后在kernel.asm
中你错误地设置了DS,并且ES段注册到了错误的值 . 在这种情况下,您需要将这两个寄存器设置为0x1000,而不是0x0000 . 这段代码:需要改为:
您遇到的下一个主要问题是GDT记录(在
toc
内)采用线性地址 . 实模式中的线性地址与物理地址相同 . 从说明书手册中可以看出:您已经为
kernel.asm
使用了OR0000 0x0000(因为您没有指定一个),因此NASM假定生成的所有偏移都来自0x0000的基数,包括标签gdt_data
. 所以当你这样做时:gdt_data
将是一个小于0x0000的小偏移量 . 在物理内存中,GDT记录实际上是0x1000:0x0000(小偏移) . 物理(线性)内存中的0x1000:0x0000是(0x1000<<4)+0x0000 = 0x10000,因此您需要将其添加到gdt_data
. 你的toc
应该像这样补偿:您遇到的下一个问题是您实际上没有打开保护模式标志 . 你有这个:
它应该是:
将该位设置为1后,需要更新CR0寄存器中的保护模式位 .
与GDT问题相关,您已从0x00000000的偏移量创建了代码段的GDT条目,其中包含整个4gb地址空间 . 这是对的 . 但是,由于NASM创建的偏移量为0x0000,而您的代码实际上是在0x1000:0x0000(物理地址0x10000)处加载的,因此需要在最终设置保护模式的JMP中为
stage3
label的值添加0x10000 . 同样,因为我们正在编码一个高于0xFFFF的值,我们需要强制NASM使用32位操作数,所以我们在JMP
上使用dword
限定符 . 你有这个:它应该是这样的: