实模式与保护模式

实模式

早期CPU(如8086)是16位的CPU,寄存器是16位的,数据总线是16位的,也就是说在8086内部,能够一次性处理与传输的数据最长为16位比特,那么它的寻址能力仅为216=64 KB。但是地址总线却是20位的,即其寻址能力为220=1 MB。

为了解决寻址能力不匹配这一问题,引入了地址加法器,以如下公式进行地址的换算:内存地址 = (段地址 << 4) + 段内偏移地址

由于寄存器为16位,则其中存的段地址/段内偏移地址为16位,段地址向左偏移4位即得20位的地址,再加上段内偏移即可得到内存中实际的物理地址。

这样的寻址方式是很直接的,相当于物理地址直接暴露在程序员面前,程序员可以随意的修改内存各处的内容,有着较大的安全隐患。或许这就是为什么叫做实模式吧。

另外,还有一点值得注意:段地址+段内偏移地址这样的寻址方式对于16位CPU而言是可以“越界”的。对于16位而言,最大地址即为FFFF,因此可取得内存地址:

若想访问到10FFEF,需要21根地址总线,但是实际地址总线仅有20根,内存地址实际最大仅为100000 < 10FFEF,越界了。但是系统并不认为其访问越界而抛出异常,而是将访问大于等于100000的地址均对100000取模,因此此时访问到的就是较小的内存地址了。

再后来,CPU发展到了80286,此时地址总线已有24根,那么10FFEF就是可以访问到的了,但是在实模式下,为了向下兼容,系统表现的行为又应同8086一样,即仿佛“只有20根地址总线”。为了能够自由选择实模式下寻址能力的大小,便出现了A20 Gate。

A20 Gate

A20 Gate是第21根地址总线,它有一个开关,对于实模式而言

  • 开关打开时,这根地址总线可用,程序员可以访问到100000~10FFEF的地址
  • 开关关闭时,这根地址总线不可用,程序员不可以访问到100000~10FFEF的地址

因此在实模式下要想访问高端内存区,这个开关必须打开。在保护模式下,如果A20关闭,那么系统只能访问奇数兆的内存,即只能访问0~1M、2~3M……,所以在保护模式下,这个开关一般也会打开。

保护模式

在后续更高系列的CPU中,即使A20 Gate被打开,在实模式下所能够访问的内存最大也只能为10FFEF,而内存的寻址能力远不止如此。为了能够访问更大的地址,则必须进入保护模式。

虽然后续一般寄存器和地址总线都有着相同的位数,但系统并没有使用寄存器直接指定内存地址,而是沿用了段地址+段内偏移地址的寻址方式。段值存入段寄存器,而该值作为索引,用于在全局描述符表(GDT)中寻找到对应的一个表项(段描述符),该表项中含有段地址、段大小、访问控制等信息,得到其中的段地址后再加上合法的段内偏移,即可访问到对应的物理地址。

GDT条目结构如下所示:

图源自https://en.wikipedia.org/wiki/Global_Descriptor_Table

综上可知,在保护模式下,物理地址并不是直接暴露在程序员面前了,寻址有了更多的检查步骤,这是属于虚拟内存的范畴了,在此就不再深入。

参考


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!