Rus*_*lan 6 x86 assembly protected-mode interrupt-handling 80286
我正在尝试通过AMD 286系统上的异常处理来初始化保护模式。我已经在Bochs上调试了以下代码,并且在这里可以正常工作。在奔腾4机器上运行时也是如此。但是在286上,当到达int3指令时,它只是三重故障。可以观察到的行为是:如果我注释掉了int3,则会无限期地在屏幕上显示“ OK”,而按原样使用代码,则系统将重新启动。
该代码将由FASM编译,并将二进制文件放入HDD或FDD的引导扇区中。我实际上是从1.4M软盘运行它。
org 0x7c00
use16
CODE_SELECTOR = code_descr - gdt
DATA_SELECTOR = data_descr - gdt
; print "OK" on the screen to see that we've actually started
push 0xb800
pop es
xor di,di
mov ax, 0x0700+'O'
stosw
mov ax, 0x0700+'K'
stosw
; clear the rest of the screen
mov cx, 80*25*2-2
mov ax, 0x0720
rep stosw
lgdt [cs:gdtr]
cli
smsw ax
or al, 1
lmsw ax
jmp CODE_SELECTOR:enterPM
enterPM:
lidt [idtr]
mov cx, DATA_SELECTOR
mov es, cx
mov ss, cx
mov ds, cx
int3 ; cause an exception
jmp $
intHandler:
jmp $
gdt:
dq 0
data_descr:
dw 0xffff ; limit
dw 0x0000 ; base 15:0
db 0x00 ; base 23:16
db 10010011b ; present, ring0, non-system, data, extending upwards, writable, accessed
dw 0 ; reserved on 286
code_descr:
dw 0xffff ; limit
dw 0x0000 ; base 15:0
db 0x00 ; base 23:16
db 10011011b ; present, ring0, non-system, code, non-conforming, readable, accessed
dw 0 ; reserved on 286
gdtr:
dw gdtr-gdt-1
gdtBase:
dd gdt
idt:
rept 14
{
dw intHandler
dw CODE_SELECTOR
db 0
db 11100111b ; present, ring3, system, 16-bit trap gate
dw 0 ; reserved on 286
}
idtr:
dw idtr-idt-1
idtBase:
dd idt
finish:
db (0x7dfe-finish) dup(0)
dw 0xaa55
Run Code Online (Sandbox Code Playgroud)
我想我正在使用286不支持的某些CPU功能,但是到底在哪里?
在保护模式代码中,您具有:
lidt [idtr]
mov cx, DATA_SELECTOR
mov es, cx
mov ss, cx
mov ds, cx
Run Code Online (Sandbox Code Playgroud)
这取决于在执行保护之前将DS设置为0x0000(在进入保护模式之前)(并且DS描述符缓存中对应的基地址为0 )lidt [idtr]。该指令具有隐式DS段。将lidt指令放在使用16位选择器设置段寄存器之后,而不是之前。
尽管它并不是硬件上的错误,但在实模式下,您的代码还依赖于CS设置为0x0000作为指令lgdt [cs:gdtr]。不能保证CS为0x0000,因为某些BIOS非常有可能使用非零的CS到达引导加载程序。例如0x07c0:0x0000也将到达物理地址0x07c00(0x07c0 << 4 + 0x0000 = 0x07c00)。在实模式代码中,我建议将DS设置为零并使用lgdt [gdtr]。
进入保护模式后,在使用堆栈之前,应设置SP。中断将要求堆栈指针有效。将其初始化为0x0000将使堆栈从64KiB段的顶部向下扩展。您不应该依赖它碰巧指向一旦处于保护模式就不会干扰正在运行的系统的位置(即,位于引导加载程序代码/数据之上)。
在使用任何字符串指令(如STOS / SCAS / CMPS / LODS)之前,应确保已按照预期设置了方向标志。由于您依靠向前运动,因此应使用清除方向标志CLD。您不应假定在进入引导加载程序时便清除了方向标志。
其中的许多问题都在我的通用Bootloader提示中的另一个Stackoverflow答案中捕获。