Linux 源码阅读的硬件基础
阅读数:125 评论数:0
跳转到新版页面分类
Linux
正文
上图是Intel手册中对标志寄存器的图示,几个重要标志如下:
1、TF(Trap Flag):单步调试标志,为1时,CPU每执行一条指令,都产生一个调试异常
2、IF(Interrupt Flag):中断允许标志,为0时,屏蔽“可屏蔽中断”
3、IOPL(I/o Privilege Level):输入输出特权级,只有当程序的CPL数值小于或等于IOPL时,当前程序才能访问IO地址空间,进行IO操作。
CR系统控制寄存器
1、CR3:保存当前进程的页目录的物理地址,改变CR3的值,代表着在不同的地址空间中切换。因为页目录所在内存是页对齐,所以CR3中只有20位有效。
2、CR2:保存产生缺页中断的线性地址,以便根据页表进行调页操作。
3、CR0:包含了多个标志位,重要的有
(1)PE位:保护模式开关
(2)PG位:分页机制开关
CPU的工作模式
简单来说,CPU允许四种特权级别,每种特权级别支持的指令集有所不同,特权级越高,支持的指令操作也越多。
特权级别及其切换的机制是由CPU保护模式下的分段机制提供的。
在实模式下,分段机制十分简单,此时的段从地位上来说,都是相同的,都运行在Ring 0下,都可以完全操控CPU。
而在保护模式下,分段机制引入了对于一个段的特权级别的描述,以及对代码段进行敏感操作(比如访问其他数据段,切换到其他代码段去执行,进行任务切换等等)时特权级别的检查机制,从而支持了不同的代码在不同的特权级别下运行。
保护模式下的分段机制
段的信息,由简单的16位段寄存器,扩展成64位的复杂的数据结构,称为段描述符。
出于安全及管理上的考虑,段描述符集中存储在系统表中,16位的段寄存器则退化成段选择子,用来保存13位的系统表索引,以及2位的特权级别,和1位的全局/局部标识。
而为了与实模式下用16位的段寄存器标识段的方法兼容,保护模式采取了影子寄存器的方式。
系统表分为两种:全局表和局部表,全局表有GDT和IDT两张,而局部表为LDT,每个任务有一张。每个任务还有一个TSS段,用来保存任务的上下文信息。
分段机制提供了三个方面的保护和限制:
- 段长限制
- 段类型限制
- 特权级别限制
段描述符分为三种类型:
- 存储段, 描述普通的代码、数据和堆栈
- 系统段, 描述LDT及TSS段,只存在GDT中,其中TSS并不是一个段,而是保护任务上下文信息的一个大型的数据结构
- 门描述符, 描述的不是一个段,而是一段代码的入口,以及让程序能够顺利地跳转到这段代码执行所必备的特权级别方面的设置
门描述符又分为三种类型:
- 调用门, 用于在同一任务内部,由低特权级别的代码,调用执行高特权级别的代码
- 任务门, 用于任务切换
- 中断/陷阱门, 用于提供中断及异常处理程序的入口点
所谓的各种门,可以理解为一个带有特权级别的程序指针。
指向“中断/陷阱”的服务程序,或者TSS结构体。
由于有了特权级别的限制,这些“程序/数据”不会被普通程序随便地调用,因此起到了保护的作用。
门描述符保存在全局的IDT表中,IDT表里的项目(即各种门描述符)包含了一个段选择子和一个段内偏移(任务门除外,任务门指向TSS数据结构,不需要段内偏移)。然后再根据段选择子到GDT表中找到对应的代码段,再加上段内偏移,最终找到跳转地址。
中断门与陷阱门的唯一区别:中断门会设置IF标志,防止中断嵌套;而陷阱门不会。
特权级别的检查
当前任务的特权级别CPL,由当前代码段CS段选择子指向的LDT中段描述符中的DPL域决定。
而GDT表中的段描述符中的DPL,则表明要访问或者跳转到该段时需要提供的特权级别。
当构造一个段选择子以访问或者跳转到一个段时,CPU会检查:
- 段选择子的RPL <= 其指向的段描述符中DPL (<=代表数值上不大于,即特权级别上不低于)
- CPL <= 段选择子指向的段描述符中的DPL
这样就保证了,处于Ring 3的用户态程序无法访问或者跳转到Ring 0中的内核态段。