I386 在保护模式下 CPU 具有 4 种特权级(特权级 0、特权级 1、特权级 2 和特权级 3)。而 Linux 只使用了其中的两个,特权级 0 表示内核态,特权级 3 表示用户态,内核运行在内核态,用户应用程序运行在用户态。
异常与中断的发生会引起 CPU 运行状态的改变,比如发生除法错误异常时,CPU 就需要从特权级 3切换到特权级 0。门的目的是在 CPU 希望进行状态切换时提供一种审查机制,保护系统运行。
门有 4 种,即任务门(Task Gate) 中断门、(Interrupt Gate) 陷阱门、(Trap Gate)和调用门(Call Gate),IDT 中包含了前 3 种门的描述符。
任务门的本意是用于任务切换的,在 Linux 中,任务即是进程,但描述一个进程所需的信息远远多于一个任务门所能表达的内容,所以 Linux 并不采用任务门来实现进程切换(门是一个硬件上的概念,事实上,2.0 版内核是使用任务门进行进程切换的)。实际上,内核里只有双重故障异常(中断向量 8)使用到了任务门。中断门和陷阱门的描述符结构基本相同,如图 6.6 所示。
通过 16 位段选择符,可以从全局段描述符表(GDT)中获得异常或中断服务程序所处代码段的段描
述符,再加上 32 位的段偏移量即可得到服务程序的地址。
DPL与CPL
以下参考linux内核修炼第六章 中断初始化的第二阶段内容:
(因为一些 UNIX 变种使用调用门来实现系统调用,为了使应用程序在 Linux和这些 UNIX 变种上可兼容,Linux 相应也在局部描述符 LDT 中设置了几个调用门)
,对于任务门,也只有双重故障异常(中断向量 8)使用到。
Linux 主要使用的是中断门和陷阱门,陷阱门又被细分为陷阱门和系统门。
中断门
使用 set_intr_gate 函数设置,传递给_set_gate 函数的 type 参数值为 DESCTYPE_INT。
DESCTYPE_INT 表示中断门描述符,特权级为 0。因此,对于用户应用程序来说,因为 CPL 为 3,大于中断门的 DPL,所以不可能通过某种途径,比如调用一些汇编指令,穿过中断门去进入中断服务程序。
而对于中断来说,中断门的 DPL 被忽略,总是能通过。
陷阱门
使用 set_trap_gate 函数设置,传递给_set_gate 函数的 type 参数值为 DESCTYPE_TRAP。DESCTYPE_TRAP 表示陷阱门,特权级也为 0。
系统门
使用 set_system_gate 函数设置,与陷阱门不同的是特权级为 3,因此用户应用可以通过调用某些指令,穿过系统门进入中断服务程序。
最为常见的系统门是系统调用(中断向量 0x80),用户应用通过执行“int 0x80”指令陷入内核,穿过系统门执行系统调用服务例程。