问题描述
我已经成功地为实模式编写了代码。但麻烦始于 32 位保护模式。在跳转到保护模式之前,我使用 cli 禁用了中断, 使用lgdt 加载GDT 并在cr0 中设置32 位模式位。但是 QEMU 正在无限重启。以下是代码
boot.asm:
[BITS 16]
BOOTSEG equ 0x7c00
DATASEG equ 0x07c0
STACKSEG equ 0x17c0
EXTRASEG equ 0x37c0
STACKPOINT equ 0x0000
BLACKONWHITE equ 0x0F
YELLOWONBLUE equ 0x1E
VIDEO_MEMORY equ 0xb8000
global _start
_start:
xor ax,ax
mov ax,STACKSEG
mov ss,ax ;initializing stack segment
mov sp,STACKPOINT
mov ax,DATASEG
mov ds,ax ;initializing data segment
mov ax,EXTRASEG
mov es,ax ;initializing extra segment
call Switch_To_Pm
%include "./screen.asm"
%include "./lib.asm"
%include "./gdt.asm"
%include "./protected_mode/switch_to.asm"
[bits 32]
Begin_Pm:
jmp $
times 510 - ($ - $$) db 0
dw 0xAA55
gdt.asm:
gdt_start:
null_descriptor:
dd 0x0
dd 0x0
code_descriptor:
dw 0xffff
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
data_descriptor:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ code_descriptor - gdt_start
DATA_SEG equ data_descriptor - gdt_start
protected_mode/switch_to.asm:
[BITS 16]
Switch_To_Pm:
cli
lgdt [gdt_descriptor]
mov eax,cr0
or eax,0x1
mov cr0,eax
jmp CODE_SEG:Init_Pm
[BITS 32]
Init_Pm:
mov ax,DATA_SEG
mov ds,ax
mov ss,ax
mov es,ax
mov fs,ax
mov gs,ax
call Begin_Pm
lib.asm 包含使用 int 0x15 的延迟例程,screen.asm 包含以实模式打印文本的 BIOS 例程。
以下是我用来构建的命令
nasm -fbin -o boot.bin boot.asm
qemu boot.bin
不知道为什么,QEMU 无限重启。代码直到实模式运行良好。可能是切换到保护模式有问题。
在此之前感谢任何帮助
解决方法
我想我已经确定了问题所在。问题出在线路上
jmp CODE_SEG:Init_Pm
中的 protected_mode/switch_to.asm
。我应该向远跳添加一个 0x7c00 的偏移量。
相反,我使用了 [org 0x7c00]
并重写了实模式和保护模式代码,它奏效了。