虚幻模式

虚幻的方式利用了如何在 Intel 和 AMD 处理器的加载和保存的信息来描述段两个事实。

  1. 处理器将在移动期间获取的描述符信息高速缓存在保护模式下的选择器寄存器中。
    这些信息存储在选择器寄存器本身的架构不可见部分中。

  2. 在实模式中,选择器寄存器称为段寄存器,但除此之外,它们指定相同的寄存器组,因此它们也具有不可见的部分。这些部分用固定值填充,但是对于从刚刚加载的值派生的基数。

在这种观点中,实模式只是保护模式的一种特殊情况:其中段的信息,例如基数和限制,在没有 GDT / LDT 的情况下被提取,但仍然从段寄存器隐藏部分读取。

通过切换保护模式并制作 GDT 可以创建具有所需属性的段,例如 0 的基数和 4GiB 的限制。
通过连续加载选择器寄存器,这些属性被高速缓存,然后可以以实模式切换回来并具有段寄存器,通过该段寄存器访问整个 32 位地址空间。

BITS 16

jmp 7c0h:__START__

__START__:
 push cs
 pop ds
 push ds
 pop ss
 xor sp, sp

 
 lgdt [GDT]            ;Set the GDTR register
 

 cli                ;We don't have an IDT set, we can't handle interrupts

 ;Entering protected mode

 mov eax, cr0
 or ax, 01h            ;Set bit PE (bit 0) of CR0
 mov cr0, eax            ;Apply

 ;We are now in Protected mode

 mov bx, 08h           ;Selector to use, RPL = 0, Table = 0 (GDT), Index = 1

 mov fs, bx            ;Load FS with descriptor 1 info
 mov gs, bx            ;Load GS with descriptor 1 info

 ;Exit protected mode

 and ax, 0fffeh            ;Clear bit PE (bit0) of CR0
 mov cr0, eax                   ;Apply

 sti                

 ;Back to real mode

 ;Do nothing
 cli
 hlt 

 GDT:
    ;First entry, number 0
    ;Null descriptor
    ;Used to store a m16&32 object that tells the GDT start and size

    dw 0fh                 ;Size in byte -1 of the GDT (2 descriptors = 16 bytes)
    dd GDT + 7c00h         ;Linear address of GDT start (24 bits)
    dw 00h                 ;Pad 

    dd 0000ffffh           ;Base[15:00] = 0, Limit[15:00] = 0ffffh
    dd 00cf9200h           ;Base[31:24] = 0, G = 1, B = 1, Limit[19:16] = 0fh, 
               ;P = 1, DPL = 0, E = 0, W = 1, A = 0, Base[23:16] = 00h

 TIMES 510-($-$$) db 00h
 dw 0aa55h 

注意事项

  • 一旦重新加载段寄存器,即使具有相同的值,处理器也会根据当前模式重新加载隐藏属性。这就是为什么上面的代码使用 fsgs 来保存扩展段:这种寄存器不太可能被各种 16 位服务使用/保存/恢复。
  • lgdt 指令不会加载指向 GDT 的远指针,而是加载 24 位(可以被覆盖为 32 位) 线性地址。这不是近地址,而是物理地址 (因为必须禁用分页)。这就是 GDT+7c00h 的原因。
  • 上面的程序是一个引导程序(对于 MBR,它没有 BPB),其设置 cs / ds / ss TP 7C00h 处,并开始从 0 位置的计数器,以便在偏移的字节 X 在文件中是在偏移量 X 在段 7C00h 处和在将线性地址 7C00h 处+ X
  • 必须禁用中断,因为在保护模式下短时间往返没有设置 IDT。
  • 代码使用 hack 来保存 6 个字节的代码。lgdt 加载的结构保存在… GDT 本身,在空描述符(第一个描述符)中。

有关 GDT 描述符的说明,请参阅“ 英特尔手册”第 3A 卷第 3.4.3 章。