You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

32PM→16RM模式切换异常:QEMU中16位代码被当作32位执行

32位保护模式→16位实模式切换流程及问题排查

正确的32PM→16RM切换步骤(x86_64平台兼容)

要让CPU正确进入16位实模式并执行对应指令,必须严格遵循以下流程:

  • 配置GDT中的16位兼容段:在全局描述符表中添加一个基址为0、限长0xFFFF的段描述符,属性设为0x92(表示存在、特权级0、可读写、16位模式),确保切换后能映射实模式的1MB地址空间。
  • 禁用中断与分页:先执行cli关闭中断;如果当前开启了分页(哪怕是32位分页),必须清除CR0寄存器的PG位(位31),再通过远跳转刷新TLB,避免地址翻译混乱。
  • 远跳转到16位段:通过jmp 选择子:实模式入口地址的远跳转指令,强制CPU将CS寄存器切换到之前定义的16位段,这一步是触发CPU切换指令译码模式的关键——仅修改CR0的PE位不足以切换指令模式。
  • 恢复实模式环境:
    • 加载实模式IDT:用lidt加载一个限长为0x3FF的IDT指针(对应实模式下的256个中断向量)。
    • 退出保护模式:清除CR0的PE位(位0),彻底回到实模式。
    • 刷新段寄存器:将DS、ES、SS、FS、GS全部设置为0,确保所有段的基址都是0,符合实模式的内存模型。
    • 按需开启中断:执行sti,之后就可以调用BIOS中断了。

你的问题定位

结合你描述的现象(16位代码被当作32位执行),问题大概率出在代码逻辑上,核心可能是以下几点:

  • 未执行远跳转切换CS到16位段:如果只是直接清除CR0的PE位,CPU会继续以32位模式译码指令,导致16位指令被错误解析。
  • GDT中的16位段属性错误:比如误将段的D位(位5)设为1(表示32位段),这样即使切换到该段,CPU仍会按32位模式执行。
  • 分页未完全关闭:如果CR0的PG位仍为1,关闭PE位后CPU的地址翻译机制会异常,间接导致指令执行混乱。
  • 段寄存器未刷新:切换到实模式后,DS/ES等寄存器仍保留保护模式下的段基址,访问内存时会出现地址偏移,引发未定义行为。

构建环节(编译、链接)的可能性很低:你已经尝试了flat binary格式和调整链接脚本,只要编译时用-m16生成16位指令、链接脚本将16位代码定位到正确的物理地址,就不会导致指令被错误解析。

QEMU的问题可以排除:QEMU对x86模式切换的模拟非常成熟,x86_64 CPU本身也完全兼容实模式,除非你错误配置了CPU型号(比如指定了不兼容x86的架构),否则不会出现这类模拟错误。

修复建议

  1. 强制添加远跳转步骤:在清除CR0的PE位之前,先跳转到GDT中的16位段,示例代码:
    ; 假设16位段的选择子是0x10
    jmp 0x10:real_mode_entry
    real_mode_entry:
        ; 后续执行清除PE位等操作
    
  2. 验证GDT段描述符:确保16位段的属性正确,示例定义:
    real_mode_segment:
        dw 0xFFFF       ; 限长低16位
        dw 0x0000       ; 基址低16位
        db 0x00         ; 基址中8位
        db 0x92         ; 16位可读写段属性
        db 0x00         ; 限长高4位 + 基址高8位
        db 0x00         ; 基址最高8位
    
  3. 彻底关闭分页:切换前必须清除CR0的PG位并刷新TLB:
    mov eax, cr0
    and eax, ~(1 << 31)  ; 清除PG位
    mov cr0, eax
    jmp 0x8:flush_tlb    ; 远跳转刷新TLB
    flush_tlb:
    
  4. 切换到实模式后立即刷新所有段寄存器:
    mov ax, 0
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov fs, ax
    mov gs, ax
    

内容的提问来源于stack exchange,提问作者Self learning student

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 02:53:12