IDT(Interruption Descriptor Table,中断描述符表)是保护模式下用于存储中断处理程序入口的数据结构。它和GDT、页表等数据结构一样,是由软件设置,并供硬件使用的一个数组。IDT中的每一项都是一个中断门描述符。为了便于管理,处理器为中断和异常都赋予了一个标识号,通常称为中断号,或者中断向量。CPU在接收到中断时,会根据中断向量在中断描述符表中检索对应的描述符,中断向量就是中断描述符表的下标。
中断门描述符之所以多了个门字,是因为x86芯片希望使用Gate这个词来强调特权级变化。调用中断门里的程序有可能发生特权级由低向高的转移。同时,x86提供了以下几种门描述符:任务门描述符、中断门描述符、陷阱门描述符、调用门描述符。
CPU提供任务门的本意是提供一种低特权级调用高特权级代码的机制,但是Linux的设计巧妙地通过软中断避免了使用任务门。Linux系统只使用了中断门这一种机制。所以本书只介绍中断门的结构,如果读者对其他类型的门描述符感兴趣,可以查阅相关资料。
中断门包含中断处理程序所在的段选择子和段内偏移地址,当通过此方式进入中断后,标志寄存器eflags中的IF位会自动置0,表示把中断关闭,避免中断嵌套。中断门只允许保存在IDT中。中断门描述符结构如图2-10所示。
中断门描述符的各个属性域的具体含义与段描述符中的含义是相同的,这里就不再重复介绍了。由表2-1可知,中断门描述符S位的值是0,代表这是一个门描述符,TYPE的值是0xE,代表这是一个i386中断门。
描述符中的选择子和偏移地址一起构成了一个逻辑地址,这个地址指向了中断服务程序入口。CPU会根据中断号在IDT中找到对应的描述符,然后根据描述符中的段选择子和偏移地址,进一步调用中断服务程序。
因为IDT是操作系统设置的,所以它的地址不是固定的,与GDT一样,CPU也需要一个寄存器来获得IDT的起始位置。这个寄存器就是IDTR(中断描述符表寄存器)。和GDTR一样,IDTR也是一个48位的寄存器,它的高32位存储IDT的基地址,低16位存储IDT的大小,单位是字节。每个中断描述符的大小是8B,所以IDT中最多可以存储2 16 /8=8192个描述符。通过lidt指令可以将IDT的信息加载到IDTR寄存器中。
图2-10 中断门描述符结构
i386处理器已经定义的中断和异常如表2-2所示。这就要求操作系统内核所设置的IDT的前32(即至0x20)项,必须用于处理这张表中定义的异常。从48项开始才是用户自定义的中断处理程序。
表2-2 预定义的中断和异常
(续)