繁体   English   中英

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

[英]I failed in switching the cpu from real-mode to protected-mode

我是根据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崩溃并重新启动。 书中说开关操作需要跳远。

您能帮我进行切换操作吗?

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM