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

设置Unreal Mode时是否需要配置CS寄存器?

关于Unreal Mode切换示例中CS寄存器与远跳转的疑问

OSDev提供的Unreal Mode切换示例代码如下:

ORG 0x7c00                ; add to offsets
 
start:
   xor ax, ax             ; make it zero
   mov ds, ax             ; DS=0
   mov ss, ax             ; stack starts at seg 0
   mov sp, 0x9c00         ; 2000h past code start, 
                          ; making the stack 7.5k in size
 
   cli                    ; no interrupts
   push ds                ; save real mode
 
   lgdt [gdtinfo]         ; load gdt register
 
   mov  eax, cr0          ; switch to pmode by
   or al,1                ; set pmode bit
   mov  cr0, eax
   jmp 0x8:pmode
 
pmode:
   mov  bx, 0x10          ; select descriptor 2
   mov  ds, bx            ; 10h = 10000b
 
   and al,0xFE            ; back to realmode
   mov  cr0, eax          ; by toggling bit again
   jmp 0x0:unreal
 
unreal:
   pop ds                 ; get back old segment
   sti
 
   mov bx, 0x0f01         ; attrib/char of smiley
   mov eax, 0x0b8000      ; note 32 bit offset
   mov word [ds:eax], bx
 
   jmp $                  ; loop forever
 
gdtinfo:
   dw gdt_end - gdt - 1   ;last byte in table
   dd gdt                 ;start of table
 
gdt:        dd 0,0        ; entry 0 is always unused
codedesc:   db 0xff, 0xff, 0, 0, 0, 10011010b, 00000000b, 0
flatdesc:   db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
gdt_end:
 
   times 510-($-$$) db 0  ; fill sector w/ 0's
   dw 0xAA55              ; Required by some BIOSes

针对这段代码,有以下几个疑问及解答:

疑问1:为何要操作CS?我们仅需扩大数据段限制,只需设置DS即可

操作CS是因为早期x86 CPU的设计要求:当把CR0的PE位置1进入保护模式后,必须立即执行一次远跳转来刷新指令预取队列。此时CPU的指令预取队列里还残留着实模式下的指令解码状态,远跳转能强制清空队列,让CPU完全切换到保护模式的指令解码逻辑。如果跳过这一步,后续指令可能被错误解码,直接导致系统崩溃。

疑问2:在mov cr0, eax之后(或执行近跳转刷新预取队列后),直接用mov给DS加载GDT条目是否可行?

不行。刚设置CR0.PE=1后,CPU虽然进入保护模式,但CS寄存器仍然是实模式下的段值,没有加载对应的保护模式段描述符。此时直接给DS加载GDT条目会触发#GP(一般保护异常)——保护模式下加载段寄存器需要验证权限,而CS此时还是实模式的“伪描述符”,权限不匹配,无法完成数据段寄存器的加载。必须先通过远跳转让CS加载合法的保护模式代码段描述符,建立起有效的保护模式执行环境后,才能安全地加载其他段寄存器。

疑问3:代码执行两次远跳转,返回Unreal Mode时CS=8,与CS.base不匹配会破坏中断的CS:IP保存恢复机制,完全不使用远跳转是否可行?

可以完全不用远跳转,但要处理两个核心点:

  • 进入保护模式时,用近跳转代替远跳转来刷新预取队列。近跳转不会修改CS的值,此时CS还是实模式的段值,但CR0.PE=1会让CPU把它当作一个兼容的保护模式段描述符(基地址=段值<<4,限长0xFFFF),后续加载DS的操作是合法的。
  • 返回Unreal Mode时,直接修改CR0.PE=0即可,不需要远跳转。此时所有数据段寄存器已经加载了32位平坦段描述符,回到实模式后这些寄存器的隐藏部分会保留保护模式的设置(基地址0,限长4GB),这正是Unreal Mode的核心特性——数据段使用32位平坦模式,代码段保持实模式。

不过要注意,部分非常老旧的CPU(比如早期80386)对近跳转刷新预取队列的支持不佳,远跳转是兼容性更好的做法。但如果只针对较新的x86 CPU,完全可以不用远跳转,避免CS被修改导致的中断机制问题。

内容的提问来源于stack exchange,提问作者moehr1z

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:11:00