一、用户态与内核态
-
Linux 把内存主要分为 4 个段,分别是内核代码段、内核数据段、用户代码段、用户数据段。
-
内核两个段特权级都为最高级 0,用户两个段特权级都为最低级 3。内核代码段可以访问内核数据段,但不能访问用户数据段和用户代码段,同样地,用户代码段可以访问用户数据段,但不能访问内核数据段或内核代码段。
-
当前进程运行的代码若属于内核代码段,则称当前进程处于内核态,若属于用户代码段,则称当前进程处于用户态。用户代码段和内核代码段的代码分别运行在用户栈上和内核栈上。
-
处于用户态的进程若想要切换到内核态,便要依靠中断。
二、中断
- CPU 每次执行完一条指令后,总会先检查有无中断请求,无则执行下一条指令,有则在总线上读取中断的标识码即中断向量。
- 内存中存放着一个中断描述符表(Interrupt Descriptor Table,简称 IDT,也可以叫做中断向量表),表里有许多个中断描述符,所以要在中断描述符表中找到特定一项中断描述符需要一个下标,这个下标就是上文提及的中断向量,就像访问数组中的特定元素一样。每个中断描述符的内容中有 3 项信息比较重要——该描述符的特权级,中断服务函数的入口地址,中断服务函数所在段的特权级。在 Linux 中,所有的中断服务函数都放在内核代码段,故中断服务函数所在段的特权级都为 0。
- 那 CPU 通过什么手段 IDT 在内存中的地址呢?答案是寄存器。CPU 有个寄存器叫 IDTR,用于存放 IDT 的首地址和长度,就像 C++
string
类的实现一样,有一个char*
指针指向字符串首地址和一个整形变量记录字符串长度。 - 设当前进程的代码段特权级为 C P L CPL CPL,通过中断向量找到的中断描述符的特权级为 D P L d DPL_{d} DPLd,中断服务函数所在段的特权级为 D P L s DPL_{s} DPLs</