Assembly 进入保护模式的简单引导加载程序

Assembly 进入保护模式的简单引导加载程序,assembly,x86,bootloader,protected-mode,memory-segmentation,Assembly,X86,Bootloader,Protected Mode,Memory Segmentation,我正在尝试为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 ;

我正在尝试为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字节和GDT地址的GDTR,等待1秒,禁用中断,加载GDT,启用保护模式,将带有远跳的代码段选择器设置为空闲,然后无限期地呆在那里

如果可以确定我的汇编代码中有什么不适合进入保护模式,请指出。我意识到初始引导加载程序通常不能完成这项任务,但我只是试图通过一个最小的工作程序来了解它是如何工作的

编辑: 更换后

mov ax,0x7c0
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而不是7c0h加载ds


在lgdt中,指令中的偏移量是基于0的。(这是唯一使用ds的指令。)

您需要用0而不是7c0h加载ds



在lgdt中,指令中的偏移量是基于0的。(这是唯一一条使用ds的指令。)

使用bochs及其内置调试器,或者研究qemu输出,以防它告诉您异常情况。我的最佳猜测是,进入保护模式后的远跳转不正确。你能拆开它或者得到一个汇编列表来看看实际生成的是什么吗?我想应该是像ea 48 7c 08 00那样的。(7c48是idle的地址,我猜到了。)此跳转的操作码似乎是
ea 5f 7c 08 00
jmp idle
指令具有操作码
eb-fe
,并且在文件中的位置0x5f,我认为这意味着它被加载到主内存中的位置0x7c5f(远跳转指向的位置)。我无法通过将0x7c0更改为0x0(加载DS时)并将
mov-ax,jmp空闲前08h
。但您应该做的是使用选择器010h加载所有段寄存器(ES、DS、SS)(您只将CS设置为08h)。如果您愿意,也可以将GS和FS设置为010h<转储文件中的code>EIP=0009fc6d表明您在内存中的某个地方迷失了方向。按照我的建议,将段设置为010h应该在
jmp 08h:idle
之后完成。设置SS后,您还应该使用内置调试器设置ESPUse bochs,或者研究qemu输出,以防它告诉您异常情况。我的最佳猜测是进入保护模式后的跳远不正确。你能拆开它或者得到一个汇编列表来看看实际生成的是什么吗?我想应该是像ea 48 7c 08 00那样的。(7c48是idle的地址,我猜到了。)此跳转的操作码似乎是
ea 5f 7c 08 00
jmp idle
指令具有操作码
eb-fe
,并且在文件中的位置0x5f,我认为这意味着它被加载到主内存中的位置0x7c5f(远跳转指向的位置)。我无法通过将0x7c0更改为0x0(加载DS时)并将
mov-ax,jmp空闲前08h
。但您应该做的是使用选择器010h加载所有段寄存器(ES、DS、SS)(您只将CS设置为08h)。如果您愿意,也可以将GS和FS设置为010h<转储中的code>EIP=0009fc6d表明您在内存中的某个地方走了出去。按照我的建议,将段设置为010h应该在
jmp 08h:idle
之后完成。设置SS后,您也应该设置ESPDT。或者,您可以编写lgdt[gdtr-0x7c00]这是否意味着指令
lgdt XXX
集合使用ds:XXX加载gdtr?是的,指令中的每个内存引用都使用一个段寄存器,并结合指令中给定的偏移量。但是,从gdtr加载的gdtstp的地址直接用作线性地址,没有段寄存器。进行此更改并在
空闲:
后放置
mov ax,08h
,qemu崩溃,我将添加一个错误。或者,您可以编写lgdt[gdtr-0x7c00]这是否意味着指令
lgdt XXX
集合使用ds:XXX加载gdtr?是的,指令中的每个内存引用都使用一个段寄存器,并结合指令中给定的偏移量。但是,从gdtr加载的gdtstp地址直接用作线性地址,没有段寄存器。进行此更改并在
空闲:
后放置
mov ax,08h
,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