您的位置:首页 > 其它

十、试验保护模式

2015-11-15 00:00 183 查看
问题一、怎么理解界限 = 大小 - 1?

界限就是边界、分界线,就是终止的地方,内存的界限就是一段内存的终址相对于基址的偏移号(不是偏移量,偏移号 = 偏移量 -1)。
为什么要减一?因为内存地址编号从 0 开始,第一个内存地址对应内存地址编号 0 ,第 n 个内存地址对应内存地址编号 n - 1。内存地址序号的上限减一对应内存地址编号的上限,而内存地址的最大序号就是这段内存的大小,即一段内存的大小 - 1 = 这段内存的界限。

问题二:描述符是什么?

不要被“符”字迷惑了,说白了“符”就是个数据结构(在 C语言里就是个 struct)。“描述”两个字从字面理解就行,就是对一个东西进行详细说明。我们这里学习的保护模式,描述的就是内存的分段管理模式。那么“描述符”就是说明一段内存的详细情况的数据结构。实际上,描述符就是定义一段内存的起始地址、界限、访问属性的一个数据结构,描述符表就是一个由描述符为元素组成的数组,看起来像一个表格而已。

问题三:GDT 表第一个为什么要留空呢?

因为选择子的结构是这样的:

; ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓

; ┃15┃14┃13┃12┃11┃10┃09┃08┃07┃06┃05┃04┃03┃02┃01┃0 ┃

; ┣━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━╋━━╋━━┻━━┫

; ┃ 描述符索引 ┃TI ┃ RPL ┃

; ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━┛

选择子中正真索引 GDT 表的索引号只在高 13 位,低 3 位要留给 TI 和 RPL,即索引号实际上从第 3 位开始,就是0b0000000000001000 = 8;索引号每次增加的值(步进)也不是 1 ,而是 0b1000 = 8 。

刚好 GDT 表中,一个描述符也是占用 8 个字节。

现在简单了:把第一个描述符留空不用,只是占据 8 个字节的空间,在 TI 和 RPL 都等于 0 的情况下,选择子就可以简单等同于描述符在 GDT 表中的偏移了!即:

第一个选择子 = 一号描述符在 GDT 表中的偏移 = 8

第 n 个选择子 = n 号描述符在 GDT 表中的偏移 = n * 8

打开地址线 A20、打开保护模式标志都是固定格式,照抄就行。lgdt 和 cli 是 CPU 指令,看看其指令说明就行。再来读下面的代码,就没啥难度了。

; TestPM.nas
; 初识保护模式
; 四彩
; 2015-11-15

; ========================================================================================
; ----------------------------------------------------------------------------------------
org 0x7C00
jmp Label_RM_main

; ****************************************************************************************

; ========================================================================================
%include "./INC/Descriptor.inc"
;
; ----------------------------------------------------------------------------------------
; GDT                          段基址   段界限    属性
Label_Desc_Empty  : Descriptor 0,       0,        0                 ; 空描述符
Label_Desc_PM     : Descriptor 0,       0xFFFF,   DA_32 + DA_CS_E   ; 保护模式代码段描述符
Label_Desc_Video  : Descriptor 0xB8000, 0xFFFF,   DA_DS_RW          ; 显存段描述符
;
; ----------------------------------------------------------------------------------------
; GDTPtr
GDTLen  equ $ - Label_Desc_Empty
GDTPtr  dw  GDTLen - 1                      ; 界限
dd  0                               ; 基址
;
; ----------------------------------------------------------------------------------------
; 选择子
SelectorPM      equ Label_Desc_PM    - Label_Desc_Empty
SelectorVideo   equ Label_Desc_Video - Label_Desc_Empty
;
; ****************************************************************************************

[BITS 16]
; ========================================================================================
; 实模式下开启保护模式
; ----------------------------------------------------------------------------------------
; 程序入口,实模式代码段
Label_RM_main:
; 填上保护模式代码段描述符的基址(界限、属性在定义时已初始化)
xor eax, eax
mov ax, cs
shl eax, 4
add eax, Label_PM_main                  ; 保护模式程序入口的绝对内存地址,即为其基址
mov word[Label_Desc_PM + 2], ax         ; 拆分成 3 部分存入相应位置
shr eax, 16
mov byte[Label_Desc_PM + 4], al
mov byte[Label_Desc_PM + 7], ah

; 填上 GDTPtr 的基址(界限在定义时已初始化)
xor eax, eax
mov ax, cs
shl eax, 4
add eax, Label_Desc_Empty
mov dword[GDTPtr + 2], eax

; 加载 GDT
lgdt [GDTPtr]

; 屏蔽中断
cli

; 打开地址线 A20
in al, 0x92
or al, 0b10
out 0x92, al

; 打开保护模式标志
mov eax, cr0
or eax, 1
mov cr0, eax

; 修改 CS : EIP
jmp dword SelectorPM : 0

; ****************************************************************************************

[BITS 32]
; ========================================================================================
; 保护模式代码段,由实模式跳入
Label_PM_main:
mov ax, SelectorVideo
mov gs, ax
mov edi, (80 * 5 + 35) * 2
mov ah, 0xC
mov al, 'O'
mov [gs : edi], ax
mov al, 'K'
mov [gs : edi + 2], ax

jmp $

; ****************************************************************************************

; ========================================================================================
; FAT12 文件系统引导扇区引导代码的剩余部分用 0 填满
times 510 - ($ - $$) db 0

; ****************************************************************************************

; ========================================================================================
; FAT12 文件系统引导扇区的的结束标志(最后 2 字节,必须是 0xAA55)
dw 0xAA55

; ****************************************************************************************

; ========================================================================================
CodeLenOfPM     equ $ - Label_PM_main

; ****************************************************************************************
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: