gate、中断、选择子等

133 阅读7分钟

gate

gate的结构

对应的中文术语是”门“。它是一个类似全局描述符的结构,也是64位,8个字节,4个字。具体结构是:

  1. 第0~15位,偏移量的低16位。
  2. 第15~31位,全局描述符的选择子。
  3. 第32~39位,低5位是Param Count,表示函数的最大参数个数;高3位是0,没有被用到。
  4. 第40~47位,低4位是属性中的TYPE;高四位,依次是:S、DPL(占用2位)、P。与全局描述符的对应属性完全一致。
  5. 第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只有小小的疑问。

  1. dw (%3 & 01fh) | ((%4 << 8)&ff00h)。有没有问题?
    1. 第1个问题,比较纠结。顺序没有问题。为啥会纠结?这和数据的排列方式有关系,大小端之类。
    2. &| 的使用正确吗?在这里,用&的作用是获取参数的对应位的数据。两个参数经过处理后用|的作用是获取两个参数的每一位并拼接起来。
  2. dw用得对不对?好解决。查查资料就行。
    1. dw是双字节,即一个字,16个bit。
    2. db是单字节,8个bit。

中断

中断是指操作系统停止正在执行的任务(一般是非内核任务),陷入内核任务。

中断的作用是什么?任务切换需要中断。如果没有中断,一个任务一旦执行起来就不会停止。发生中断后,切换到内核任务,产生了切换任务的契机。

能用时钟中断配合完成任务切换。时钟中断每间隔若干单位时间就发生一次。

与中断相关的概念,还有中断向量表、中断向量、中断处理程序。

中断向量是一个代号,例如0x802000。每个中断向量对应一段代码,这段代码就是中断处理程序。当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结束符。

必须向主、从片的ICW1ICW2ICW3ICW4依次写入数据。一定要按顺序写入。

主片的ICW3和从片的ICW3的结构不一致,但都是8位。主片的ICW3用位图表示第几号引脚连接了从片。从片的ICW3用低3位表示主片发送的数据是不是发送到本片。

例如,主片的第0~7位分别是:00100000,表示第2号引脚接入了从片。当主片向从片发送数据时,会连2一起发送。所有从片接收到信息后,检查本片的低位的值。假如某个从片发现自己的低3位是010(十进制值是3),这个从片就会认为数据是发送给自己的。而其他从片就会丢弃主片发送来的数据。

OCW负责设置屏蔽哪些中断、放行哪些中断。0表示放行,1表示屏蔽。不需要按顺序写入。

选择子

此处的选择子是指描述符的选择子。

选择子的结构

选择子有16位。

  1. 第0~1位,RPL,请求数据特权级。
  2. 第2位,T1,指示选择子是全局描述符的选择子还是局部描述符的选择子。0,全局描述符的选择子;1,局部。
  3. 第3~15位,描述符在GDT或LDT中的索引Index这种描述不是最准确的。最准确的描述应该是,这13位数据是某个描述符相对于第一个描述符的字节偏移量。

只讨论T1是0这种情况。

Index的最大值是MaxIndexMaxIndex是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次方。

实例分析选择子

  1. 选择子是0x8
    1. 转换为二进制形式,0x1000,高12位都是0,省略。左边是高位,右边是低位。
    2. 低3位分别是RPL、T1。
    3. 高13位是01b,即1。是第1个描述符。
  2. 选择子是0x10
    1. 转换为二进制形式,0x10000,高12位都是0,省略。左边是高位,右边是低位。
    2. 低3位分别是RPL、T1。
    3. 高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中的索引,吻合。