操作系统程序员必须了解的四类寄存器
供操作系统程序员使用的寄存器可以分为下面这么几类:
- EFLAGS
- Memory-Management Registers
- Control Registers
- Debug Registers
接下来我们分别介绍一下这几类寄存器。
EFLAGS
操作系统在很多地方都要关闭中断、打开中断,实现这一点就要用到EFLAGS寄存器,当然EFLAGS寄存器的作用不只是这一点。
下图是EFLAGS寄存器的所有位,其中灰色代表保留为,不可使用。图下方的表格会详细介绍每一位的作用,比较重要的位被标为黑体。
简称 | 中文名称 | 标志类型 | 具体作用 |
---|---|---|---|
ID | 识别标志 | 系统标志 | 如果ID为能够被设置,表示处理器支持CPUID命令。 |
VIP | 虚拟未决中断标志 | 系统标志 | 如果有中断挂起,VIP设为1。 |
VIF | 虚拟中断标志 | 系统标志 | IF位的虚拟镜像。 |
AC | 对齐检查标志 | 系统标志 | 如果对内存引用的对齐检查完成,AC设为1。 |
VM | 虚拟8086模式 | 系统标志 | VM为1是表示允许虚拟8086模式(既实模式)。 |
RF | 恢复标志 | 系统标志 | 对调试异常做出反应。具体说就是暂时关闭调试异常(_debug exception_),这样指令可以在出现调试异常后重新执行而不会马上引起另一个调试异常。 |
NT | 任务嵌套标志 | 系统标志 | 用于控制中断链,如果当前程序或者任务与下一个程序或任务相关联,NT设为1。NT位的设置会影响到IRET 指令。 |
IOPL | I/O特权级标志 | 系统标志 | 表示当前程序或者任务的I/O特权级。只有当前特权级(Current Privilege Level)$\leq$I/O特权级的时候才能够访问该I/O地址空间。 |
OF | 溢出标记 | 状态标志 | 如果运算结果溢出,OF设为1,否则设为0。 |
DF | 方向标志 | 控制标志 | DF为1时字符串操作会从高地址向低地址处理,否则相反。汇编中的STD 命令用来讲DF设为1,CLD 命令将DF设为0。 |
IF | 中断标志 | 系统标志 | IF为1时表示允许中断。 |
TF | 陷阱标志 | 系统标志 | TF为1时表示允许单步调试。单步调试模式下CPU会在执行每个指令后自动产生抛出一个异常,这样就能在执行每条指令后观察程序状态。 |
SF | 符号位 | 状态标志 | 如果计算结果是负数,SF设为1,否则设为0。 |
ZF | 零标记 | 状态标志 | 如果计算结果是0,ZF设为1,否则设为0。 |
AF | 辅助进位标记 | 状态标志 | 如果计算时低效半字节(low nibble),也就是最低4位发生了进位或者借位,AF设为1,否则设为0。主要用来辅助BCD码(二进制编码的十进制)的算术计算。 |
PF | 奇偶位 | 状态标志 | 计算结果转化为二进制数,如果最低8位(least significant byte)中1的个数是偶数,PF设为1,否则设为0。 |
CF | 进位标记 | 状态标志 | 如果上次算术运算有进位或者借位,CF设为1,否者设为0。 |
内存管理寄存器——Memory-Management Registers
80386处理器中四个寄存器用于定位控制段内存管理的数据结构,它们是:
全局描述符表寄存器 Global Descriptor Table Register
指向全局描述符表(GDT),GDT中没8bytes代表一个描述符,描述符可以是段描述符、TSS(任务状态段)描述符、门描述符(局部描述符表描述符)。
段描述符如下图:TSS描述符指向TSS,门描述符指向LDT。
局部描述符表寄存器 Local Descriptor Table Register
指向局部描述符表(LDT),和GDT不同,LDT只能存放段描述符。中断描述符表寄存器 Interrupt Descriptor Table Register
指向中断描述符表(IDT),中断描述符表中记录着中断处理程序的入口。任务寄存器 Task Register
指向处理器定义当前任务所需信息。
控制寄存器——Control Registers
80386处理器中的控制寄存器有_CR0_、_CR2_、CR3(更新的处理器中有更多的控制寄存器) 。这些寄存器只能通过汇编指令MOV
来读写,具体点就是将通用寄存器中的值存储到控制寄存器,或者从控制寄存器中读取值放在通用寄存器。下面我们详细介绍一下这三个寄存器的作用。
CR0控制寄存器:
CR0控制寄存器包含系统控制标志,这些标志可以用来控制整个系统的状态。我们分别说一下这些控制标志简称 全称 作用 PG Paging 指明处理器是否使用页表将线性地址翻译为物理地址。PG为1是处理器使用分页。 ET Extension Type ET指明系统中存在的协处理器的类型。 TS Task Switched 每次任务切换处理器都会把TS置1,并且在执行协处理器指令时检查TS位。 EM Emulation EM位指明是否模拟协处理器功能。如果EM为1,执行 ESC
指令时会产生7号异常,让异常处理程序有机会模拟ESC
指令。MP Monitor Coprocessor 控制 WAIT
指令,如果MP为1,当执行WAIT
指令时CPU会检查TS位,如果发现TS位是1,则抛出7号异常。PE Protection Enable PE位置1,处理器会开始执行保护模式。置0会返回实模式。 CR1控制寄存器(保留,不可用)
CR2控制寄存器:
当CR0中的PG位置1时,CR2用于处理页错误,处理器将触发页错误的线性地址存入CR2寄存器。CR3控制寄存器:
当CR0中的PG位置1时,CR3寄存器用于存放当前任务页表目录(Page Table Directory)的入口。CR3对于环境切换非常重要。
调试寄存器——Debug Register
调试寄存器让80386处理器能够在不改变程序代码的情况下实现指令断点等高级调试功能。80386处理器一共有8个调试处理器,如图:
和控制寄存器类似,用MOV
指令操作这些寄存器,另外只有特权级为0是才能操作,其他特权级试图操作为引起异常。
DR0~3——调试地址寄存器:
用于存放与断点条件相应的线性地址。
这些调试地址寄存器不管是否使用分页都有效,如果使用分页,寄存器中的线性地址会被转化为物理地址,否者这些线性地址会直接被当作物理地址。
需要注意的是,如果使用分页,不同的任务可能有不同的地址映射。如果任务之间的地址映射不同,那么调试寄存器中的地址可能和具体任务有关。DR4~5——保留不用的寄存器
DR6——调试状态寄存器
调试状态寄存器帮助调试人员判断发生了哪些调试条件。
如果DR0-3指明的调试条件发生,在进入调试异常处理程序前DR6中相应的的B0-3被置1。
DR6中的BT位和TSS(任务状态段)中的T-bit配合,当发生任务切换并且新的TSS中的T-bit为1,那么在进入调试异常处理程序前BT会被置1。
DR6中的BS位和EFLAGS寄存器中的TF位配合,如果由于单步执行异常进入异常处理程序,BS会被置1。单步执行陷阱是最高优先级的调试异常,所以当BS为1时,所有的其他调试状态位可能也会被置1。
如果下一条指令会读写八个调试寄存器中的任意一个,BD位会被置1。
对于DR6有一点需要注意,处理器不会清零DR6,所以调试异常处理程序在返回前应该将DR6清零,以避免混乱。DR7——调试控制寄存器
调试控制寄存器用于帮助定义调试条件,选择性的开关这些条件。
DR7中的R/W0,R/W1,R/W2,R/W3分别用于指明DR0,DR1,DR2,DR3在什么情况下触发断点。R/W0-3都包含2bit,可能的情况有:- 00——在指令执行时中断
- 01——在写数据时中断
- 10——未定义
- 11——在数据读写(不包括取指令)时中断
当RW0-3为01或者11,DR7中对应的LEN用于指明数据的大小。RW为00时对应的LEN也必须为00。下面是LEN可能的值及对应含义:
00——1byte
01——2byte
10——未定义
11——4byte
DR7的低8位(L0-3,G0-3)用于是否开启断电条件,是全局(G)还是本地(L)。L0-3位任务切换时会被处理器自动重置,G0-3在任务切换时则不会被重置。
DR7中还有LE和GE两位,用于控制处理器降低执行速度,使得有时间将断点报给触发断点的指令。同样的LE在任务切换时会被重置,GE不会。