实模式
- 运行于16位的CPU环境下:
- 16位的寄存器
- 16位的数据总线
- 20位的地址总线,以及1MB的寻址能力(2^20B)
- 一个地址由段和偏移两部分组成,物理地址=段值x16+偏移(段值和偏移都是16位,段值左移四位最后计算出来的地址才是20位)
保护模式
- 运行与32位的CPU环境下
- 32位的寄存器
- 32位的数据总线
- 32位的地址总线,以及4GB的寻址能力(2^32B)
- 一个地址仍旧由段和偏移两部分组成
保护模式与实模式的区别
- 实模式下的段值可以看做是地址的一部分,段值为xxxxh表示以xxxx0h(物理地址,段值二进制左移4位,16进制左移一位)开始的一段内存
- 保护模式下的段值仅仅只是一个索引,指向一个数据结构(GDT或LDT)的一个表项(描述符),表项中详细定义了段的起始地址、界限、属性等内容
GDT(Global Descriptor Table,全局描述符表)
GDT中的每一个描述符就定义一个段
-
描述符分为3类
- 代码段和数据段描述符
- 系统段描述符
- 门描述符
-
代码段和数据段描述符的结构
(共8个字节,段基址4个字节,段界限2个字节,属性2个字节)
-
选择子的结构
(共2个字节,16位)
若不考虑前3位,那么可以将选择子看成是对应描述符相对于GDT基址的偏移
-
程序如何将对应段与寄存器联系起来呢?
mov ax, Selector ; Selector表示一个选择子
mov gs, ax ; gs表示段寄存器
- 保护模式下的寻址
让我们解析下这个寻址过程:
- 首先,我们在程序中使用的是逻辑地址(段:偏移的形式)
- 段寄存器存储的是一个段描述符的选择子,指向GDT或LDT结构数组中的某个表项
- 指向的段描述符结合偏移量在定位到线性地址(由它的基址、界限、属性决定)
实模式跳转到保护模式
分为6步
- 准备GDT
- 用lgdt加载gdtr
- GdtPtr是个小的数据结构,共6个字节(前两个字节是GDT的界限,后4个字节是GDT的基地址),把GDT的物理地址填充到这个数据结构中,然后执行指令
lgdt [GdtPtr]
将GdtPtr指示的6个字节加载到寄存器gdtr中
gdtr寄存器与GdtPtr的结构完全一样
- GdtPtr是个小的数据结构,共6个字节(前两个字节是GDT的界限,后4个字节是GDT的基地址),把GDT的物理地址填充到这个数据结构中,然后执行指令
- 关中断
- 执行指令
cli
- 执行指令
- 打开A20
- 执行指令
; 打开地址线A20
in al, 92h
or al, 00000010b
out 92h, al
- 置cr0的PE位(第0个位置)为1
- 寄存器cr0的PE位为0表示CPU运行于实模式,为1表示保护模式
- 执行指令
; 准备切换到保护模式
mov eax, cr0
or eax, 1
mov cr0, eax
- 跳转,进入保护模式
- 此时cs寄存器的值还是实模式下的值,将代码段的选择子装入cs寄存器中
- 执行指令
jmp dword selector:0
,selector根据自己的选择子替换,dword不可省略
初始化段描述符---程序解析
以下程序以代码段LABEL_DESC_CODE32为例
- 准备GDT的信息
[SECTION .gdt]
; GDT
; 段基址, 段界限, 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
; GDT 结束
GdtLen equ $ - LABEL_GDT ; GDT长度
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址
; GDT 选择子
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt]
LABEL_GDT就是GDT的首地址了
- 初始化GDT:加载段选择子
xor eax, eax ; 清空 eax 寄存器
mov ax, cs ; 将当前代码段寄存器 cs 的值加载到 ax 寄存器
shl eax, 4 ; 将 ax 寄存器的值左移4位(乘以16),获得段的线性地址
add eax, LABEL_DESC_CODE32 ; 将 LABEL_DESC_CODE32 的地址加到 eax 中,得到代码段的线性地址
- 初始化GDT:设置描述符的其他字段
mov word [LABEL_DESC_CODE32 + 2], ax ; 将 ax 寄存器的低16位存储到 LABEL_DESC_CODE32+2 的位置,这是段选择子
shr eax, 16 ; 将 eax 寄存器右移16位,获得高16位
mov byte [LABEL_DESC_CODE32 + 4], al ; 将 al 寄存器的低8位存储到 LABEL_DESC_CODE32+4 的位置,描述符的访问权限字节
mov byte [LABEL_DESC_CODE32 + 7], ah ; 将 ah 寄存器的高8位存储到 LABEL_DESC_CODE32+7 的位置,描述符的段基址的高字节
- 加载全局描述符表寄存器(GDTR)
xor eax, eax ; 清空 eax 寄存器
mov ax, ds ; 将数据段寄存器 ds 的值加载到 ax 寄存器
shl eax, 4 ; 将 ax 寄存器的值左移4位(乘以16),获得全局描述符表(GDT)的基地址
add eax, LABEL_GDT ; 将 LABEL_GDT 的地址加到 eax 中,得到完整的 GDT 的线性地址
mov dword [GdtPtr + 2], eax ; 将 eax 的值存储到 GdtPtr+2 的位置,准备加载 GDTR 寄存器
lgdt [GdtPtr] ; 加载 GDTR
标签:保护模式,GDT,LABEL,eax,描述符,寄存器,------,DESC
From: https://www.cnblogs.com/winter-z/p/18327122