设置全局描述符表和保护模式后不断重新启动



我一定是GDT setup和切换到protected mode做了什么问题,因为它不断重新启动。

这是我应该设置GDT并切换到protected modekernel.asm

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

我的错在哪里?

由于我只能假设您已在 0x1000:0x0000 正确将扇区读入内存,因此我只能指出kernel.asmgdt.inc中的潜在问题。


代码问题

如果您使用jmp 0x1000:0x0000到达内核阶段(我怀疑是这种情况),那么kernel.asm您错误地设置了 DS并且 ES段寄存器为错误的值。在这种情况下,您需要将这两个寄存器设置为 0x1000,而不是0x0000。此代码:

xor ax,ax
mov ds,ax
mov es,ax

需要更改为:

mov ax,0x1000
mov ds,ax
mov es,ax

您遇到的下一个主要问题是GDT记录(toc内部)采用线性地址。实模式下的线性地址与物理地址相同。从指令集手册中它说:

源操作数指定一个 6 字节内存位置,其中包含全局描述符表 (GDT) 的基址(线性地址)和限制(表的大小(以字节为单位)

您已将ORG0x0000(因为您未指定)用于kernel.asm,因此NASM假定生成的所有偏移量都来自包括标签gdt_data在内的0x0000基数。因此,当您执行此操作时:

toc:
dw end_of_gdt - gdt_data -1
dd gdt_data

gdt_data将是略高于0x0000的一些小偏移。在物理内存中,GDT记录实际上位于 0x1000:0x0000+(小偏移量)。物理(线性)内存中的0x1000:0x0000是(0x1000<<4)+0x0000 = 0x10000因此您需要将其添加到gdt_data中。您的toc应如下所示以补偿:

toc:
dw end_of_gdt - gdt_data -1
dd gdt_data+0x10000

遇到的下一个问题是您实际上没有打开保护模式标志。你有这个:

mov eax,cr0
or eax,1

它应该是:

mov eax,cr0
or eax,1
mov cr0, eax

将保护模式位设置为 1 后,需要更新CR0寄存器中的保护模式位。


GDT问题相关,您已经从包含整个 4GB 地址空间的偏移量 0x00000000 为代码段创建了GDT条目。这是正确的。同样,由于NASM创建了与0x0000的偏移量,并且您的代码实际上是在0x1000:0x0000(物理地址0x10000)加载的,因此您需要将0x10000添加到最终设置保护模式的JMPstage3标签的值中。同样,由于我们正在编码一个高于0xFFFF的值,因此我们需要强制NASM使用 32 位操作数,因此我们在JMP上使用dword限定符。你有这个:

jmp 08h:Stage3

应该是这样的:

jmp dword 08h:Stage3+0x10000

相关内容

  • 没有找到相关文章

最新更新