一口气看完45个寄存器,CPU核心技术大揭秘( 四 )


描述符寄存器所谓描述符 , 其实就是一个数据结构 , 用来记录一些信息 , ‘描述’一个东西 。 把很多个描述符排列在一起 , 组成一个表 , 就成了描述符表 。 再使用一个寄存器来指向这个表 , 这个寄存器就是描述符寄存器 。
在x86/x64系列CPU中 , 有三个非常重要的描述符寄存器 , 它们分别存储了三个地址 , 指向了三个非常重要的描述符表 。
gdtr: 全局描述符表寄存器 , 前面提到 , CPU现在使用的是段+分页结合的内存管理方式 , 那系统总共有那些分段呢?这就存储在一个叫全局描述符表(GDT)的表格中 , 并用gdtr寄存器指向这个表 。 这个表中的每一项都描述了一个内存段的信息 。
ldtr: 局部描述符表寄存器 , 这个寄存器和上面的gdtr一样 , 同样指向的是一个段描述符表(LDT) 。 不同的是 , GDT是全局唯一 , LDT是局部使用的 , 可以创建多个 , 随着任务段切换而切换(下文介绍任务寄存器会提到) 。
一口气看完45个寄存器,CPU核心技术大揭秘文章插图
GDT和LDT中的表项 , 就是段描述符 , 描述了一个内存分段的信息 , 其结构如下:
一口气看完45个寄存器,CPU核心技术大揭秘文章插图
一个表项占据8个字节(32位CPU) , 里面存储了一个内存分段的诸多信息:基地址、大小、权限、类型等信息 。
除了这两个段描述符寄存器 , 还有一个非常重要的描述符寄存器:
idtr: 中断描述符表寄存器 , 指向了中断描述符表IDT , 这个表的每一项都是一个中断处理描述符 , 当CPU执行过程中发生了硬中断、异常、软中断时 , 将自动从这个表中定位对应的表项 , 里面记录了发生中断、异常时该去哪里执行处理函数 。
一口气看完45个寄存器,CPU核心技术大揭秘文章插图
IDT中的表项称为Gate , 中文意思为门 , 因为这是应用程序进入内核的主要入口 。 虽然表的名字叫中断描述符表 , 但表中存储的不全是中断描述符 , IDT中的表项存在三种类型 , 对应三种类型的门:
任务门
陷阱门
中断门
一口气看完45个寄存器,CPU核心技术大揭秘文章插图
三种描述符中都存储了处理这个中断/异常/任务时该去哪里处理的地址 。 三种门用途不一 , 其中中断门是真正意义上的中断 , 而像前面提到的调试指令int 3以及老式的系统调用指令int 2e/int 80都属于陷阱门 。 任务门则用的较少 , 要了解任务门 , 先了解下任务寄存器 。
任务寄存器现代操作系统 , 都是支持多任务并发运行的 , x86架构CPU为了顺应时代潮流 , 在硬件层面上提供了专门的机制用来支持多任务的切换 , 这体现在两个方面:
CPU内部设置了一个专用的寄存器——任务寄存器TR , 它指向当前运行的任务 。
定义了描述任务的数据结构TSS , 里面存储了一个任务的上下文(一系列寄存器的值) , 下图是一个32位CPU的TSS结构图:
x86CPU的构想是每一个任务对应一个TSS , 然后由TR寄存器指向当前的任务 , 执行任务切换时 , 修改TR寄存器的指向即可 , 这是硬件层面的多任务切换机制 。
这个构想其实还是很不错的 , 然而现实却打了脸 , 包括Linux和Windows在内的主流操作系统都没有使用这个机制来进行线程切换 , 而是自己使用软件来实现多线程切换 。
所以 , 绝大多数情况下 , TR寄存器都是指向固定的 , 即便线程切换了 , TR寄存器仍然不会变化 。
注意 , 我这里说的的是绝大多数情况 , 而没有说死 。 虽然操作系统不依靠TSS来实现多任务切换 , 但这并不意味着CPU提供的TSS操作系统一点也没有使用 。 还是存在一些特殊情况 , 如一些异常处理会使用到TSS来执行处理 。
下面这张图 , 展示了控制寄存器、描述符寄存器、任务寄存器构成的全貌:
一口气看完45个寄存器,CPU核心技术大揭秘文章插图
模型特定寄存器从80486之后的x86架构CPU , 内部增加了一组新的寄存器 , 统称为MSR寄存器 , 中文直译是模型特定寄存器 , 意思是这些寄存器不像上面列出的寄存器是固定的 , 这些寄存器可能随着不同的版本有所变化 。 这些寄存器主要用来支持一些新的功能 。
随着x86CPU不断更新换代 , MSR寄存器变的越来越多 , 但与此同时 , 有一部分MSR寄存器随着版本迭代 , 慢慢固化下来 , 成为了变化中那部分不变的 , 这部分MSR寄存器 , Intel将其称为Architected MSR , 这部分MSR寄存器 , 在命名上 , 统一加上了IA32的前缀 。