2

我是根据 Nick Blundell 的一本书来做的。我写了一个MBR程序,它首先在实模式下运行,程序中的一些指令会将cpu切换到保护模式。首先,我这样设置 GDT:

gdt_start:

gdt_null:
    dd 0x0
    dd 0x0

gdt_code:
    dw 0xffff
    dw 0x0
    db 10011010b
    db 11001111b
    db 0x0

gdt_data:
    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 gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

然后cpu运行以下指令:

   cli

    lgdt [gdt_descriptor]
    mov eax,cr0
    or eax,0x1
    mov cr0,eax ;this will set the cpu to protected-mode        

;jmp $  ;I use this instrction to find where is wrong
    jmp CODE_SEG:init_pm

jmp $
[bits 32]
init_pm:
jmp $
    mov ax,10
jmp $
    mov ds,eax
    mov ss,eax
jmp $
    mov es,ax
    mov fs,ax
    mov gs,ax
    mov ebp,0x90000
    mov esp,ebp
    call BEGIN_PM

该指令jmp CODE_SEG:init_pm将导致cpu崩溃并重新启动。如果我将其更改为jmp init_pm,则以下指令mov ax,10将导致 cpu 崩溃并重新启动。而且书上说切换操作需要跳远。

你能帮我做切换操作吗?

4

2 回答 2

0

在你的gdt_descriptor,你有限制和地址。与大多数其他地址不同,这不是段:偏移地址。它必须是线性地址。作为 MBR,您可能已将其从最初加载的位置 0x7C00 移出。您gdt_descriptor(通常称为gdtr)中的地址需要是您现在所在位置的线性地址。您没有显示足够的代码来确定,但我怀疑您的问题就在那里。

于 2013-09-02T11:50:09.370 回答
0

您的代码中有几个问题:

  1. 您的gdt_code描述符中缺少基数高字的低字节。只需db 0x0dw 0x0.
  2. 弗兰克科特勒写道,gdt_descriptor必须包含线性地址。是的,确实如此,但它并不是唯一需要线性地址的地方。您可以ORG在任何代码之前使用指令,或手动将来源添加到此字段。
  3. 指令lgdt仍然使用ds寄存器进行seg:off地址计算。在org.
  4. 远跳转到保护模式也需要线性地址作为偏移量。请记住,此跳转是在兼容模式下执行的(因为它是在保护模式切换后执行的第一条指令)。它使用两个字节作为段选择器(在冒号之前),只使用两个字节作为偏移量(在冒号之后)。这意味着您不应该尝试跳转到高于0xFFFF. 再次检查代码的来源。
于 2013-09-03T16:14:00.157 回答