我正在尝试为x86体系结构编写一个简单的引导程序,该引导程序应仅输出字符“ A”,进入保护模式,然后停止。我的代码(带注释)如下:
BITS 16
ORG 0x7c00
jmp 0:start ;set cs to 0
start:
mov ax,0x7c0
add ax,288
mov ss,ax
mov sp,4096
mov ax,0x7c0
mov ds,ax ;Sets segment descriptors for now
mov ah,0eh
mov al,65
int 10h ;Print A for test
jmp pretect ;Jump to a ~1 second delay before entering protected mode so we can see the 'A' if anything goes wrong
nod:
jmp nod ;Not used for now
gdtstp: ;global descriptor table
dq 0 ;Null
dw 0xffff ;Entry 08h, full 4gb
dw 0
db 0
db 0x9a
db 11001111b
db 0
dw 0xffff ;Entry 16h, full 4gb
dw 0
db 0
db 0x92
db 11001111b
db 0
gdtr: ;descriptor for gdt
dw 24
dd gdtstp
pretect: ;Wait for about 1 second before jumping to protect
mov esi,0x20000000
.loop:
dec esi
test esi, esi
jz protect
jmp .loop
protect: ;attempt to enter protected mode
cli
lgdt [gdtr] ;set gdt register
mov eax,cr0
or al,1
mov cr0,eax ;set bit 1 of cr0
jmp 08h:idle ;sets cs to 08h and jumps to idle
idle:
jmp idle ;Should stop here
times 510-($-$$) db 0
dw 0xaa55 ;magic number
这是在NASM中并在qemu上运行。我有一种轻松的方法,可以在输出“ A”和尝试进入保护模式之间增加大约1秒的延迟。目前,当我尝试运行此代码时,它会显示“ A”,并停留约一秒钟,然后重新启动。我不知道为什么,但是我认为这很可能是因为全局描述符表无效或加载不正确,或者是因为设置代码段选择器的跳转不正确。
我的代码应该做的是:打印'A',具有3个条目的GDT:空描述符,所有4GB的代码段和所有4GB的数据段,具有指定24的GDTR。字节和GDT的地址,等待1秒钟,禁用中断,加载GDT,启用保护模式,将代码段选择器远跳设置为空闲,然后无限期停留在该位置。
如果可以确定我的汇编代码中哪些内容不适合进入保护模式,请指出。我意识到最初的引导加载程序通常无法完成此任务,但是我只是想通过一个最小的工作程序来了解它的工作原理。
编辑: 更改后
mov ax,0x7c0
mov ds,ax
到
mov ax,0
mov ds,ax
并将mov ax,08h
放在idle:
和jmp idle
之间,qemu崩溃并给出以下内容:
qemu: fatal: Trying to execute code outside RAM or ROM at 0x000a0000
EAX=feeb0010 EBX=00000000 ECX=00000000 EDX=ffffffff
ESI=00000000 EDI=8000007c EBP=00000000 ESP=00000ffc
EIP=0009fc6d EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =08e0 00008e00 0000ffff 00009300 DPL=0 DS16 [-WA]
DS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
FS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
GS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00007c1f 00000018
IDT= 00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=feeb0010 CCD=feeb0010 CCO=ADDB
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
答案 0 :(得分:2)
您需要为ds加载0,而不是7c0h。
在lgdt中,指令中的偏移量从0开始。 (这是唯一使用ds的指令。)