|| 版权声明:本文为博主原创文章,未经博主允许不得转载。
一、前言
处理器8086 有 20 根地址线(不清楚8086的童鞋,可以自行百度,这可处理器非常有名,资料也很多),可以寻址 1MB 内存。但是,它内部的寄存器16 位的,无法在程序中访问整个 1MB 内存。所以,它也是第一款支持内存分段模型的处理器。还有, 8086 处理器只有一种工作模式,即实模式。当然,在那时,还没有实模式这一说。
由于 8086 处理器的成功,推动着 Intel 公司不断地研发更新的处理器, 32 位的时代就这样到来了。尽管 8086 是 16 位的处理器,但它也是 32位架构内的一部分。原因在于, 32 位的处理器架构是从 8086 那里发展来的,是基于 8086 的,具有延续性和兼容性。
32位处理器有自己的 32 位工作模式。在本系列文章中,保护模式其实就是32位模式。在这种模式下,可以完全、充分地发挥处理器的性能。同时,在这种模式下,处理器可以使用它全部的 32根地址线,能够访问4GB 内存。
b.实模式的寻址方式与工作机理
其实,8086的段寄存器和IP寄存器都是16位的,如果按照原先的方式,把段寄存器的内容和偏移地址直接相加来形成物理地址的话,也只能得到 16 位的物理地址。麻烦的是,8086却提供了20根地址线。换句话说,它提供的是20位的物理地址。
提供 20 位地址线的原因很简单, 16 位的物理地址只能访问 64KB 的内存,地址范围是0000H~FFFFH,共 65536 个字节。这样的容量,即使是在那个年代, 也显得捉襟见衬。注意,这里提到了一个表示内存容量的单位“ KB”。为了方便,我们通常使用更大的单位来描述内存容量,比如千字节( KB)、兆字节( MB)和吉字节( GB)。
所以,65536个字节就是64KB,而 20 位的物理地址则可以访问多达1MB的内存,地址范围从 00000H到FFFFFH。问题是,16 位的段地址和 16 位的偏移地址相加,只能形成 16 位的物理地址,怎么得到这 20位的物理地址呢?
为了解决这个问题,8086 处理器在形成物理地址时,先将段寄存器的内容左移 4 位(相当于乘以十六进制的10,或者十进制的 16),形成 20 位的段地址,然后再同16位的偏移地址相加,得到20位的物理地址。比如,对于逻辑地址 F000H:052DH,处理器在形成物理地址时,将段地址F000H左移 4 位,变成 F0000H,再加上偏移地址052DH,就形成了20位的物理地址 F052DH。
这样,因为段寄存器是16位的,在段不重叠的情况下,最多可以将1MB的内存分成65536个段,段地址分别是0000H、0001H、0002H、0003H,……,一直到FFFFH。
一个地址有段和偏移两部分组成,物理地址的计算公式为:
物理地址(physicaladdress)=段值(segment) * 16 + 偏移(offset)
其中,segment和offset都是16位的。
在这种模式下,系统计算实际地址的时候是按照对1M求模的方式进行的,这种技术被称为wrap-around。也就是说,当程序员给出超过1M(100000H-10FFEFH)的地址时,因为逻辑上正常,系统并不认为其访问越界而产生异常,而是自动从0开始计算。
三、保护模式
a.起源
最开始的程序寻址是直接的“段:偏移”模式,这样的好处是所见即所得,程序员指定的地址就是物理地址,物理地址对程序员是可见的。这就带来一些问题:1)无法支持多任务2)程序的安全性无法得到保证。
在windows的旧版本中,我们时不时就死机或者蓝屏,其实发生这些问题大部分就是由于内存被破坏引起的。因为在实模式中,将整个物理内存看成分段的区域,程序代码和数据位于不同区域,系统程序和用户程序没有区别对待,而且每一个指针都是指向"实在"的物理地址。这样一来,用户程序的一个指针如果指向了系统程序区域或其他用户程序区域,并改变了值,那么对于这个被修改的系统程序或用户程序,容易造成软件甚至系统崩溃。
而在保护模式下,全部32条地址线有效,可寻址高达4G字节的物理地址空间。扩充的存储器分段管理机制和可选的存储器分页管理机制,不仅为存储器共享和保护提供了硬件支持,而且为实现虚拟存储器提供了硬件支持,支持多任务,能够快速地进行任务切换和保护任务环境,4个特权级和完善的特权检查机制,既能实现资源共享又能保证代码和数据的安全和保密及任务的隔离,支持虚拟8086方式,便于执行8086程序。
保护模式出现的原因是:保护进程地址空间。这样,就产生了一个结果:两种模式下程序的寻址方式发生了变化。
b.保护模式的寻址方式和工作原理
在保护模式下的寻址相对实模式来说是比较复杂的,而且涉及到一些概念问题,下面我们先来简单介绍一下,后期操作系统的系列文章会在有相关知识点的时候进行更为详细的讲解。
其实在保护模式下地址的表示方式与实模式是一样的,都是:段(segment):偏移(offset),不过保护模式下,“段”的概念发生了根本性的改变。实模式下,段值还是可以看作是地址的一部分,比如段值为xxxxh表示以xxxx0h开始的一段内存。而保护模式下,虽然段值仍然由原来的cs、ds等寄存器表示,但此时它仅仅变成了一个索引,这个索引指向了一个数据结构的一个表项,表项中详细定义了段的起始地址、界限、属性等内容。这个数据结构就是全局描述符GDT(也有可能是LDT,这里我们先介绍GDT,LDT其实跟GDT差不多,我们后期在详讲)。
GDT的作用是用来提供段式存储机制,这种机制是段寄存器和GDT中的描述符共同提供的。每个描述符在GDT中占8字节,也就是 2 个双字,或者说是 64 位。下图中,下面是低32位,上面是高32位。
很明显,描述符中指定了 32 位的段起始地址,以及 20 位的段边界。在实模式下,段地址并非真实的物理地址,在计算物理地址时,还要左移 4 位(乘以 16)。和实模式不同,在 32 位保护模式下,段地址是 32 位的线性地址,如果未开启分页功能,该线性地址就是物理地址。
四、总结
回顾上面所讲的内容,我们主要讲解了什么是实模式,什么是保护模式,同时也对这两种模式的寻址方式进行简单介绍,也提到了关于描述符的概念,虽然这里只是简单的介绍了描述符的概念与结构,但这是打入保护模式的关键之一,后期文章中也会进行详细分析,欢迎交流指正。