X86 和 Linux
x86 有 tr 寄存器,用来索引tss结构,tr 索引的是 GDT中的表项,描述符的类型必须是TSS。
tr寄存器,发生陷入时CPU就是从通过这个指针指向的TSS中拿到SS和ESP的值。
在linux中,每一个CPU对应一个TSS(而不是每个进程对应一个TSS),在同一个CPU上运行的进程共用一个TSS,由于每个进程的内核栈都不同(SS相同,但是ESP 不同),在某个CPU上正在运行的进程才使用这个TSS。在发生进程切换时,A-->B,内核将TSS中的SS和ESP修改成进程B的内核栈对应值,如此类推。所以在LINUX系统中,TSS真正被使用的域就是SS和ESP(确切地讲,是SS0和ESP0,因为内核只用了0级和3级,所以陷入只发生在从3级-->0级,另外有些进程可能还使用了I/O端口访问权限的BITMAP,不过对于本问题来说并不重要),至于那些通用寄存器的域 如TSS->eax, TSS->edx...确实没有被使用。
task_struct 值可用 esp % 8192 内核把 task_struct 和 任务的内核堆栈分配在(逻辑连续的)两页中(1页是4k)。
x86 段描述符 分系统段描述符和数据段描述符;
系统段描述符: 有LDT描述符, TSS描述符,各种门描述符(系统调用,中断,陷阱,任务门)
门描述符:描述控制转移的入口点。
中断门和陷阱门的区别是 中断门会关中断(eflags的if置零)。
Linux的 系统调用(int $0x80) 使用的是 陷阱门。
分页机制只区分两种特权级。特权级0、1和2统称为系统特权级,特权级3称为用户特权级。
页表中的描述中的 U/S 位指定 特权级别。
Linux 中 高端 1G 内存 受 内核保护,是Linux这么设计的,其实可以把任何一页变成特权的。
1.当前特权CPL(Current Privilege Level)
CPL是当前进程的权限级别(Current Privilege Level),是当前正在执行的代码所在的段的特权级,存在于cs寄存器的低两位。
2.描述符特权级DPL(Descriptor Privilege Level)
DPL存储在段描述符中,规定访问该段的权限级别(Descriptor Privilege Level),每个段的DPL固定。
3.请求特权级RPL(Request Privilege Level)
RPL保存在选择子的最低两位。RPL说明的是进程对段访问的请求权限,意思是当前进程想要的请求权限。RPL的值由程序员自己来自由的设置,并不一定RPL>=CPL,但是当RPL<CPL时,实际起作用的就是CPL了,因为访问时的特权检查是判断:EPL=max(RPL,CPL)<=DPL是否成立,所以RPL可以看成是每次访问时的附加限制,RPL=0时附加限制最小,RPL=3时附加限制最大。所以你不要想通过来随便设置一个RPL来访问一个比CPL更内层的段。
对于为甚麽在CPL之外在增加一个RPL的原因:
Intel手册上的解释为:The RPL can be used to insure that privileged code does not access a segment on behalf of an application program unless the program itself has access privileges for that segment.
内核态时(CPL=0), 访问一个段(DPL=0), 如果没有RPL 那么内核态的可以访问所有段的数据,没有保护可能,如果加入RPL,这样可以根据需求来判断是否可以访问数据。