关于实模式与保护模式

本文最后更新于:2022年6月8日 晚上

首先到了80386时代,CPU有了四种运行模式,即实模式、保护模式、虚拟8086模式和SMM模式

其中实模式指的是8086的运行模式,不过这个是后来提出的概念,在8086时代只有当时的运行模式。

以下转自:https://zhuanlan.zhihu.com/p/42309472

实模式和保护模式都是 CPU 的工作模式,而 CPU 的工作模式是指 CPU 的寻址方式、寄存器大小等用来反应 CPU 在该环境下如何工作的概念。

实模式工作原理

实模式出现于早期 8088CPU 时期。当时由于 CPU 的性能有限,一共只有 20 位地址线(所以地址空间只有 1MB),以及 8 个 16 位的通用寄存器,以及 4 个 16 位的段寄存器。所以为了能够通过这些 16 位的寄存器去构成 20 位的主存地址,必须采取一种特殊的方式。当某个指令想要访问某个内存地址时,它通常需要用下面的这种格式来表示:

  段基址:段偏移量

  其中第一个字段是段基址,它的值是由段寄存器提供的 (一般来说,段寄存器有 6 种,分别为 cs, ds, ss, es, fs, gs,这几种段寄存器都有自己的特殊意义,这里不做介绍)。

  第二字段是段内偏移量,代表你要访问的这个内存地址距离这个段基址的偏移。它的值就是由通用寄存器来提供的,所以也是 16 位。那么两个 16 位的值如何组合成一个 20 位的地址呢?CPU 采用的方式是把段寄存器所提供的段基址先向左移 4 位。这样就变成了一个 20 位的值,然后再与段偏移量相加。

即:
$$
物理地址 = 段基址 <<4 + 段内偏移
$$
  所以假设段寄存器中的值是 0xff00,段偏移量为 0x0110。则这个地址对应的真实物理地址是 0xff00<<4 + 0x0110 = 0xff110。

由上面的介绍可见,实模式的 “实” 更多地体现在其地址是真实的物理地址。

保护模式工作原理

随着 CPU 的发展,CPU 的地址线的个数也从原来的 20 根变为现在的 32 根,所以可以访问的内存空间也从 1MB 变为现在 4GB,寄存器的位数也变为 32 位。所以实模式下的内存地址计算方式就已经不再适合了。所以就引入了现在的保护模式,实现更大空间的,更灵活也更安全的内存访问。

在保护模式下,CPU 的 32 条地址线全部有效,可寻址高达 4G 字节的物理地址空间;

但是我们的内存寻址方式还是得兼容老办法 (这也是没办法的,有时候是为了方便,有时候是一种无奈),即(段基址:段偏移量) 的表示方式。

当然此时 CPU 中的通用寄存器都要换成 32 位寄存器 (除了段寄存器,原因后面再说) 来保证寄存器能访问所有的 4GB 空间。

我们的偏移值和实模式下是一样的,就是变成了 32 位而已,而段值仍旧是存放在原来 16 位的段寄存器中,但是这些段寄存器存放的却不再是段基址了,毕竟之前说过实模式下寻址方式不安全,我们在保护模式下需要加一些限制,而这些限制可不是一个寄存器能够容纳的,于是我们把这些关于内存段的限制信息放在一个叫做全局描述符表 (GDT) 的结构里。全局描述符表中含有一个个表项,每一个表项称为段描述符。而段寄存器在保护模式下存放的便是相当于一个数组索引的东西,通过这个索引,可以找到对应的表项。段描述符存放了段基址、段界限、内存段类型属性 (比如是数据段还是代码段, 注意一个段描述符只能用来定义一个内存段) 等许多属性, 具体信息见下图:

其中,段界限表示段边界的扩张最值,即最大扩展多少或最小扩展多少,用 20 位来表示,它的单位可以是字节,也可以是 4KB,这是由 G 位决定的 (G 为 1 时表示单位为 4KB)。

$$
实际段界限边界值 =(描述符中的段界限 + 1)*(段界限的单位大小 (即字节或 4KB))-1
$$
如果偏移地址超过了段界限,CPU 会抛出异常。

全局描述符表位于内存中,需要用专门的寄存器指向它后, CPU 才知道它在哪里。这个专门的寄存器便是 GDTR(一个 48 位的寄存器), 专门用来存储 GDT 的内存地址及大小。

最后我们再介绍一下一个新的概念:段的选择子。段寄存器 CS、 DS、 ES、 FS、 GS、 SS,在实模式下时,段中存储的是段基地址,即内存段的起始地址。 而在保护模式下时,由于段基址已经存入了段描述符中,所以段寄存器中再存放段基址是没有意义的,在段寄存器中存入的是一个叫作选择子的东西。选择子 “基本上” 是个索引值,虽然它还有其他内容,不过作为初学者暂时忽略也没太大关系。由于段寄存器是 16 位,所以选择子也是 16 位,在其低 2 位即第 0~1 位, 用来存储 RPL,即请求特权级(有兴趣的可以了解一下,不想了解的忽略即可,跟用户态和内核态相关的),可以表示 0、 1、 2、 3 四种特权级。在选择子的第 2 位是 TI 位,即 Table Indicator,用来指示选择子是在 GDT 中,还是 LDT 中索引描述符。 TI 为 0 表示在 GDT 中索引描述符, TI 为 1 表示在 LDT 中索引描述符。选择子的高 13 位,即第 3~15 位是 描述符的索引值,用此值在 GDT 中索引描述符。前面说过 GDT 相当于一个描述符数组,所以此选择子中的索引值就是 GDT 中的下标。选择子结构如下:

此外, 扩充的存储器分段管理机制和可选的存储器分页管理机制,不仅为存储器共享和保护提供了硬件支持,而且为实现虚拟存储器提供了硬件支持; 支持多任务,能够快速地进行任务切换 (switch) 和保护任务环境(context); 4 个特权级和完善的特权检查机制,既能实现资源共享又能保证代码和数据的安全和保密及任务的隔离; 支持虚拟 8086 方式,便于执行 8086 程序。


关于实模式与保护模式
https://www.glj0.top/posts/4bb7b00b/
作者
gong lj
发布于
2022年3月11日
更新于
2022年6月8日
许可协议