首页 文章

我无法将cpu从实模式切换到保护模式

提问于
浏览
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崩溃并重新启动 . 书中说切换操作需要长时间跳转 .

你能帮我做一下切换操作吗?

2 回答

  • 0

    您的代码中存在几个问题:

    • 您在 gdt_code 描述符中缺少基本高位字的低位字节 . 只需在 dw 0x0 之后添加 db 0x0 即可 .

    • Frank Kotler写道 gdt_descriptor 必须包含线性地址 . 是的,'s true, but it'不是唯一需要线性地址的地方 . 您可以在任何代码之前使用 ORG 指令,或手动将原点添加到此字段 .

    • 指令 lgdt 仍然使用 ds 寄存器来计算 seg:off 地址 . 在 org 下编写代码时,应将其设置为零 .

    • 远程跳转到保护模式也需要用作偏移的线性地址 . 请记住,此跳转是在兼容模式下执行的(因为它是保护模式切换后执行的第一条指令) . 它使用两个字节用于段选择器(冒号前)和 only two bytes 用于偏移量(冒号后) . 这意味着您不应该尝试跳转到高于 0xFFFF 的地址 . 再次,检查代码的来源 .

  • 0

    在你的 gdt_descriptor 中,你've got the limit and the address. Unlike most other addresses, this is NOT a segment:offset address. It needs to be a linear address. As an MBR, you' ve可能会将它从最初加载的位置移到0x7C00 . gdt_descriptor 中的地址(通常称为 gdtr )需要是您现在所处位置的线性地址 . 您没有显示足够的代码以确定,但我怀疑您的问题是正确的 .

相关问题