分类:
2011-07-12 15:07:15
原文地址:我的OS(1)---- 初识保护模式 作者:fireaxe
在IA32下,CPU有两种工作模式:实模式和保护模式。在实模式下,段寄存器含有段值,为访问存储器形成物理地址时,处理器引用相应的某个段寄存器并将其值乘以16,形成20位的段基地址。计算公式如下:物理地址 = 段值*16 + 偏移。
其中段值和偏移都是16位的,这样通过“段:偏移”的方式达到了1MB的寻址能力。
在保护模式下,寄存器是32位的,但是为了兼容性,地址仍然用“段:偏移”的方式来表示,只不过这时的保护模式下的“段”的概念已经发生了根本的改变,虽然段值仍然由原来的cs、ds等寄存器表示,但是此时它仅仅是一个索引,叫做选择子,指向一个数据结构(叫做GDT,Global Descriptor Table全局描述符表或者LDT,Local Descriptor Table局部描述符表)的一个表项(叫做Descriptor描述符)。
1.1.2 地址转换方式
实模式下的地址转换方式是段地址加偏移量。段地址左移4位加偏移量得到线性地址。假设我们在ES中存入0x1000,在DI中存入0xFFFF,则线性地址ES:DI=0x1000*0x10+0xFFFF=0x1FFFF。
保护模式下的地址转换方式也是段地址加偏移量。段地址不是直接放在段寄存器中,而是以段寄存器中的值为偏移量(选择子)、Gdtr寄存器中的值作为基址,找到段地址。假设上面的数据不变ES=0x1000,DI=0xFFFF,现在ES:DI等于什么呢?公式如下:(注:0x1000=1000000000000b= 10 0000 0000 0 00)ES:DI=全局描述符表中第0x200项描述符给出的段基址+0xFFFF。实模式下称ES为“段寄存器”,而到了保护模式就说是“选择子”。其实它们都是一种映射,只是映射规则不同而已:在实模式下这个“地址转换方式”是“左移4位”;在保护模式下是“查全局/局部描述表”。前者是系统定义的映射方式,后者是用户自定义的转换方式。
1.1.3 GDT描述符
保护模式下引入描述符来描述各种数据段,所有的描述符均为8个字节(0-7),由第5个字节说明描述符的类型,类型不同,描述符的结构也有所不同。若干个描述符集中在一起组成描述符表,而描述符表本身也是一种数据段,也使用描述符进行描述。从现在起,“地址转换”由描述符表来完成,从这个意义上说,描述符表是一张地址转换函数表。
(1) P: 存在(Present)位。
P=1 表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;
P=0 表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。
(2) DPL: 表示描述符特权级(Descriptor Privilege level),共2位。它规定了所描述段的特权级,用于特权检查,以决定对该段能否访问。
(3) S: 说明描述符的类型。
对于存储段描述符而言,S=1,以区别与系统段描述符和门描述符(S=0)。
(4) TYPE: 说明存储段描述符所描述的存储段的具体属性。
数据段类型
类型值 说明
----------------------------------
0 只读
1 只读、已访问
2 读/写
3 读/写、已访问
4 只读、向下扩展
5 只读、向下扩展、已访问
6 读/写、向下扩展
7 读/写、向下扩展、已访问
代码段类型
类型值 说明
----------------------------------
8 只执行
9 只执行、已访问
A 执行/读
B 执行/读、已访问
C 只执行、一致码段
D 只执行、一致码段、已访问
E 执行/读、一致码段
F 执行/读、一致码段、已访问
系统段类型
类型编码 说明
----------------------------------
0 <未定义>
1 可用286TSS
2 LDT
3 忙的286TSS
4 286调用门
5 任务门
6 286中断门
7 286陷阱门
8 未定义
9 可用386TSS
A <未定义>
B 忙的386TSS
C 386调用门
D <未定义>
E 386中断门
F 386陷阱门
(5) G: 段界限粒度(Granularity)位。
G=0 表示界限粒度为字节;
G=1 表示界限粒度为4K 字节。
注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。
(6) D: D位是一个很特殊的位,在描述可执行段、向下扩展数据段或由SS寄存器寻址的段(通常是堆栈段)的三种描述符中的意义各不相同。
⑴ 在描述可执行段的描述符中,D位决定了指令使用的地址及操作数所默认的大小。
① D=1表示默认情况下指令使用32位地址及32位或8位操作数,这样的代码段也称为32位代码段;
② D=0 表示默认情况下,使用16位地址及16位或8位操作数,这样的代码段也称为16位代码段,它与80286兼容。可以使用地址大小前缀和操作数大小前缀分别改变默认的地址或操作数的大小。
⑵ 在向下扩展数据段的描述符中,D位决定段的上部边界。
① D=1表示段的上部界限为4G;
② D=0表示段的上部界限为64K,这是为了与80286兼容。
⑶ 在描述由SS寄存器寻址的段描述符中,D位决定隐式的堆栈访问指令(如PUSH和POP指令)使用何种堆栈指针寄存器。
① D=1表示使用32位堆栈指针寄存器ESP;
② D=0表示使用16位堆栈指针寄存器SP,这与80286兼容。
(7) AVL: 软件可利用位。80386对该位的使用未左规定,Intel公司也保证今后开发生产的处理器只要与80386兼容,就不会对该位的使用做任何定义或规定。
描述符类型值说明,其中:
DA_ : Descriptor Attribute
D : 数据段
C : 代码段
S : 系统段
R : 只读
RW : 读写
A : 已访问
其它 : 可按照字面意思理解
----------------------------------------------------------------------------
DA_32 EQU 4000h ; 32 位段
DA_DPL0 EQU 00h ; DPL = 0
DA_DPL1 EQU 20h ; DPL = 1
DA_DPL2 EQU 40h ; DPL = 2
DA_DPL3 EQU 60h ; DPL = 3
----------------------------------------------------------------------------
存储段描述符类型值说明
----------------------------------------------------------------------------
DA_DR EQU 90h ; 存在的只读数据段类型值
DA_DRW EQU 92h ; 存在的可读写数据段属性值
DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
DA_C EQU 98h ; 存在的只执行代码段属性值
DA_CR EQU 9Ah ; 存在的可执行可读代码段属性值
DA_CCO EQU 9Ch ; 存在的只执行一致代码段属性值
DA_CCOR EQU 9Eh ; 存在的可执行可读一致代码段属性值
----------------------------------------------------------------------------
系统段描述符类型值说明
----------------------------------------------------------------------------
DA_LDT EQU 82h ; 局部描述符表段类型值
DA_TaskGate EQU 85h ; 任务门类型值
DA_386TSS EQU 89h ; 可用 386 任务状态段类型值
DA_386CGate EQU 8Ch ; 386 调用门类型值
DA_386IGate EQU 8Eh ; 386 中断门类型值
DA_386TGate EQU 8Fh ; 386 陷阱门类型值
----------------------------------------------------------------------------
1.1.4 Gdtr寄存器
保护模式下,地址转换通过查询GDT表实现。那么,系统如何知道GDT在内存中的位置呢?
在80x86系列中使用寄存器Gdtr实现,GDTR寄存器长度为6字节(48位),其中低2字节表示GDT表长度长度(limit),高4字节表示GDT表基址(实际是用于校验Seletor是否越界)。
利用Gdtr寄存器只能找到GDT表的基址,而要找到对应的表项则需要使用Selector了。
选择子是一个2字节的数,共16位,最低2位表示RPL,第3位表示查表是利用GDT(全局描述符表)还是LDT(局部描述符表)进行,最高13位给出了所需的描述符在GDT描述符表中的地址。(注:13位正好足够寻址8K项)
在程序运行时,段寄存器中保存的就是Selector。CPU通过Gdtr寄存器加段寄存器中保存的Selector的方式索引到对应的GDT表项,找到实际的段地址,然后加上指令中的地址,才能得到线性地址。如果没有使用页表结构,则这个线性地址就是物理地址了。
RPL(Requested Privilege Level): 请求特权级,用于特权检查。
TI(Table Indicator): 引用描述符表指示位
TI=0 指示从全局描述符表GDT中读取描述符;
TI=1 指示从局部描述符表LDT中读取描述符。
----------------------------------------------------------------------------
选择子类型值说明
SA_ : Selector Attribute
SA_RPL0 EQU 0 ; ┓
SA_RPL1 EQU 1 ; ┣ RPL
SA_RPL2 EQU 2 ; ┃
SA_RPL3 EQU 3 ; ┛
SA_TIG EQU 0 ; ┓TI
SA_TIL EQU 4 ; ┛
----------------------------------------------------------------------------
; usage: Descriptor Base, Limit, Attr ; Base: dd ; Limit: dd (low 20 bits available) ; Attr: dw (lower 4 bits of higher byte are always 0) %macro Descriptor 3 dw %2 & 0FFFFh ; 段界限 1 (2 字节) dw %1 & 0FFFFh ; 段基址 1 (2 字节) db (%1 >> 16) & 0FFh ; 段基址 2 (1 字节) dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性 1 + 段界限 2 + 属性 2 (2 字节) db (%1 >> 24) & 0FFh ; 段基址 3 (1 字节) %endmacro ; 共 8 字节 |
1.1.6 CR0寄存器
CR0是x86系列cpu的保护控制寄存器。CR0的第0位PE位用于设置CPU工作模式。
PE=0:实模式
PE=1:保护模式