经过与我自己的争论,我终于决定将我的操作系统转移到保护模式 . 但是,我在执行保护模式代码时遇到了一些问题 . OSDev wiki的第一步是启用A20系列,因为快速门,我没有遇到什么麻烦 . 第二部分是加载全局描述符表 . 我按照BrokenThorn娱乐教程使用它作为我的GDT的粗略基础,并将一些长二进制值转换为漂亮和短的十六进制值 . 最后,我将cr0寄存器的最低位设置为1进入保护模式 . 然后我跳远到 0x08:start32
. 但是,在执行我的代码并使用qemu的 monitor -stdio
标志监视寄存器时,我看到意外的结果 . 我的主要保护模式例程 start32
很简单 . 它将值 0xDEADBABA
移动到 eax
寄存器中 . 然而,这似乎没有生效,因为在QEMU上,该值显示为 00000100
. cr0寄存器是 00000010
,这似乎是正确的,但再一次让我持怀疑态度,因为它不是最低位 . 到目前为止最糟糕的是GDT寄存器,它恰好等于 00000000 00000000
. 这里有什么问题?我已经为我的bootsector和我的部分内核提供了代码,下面切换到保护模式 .
P.S:bootsector清除屏幕并加载内核 . 这是它的唯一目的 .
start.asm(bootsector):
bits 16
start:
mov ax, 0x07C0
add ax, 288
mov ss, ax
mov sp, 4096
mov ax, 0x07C0
mov ds, ax
mov ah, 0x00
mov al, 0x03
int 0x10
call load_kernel
load_kernel:
mov ah, 0x02 ; call function 0x02 of int 13h (read sectors)
mov al, 0x01 ; read one sector (512 bytes)
mov ch, 0x00 ; track 0
mov cl, 0x02 ; sector 2
mov dh, 0x00 ; head 0
mov dl, 0x00 ; drive 0, floppy 1
mov bx, 0x2000 ; segment 0x2000
mov es, bx ; segments must be loaded from non immediate data
mov bx, 0x0000 ; start of segment -offset value
.readsector:
int 13h ; call int 13h
jc .readsector ; error? try again
mov ax, 0x2000 ; set the data segment register
mov ds, ax ; as a pointer to the kernel's memory location
jmp 0x2000:0x0000 ; jump to the kernel
times 510-($-$$) db 0
dw 0xAA55
kernel.asm(有问题的文件):
bits 16
section .text
start:
mov ax, 0x2000
add ax, 288
mov ss, ax
mov sp, 4096
mov ax, 0x2000
mov ds, ax
cli
in al, 0x92
or al, 2
out 0x92, al
lgdt[toc]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:start32
section .rodata
gdt32:
dd 0
dd 0
dw 0x0FFFF
dw 0
db 0
db 0x9A
db 0xCF
db 0
dw 0x0FFFF
dw 0
db 0
db 0x92
db 0xCF
db 0
gdt_end:
toc:
dw gdt_end - gdt32 - 1
dd gdt32
bits 32
section .text
start32:
mov eax, 0xDEADBABA