gate
gate的结构
对应的中文术语是”门“。它是一个类似全局描述符的结构,也是64位,8个字节,4个字。具体结构是:
- 第0~15位,偏移量的低16位。
- 第15~31位,全局描述符的选择子。
- 第32~39位,低5位是Param Count,表示函数的最大参数个数;高3位是0,没有被用到。
- 第40~47位,低4位是属性中的TYPE;高四位,依次是:S、DPL(占用2位)、P。与全局描述符的对应属性完全一致。
- 第48~63位,偏移量的高16位。
代码
C语言
// 32位CPU
struct gate{
unsigned short offset_low;
unsigned short selector;
unsigned char paramCount;
unsigned char attribute;
unsigned short offset_high;
};
nasm
; Gate offset,selector,paramCount,attribute
%macro Gate 4
dw %1 & 0ffffh
dw %2
dw (%3 & 01fh) | ((%4 << 8)&ff00h)
dw (%1 >> 16) & ffffh
%endmacro
因为对全局描述符的nasm代码理解得比较透彻,对gate的nasm只有小小的疑问。
dw (%3 & 01fh) | ((%4 << 8)&ff00h)
。有没有问题?- 第1个问题,比较纠结。顺序没有问题。为啥会纠结?这和数据的排列方式有关系,大小端之类。
- 对
&
和|
的使用正确吗?在这里,用&
的作用是获取参数的对应位的数据。两个参数经过处理后用|
的作用是获取两个参数的每一位并拼接起来。
dw
用得对不对?好解决。查查资料就行。dw
是双字节,即一个字,16个bit。db
是单字节,8个bit。
中断
中断是指操作系统停止正在执行的任务(一般是非内核任务),陷入内核任务。
中断的作用是什么?任务切换需要中断。如果没有中断,一个任务一旦执行起来就不会停止。发生中断后,切换到内核任务,产生了切换任务的契机。
能用时钟中断配合完成任务切换。时钟中断每间隔若干单位时间就发生一次。
与中断相关的概念,还有中断向量表、中断向量、中断处理程序。
中断向量是一个代号,例如0x80
、2000
。每个中断向量对应一段代码,这段代码就是中断处理程序。当CPU接收到中断向量2000
时,它会执行2000
对应的那段代码(比如,打印一个A
字符)。中断向量组成中断向量表。
外部中断是电脑的外部设备发出的。有哪些外部设备呢?比如,键盘、鼠标、摄像头等。
电脑的外部设备非常多,如果每个外部设备都直接连接到CPU上,CPU需要留出非常多接口,而且数量不确定,并且要和外部设备直接交互数据。速度慢,而且让CPU变得臃肿。所以,使用一个中断代理器来管理中断。它从外部设备接收中断向量,发送给CPU,再从CPU获取中断处理结果并返回给对应的外部设备。
这个中断处理器就是8259A
。它是一个硬件,可编程的。
8259A
一个8259A
有8个引脚(接线口,可以用路由器的网线接口类比),每个引脚能接入一个外部设备。如此,一个8259A
只能连接8个外部设备。为了多接收外部设备的中断信号,可以采用“级联”的方式。
所谓“级联”,是指把第2个8259A
连接到第一个8259A
的其中一个引脚上。第1个8259A
是主片,第2个是从片。用这种方式,能接收 7 + 8 = 15 个外部设备的中断向量。
8259A
的运行过程比较繁琐,应该不重要吧。作者只想掌握有限的知识、能用它实现中断就满足了。
怎么对8259A
编程?它有两类端口,一种是ICW
,初始化命令字;另一种是OCW
,操作操作命令字。
ICW
负责设置8259A
是不是级联、用主片的几号引脚连接从片、初始向量号是多少、会不会自动发送EO
结束符。
必须向主、从片的ICW1
、ICW2
、ICW3
、ICW4
依次写入数据。一定要按顺序写入。
主片的ICW3
和从片的ICW3
的结构不一致,但都是8位。主片的ICW3
用位图表示第几号引脚连接了从片。从片的ICW3
用低3位表示主片发送的数据是不是发送到本片。
例如,主片的第0~7位分别是:00100000
,表示第2号引脚接入了从片。当主片向从片发送数据时,会连2
一起发送。所有从片接收到信息后,检查本片的低位的值。假如某个从片发现自己的低3位是010
(十进制值是3),这个从片就会认为数据是发送给自己的。而其他从片就会丢弃主片发送来的数据。
OCW
负责设置屏蔽哪些中断、放行哪些中断。0
表示放行,1表示屏蔽。不需要按顺序写入。
选择子
此处的选择子是指描述符的选择子。
选择子的结构
选择子有16位。
- 第0~1位,RPL,请求数据特权级。
- 第2位,T1,指示选择子是全局描述符的选择子还是局部描述符的选择子。0,全局描述符的选择子;1,局部。
- 第3~15位,描述符在GDT或LDT中的索引
Index
。这种描述不是最准确的。最准确的描述应该是,这13位数据是某个描述符相对于第一个描述符的字节偏移量。
只讨论T1是0这种情况。
Index
的最大值是MaxIndex
?MaxIndex
是2的13次方-1。很纠结这种小细节。
教室里有8个同学,依次给这个8个同学编号:1、2、3、......、8。那么,一共有多少个同学呢?一定不是8-1
而是8-1+1
,要把第1个同学包括在内。
13个bit能表示的最大值是2的13次方-1。13个bit能表示的数值的数量是:最大值-第1个值+1
= 2的13次方-1-0+1
= 2的13次方
。
按照选择子的结构(13个bit表示描述符在GDT中的索引),GDT中的描述符的数量是2的13次方。因为,13个bit所表示的数字中的每一个都是一个描述符的索引值。有多少个数字就有多少个描述符。
第一个描述符的选择子是0x0
,第二个描述符的选择子是0x8
,第三个描述符的索引是0x10
。
乍一看,会把0x8
误解为描述符的索引,进而会认为GDT中描述符的最大数量是2的13次方字节/8
。
不是这样的。严格按照选择子的结构来理解。选择子的高13位是描述符在GDT中的索引,索引编号从0一直到2的13次方。
实例分析选择子
- 选择子是
0x8
。- 转换为二进制形式,
0x1000
,高12位都是0,省略。左边是高位,右边是低位。 - 低3位分别是RPL、T1。
- 高13位是
01b
,即1。是第1个描述符。
- 转换为二进制形式,
- 选择子是
0x10
。- 转换为二进制形式,
0x10000
,高12位都是0,省略。左边是高位,右边是低位。 - 低3位分别是RPL、T1。
- 高13位是
010b
,即2。是第2个描述符。
- 转换为二进制形式,
lgdt
lgdt
是一个寄存器,专门存储GDT的内存地址。它的第0~15位是GDT的长度-1。GDT的最大长度M是2的16次方,单位是字节。一个描述符的长度是8字节,GDT中的最大描述符数量 = M/8 = 2的16 次方/2的3次方 = 2的13次方。
GDT中最多有2的13次方个描述符,这和选择子的高13位是描述符在GDT中的索引,吻合。