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

标签 assembly protected-mode mbr real-mode gdt

我是根据尼克·布伦德尔的书来做这件事的。我写了一个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崩溃并重新启动。而且书上说切换操作需要跳远。

可以帮我做一下切换操作吗?

最佳答案

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

  1. 您的 gdt_code 描述符中缺少基数高位字的低字节。只需在 dw 0x0 之后添加 db 0x0 即可。
  2. Frank Kotler 写道,gdt_descriptor 必须包含线性地址。是的,确实如此,但这并不是唯一需要线性地址的地方。您可以在任何代码之前使用 ORG 指令,或手动将 origin 添加到此字段。
  3. 指令lgdt仍然使用ds寄存器进行seg:off地址计算。在 org 下编写代码时,应将其设置为零。
  4. 远跳转到保护模式也需要线性地址作为偏移量。请记住,此跳转是在兼容模式下执行的(因为它是保护模式切换后执行的第一条指令)。它使用两个字节作为段选择器(冒号之前),仅使用两个字节作为偏移量(冒号之后)。这意味着您不应尝试跳转到高于 0xFFFF 的地址。再次检查代码的来源。
  5. 你所说的会导致cpu崩溃并重启的mov ax, 10指令,使用了错误的值!我们需要的选择器位于偏移量 16 处,即十六进制的 0x10。由于您定义了 DATA_SEG equ gdt_data - gdt_start,您确实应该编写 mov ax, DATA_SEG

关于assembly - 我无法将 cpu 从实模式切换到保护模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18568711/

相关文章:

assembly - 在 x86-64 中指定 8 位立即数(GNU 汇编器)

c# - 如何在 IE 保护模式下访问 AppData(从托管 BHO)

assembly - 从 DOS 程序进入保护模式

linux - Windows MBR 被 linux 命令覆盖 dd if=/dev/zero of=/dev/sdb bs=512 count1

c++从无文件系统执行代码

assembly - 写入MBR代码

assembly - 在 64 位 masm 中打印 hello

c - 为什么 "guarded do"在 asm 中比 "jump to middle"好

x86 从实模式 CPL(当前特权级别)切换到保护模式

assembly - 编译错误 : relocation R_X86_64_PC32 against undefined symbol