- 引言
阅读于渊的《ORANGE'S:一个操作系统的实现》,对一些知识点做一个笔记,方便以后复习相关知识。
这一篇主要对GDT结构体代码进行讲解。
GDT结构体
- 知识补充
随着内存的增加,以往的DOS的寻址方式已经不再适用,同时为了系统的安全出现了保护模式。过去使用 段基址:偏移地址 的寻址方式已经不能满足4GB的内存,段寄存器转变为选择子SA,称为描述符表的索引,描述符表分为全局描述符表(GDT)与局部描述符表(LDT), 全局描述符表只用一个,存储操作系统的描述符信息。一般LDT的索引存储在GDT中。 同时出现了分页机制,所有从描述符表中查找的地址都是线性地址,没有采用分页机制时,线性地址即物理地址。
描述符
描述符占8个字节,以下分别讲述每个字节存储的相关信息(从高地址开始)。
- 字节7:
段基址2 - 字节6:
G(1bit):【段界限粒度位,G=0 表示界限粒度为字节,G=1 表示界限粒度为4K字节,*** 注意:界限粒度只对段界限有效,对段基地址无效,段基址总是以字节为单位】
D(1bit):【 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兼容。 】
0(1bit)
AVL(4bit):【软件可利用位。80386对该位的使用未左规定,Intel公司也保证今后开发生产的处理器只要与80386兼容,就不会对该位的使用做任何定义或规定。 】
在下列类型值命名中:
;
DA_ : Descriptor Attribute;
D : 数据段;
C : 代码段;
S : 系统段;
R : 只读;
RW : 读写;
A : 已访问;
其它 : 可按照字面意思理解
段界限2(4bit)
- 字节5:
P(1bit):【 存在位,P=1,表示描述符对地址的转换时有效的,或者说该描述符所描述的段存在,即在 内存中】
DPL(2bit):【表示描述符的特权级,规定了所描述段的特权级,用于特权检查,以决定该段能否访问】
S(1bit):【说明描述符类型。 对于存储描述符而言,S=1, 以区别系统段描述符和门描述符S=0】
TYPE(4bit):【说明存储段描述符所描述的存储段的具体属性】
; 数据段类型 类型值 说明
; ----------------------------------
; 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陷阱门
- 字节2,3,4: 段基址1
- 字节0,1: 段界限1
描述符类型
; 描述符类型DA_32 EQU 4000h
; 32 位段DA_DPL0 EQU 00h
; DPL = 0DA_DPL1 EQU 20h
; DPL = 1DA_DPL2 EQU 40h
; DPL = 2DA_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 陷阱门类型值
选择子SA
选择子SA共16位,SS选择索引(段寄存器)
选择子的高13位为描述符索引(即描述符表的大小<=2^13)
第2位为TI:描述符表指示位 TI=0表示GDT中读取描述符,TI=1从LDT中读取描述符
第0、1位: PRL(请求的特权级),一般RPL>=DPL才可以访问相应的段
选择子类型值说明
; 其中:
; SA_ : Selector Attribute
SA_RPL0 EQU 0 ; ┓
SA_RPL1 EQU 1 ; ┣ RPL
SA_RPL2 EQU 2 ; ┃
SA_RPL3 EQU 3 ; ┛
SA_TIG EQU 0 ; ┓
TISA_TIL EQU 4 ; ┛
描述符宏定义
描述符占8个字节,以下分别讲述每个字节存储的相关信息(从高地址开始)。
- 字节7: 段基址2
- 字节6: G(1bit)、D(1bit)、 0(1bit)、 AVL(4bit)、 段界限2(4bit)
- 字节5: P(1bit)、DPL(2bit)、 S(1bit)、TYPE(4bit)
- 字节2,3,4: 段基址1(24位)
- 字节0,1: 段界限1(16位)
; 描述符
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)
; Attr: dw (lower 4 bits of higher byte are always 0)
; 定义Descriptor描述符结构体
; 输入三个参数,分别为 :
; 段基址(dd双字类型32位)
; 段界限(dd, 低20bits可用)
; 属性(dw 16bits, 高字节的低4位总为0即AVL) 除去段基址与段界限共16bit属性
%macro Descriptor 3 ; 3表示用3个输入
dw %2 & 0FFFFh ; 段界限1 (%2表示第二个输入的值,&0FFFFh, 表示取低16位即低2个字节)
dw %1 & 0FFFFh ; 段基址1(%1第一个输入值,&0FFFFh,取低16位)
db (%1 >> 16) & 0FFh ; 段基址2(第一个输入值右移16位,&0FFh, 取右移后的低8个bit,也就是取原来的第3个字节)
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性1 + 段界限2 + 属性2,((%2 >> 8) & 0F00h)取段界限的第16-20位
db (%1 >> 24) & 0FFh ; 段基址3%endmacro
; 共 8 字节;
; 门 在IDT中断描述符表中
; usage: Gate Selector, Offset, DCount, Attr
; Selector: dw
; Offset: dd
; DCount: db
; Attr: db
%macro Gate 4
dw (%2 & 0FFFFh) ; 偏移1
dw %1 ; 选择子
dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性
dw ((%2 >> 16) & 0FFFFh) ; 偏移2%endmacro ; 共 8 字节
%macro name params个数,%macro Descriptor 3定义描述符结构体,输入三个值,第一个为Base段基地址,第二个Limit段界限,第三个 Attr属性,属性表示描述符中除去段基址与段界限以外属性值,比如D,S,TYPE等位,通过宏将这三个输入进行组合,最终形成描述符(8bytes)。第一步取第二个参数段界限取低16位放在描述符的低16位上,作为段界限1,同理最终组合成描述符。