所谓的硬件上的分段、分页,是针对CPU在实模式下,即操作系统尚未加载启动之前所采用的内存寻址方式。
而软件上的分段、分页,则是CPU在保护模式下,即操作系统启动后所采用的内存寻址方式。
在这里再引出”实模式“和”保护模式“的概念:
实模式是 Intel公司80286及以后的x86(80386,80486和80586等)兼容处理器(CPU)的一种操作模式。实模式被特殊定义为20位地址内存可访问空间上,这就意味着它的容量是2的20次幂(1M)的可访问内存空间(物理内存和BIOS-ROM)。软件可通过这些地址直接访问BIOS程序和外围硬件。
实模式下处理器没有硬件级的内存保护概念和多道任务的工作模式。
但是为了向下兼容,所以80286及以后的 x86系列兼容处理器仍然是开机启动时工作在实模式下。80186和早期的处理器仅有一种操作模式,就是后来我们所定义的实模式。实模式虽然能访问到1M的地址空间,但是由于BIOS的映射作用(即BIOS占用了部分空间地址资源),真正能使用的物理内存空间(内存条),也就是在640k到924k之间。实模式工作原理:
1)对于8086/8088来说,计算实际地址是用绝对地址对1M取模。
8086/8088的地址线:20根,可物理寻址的内存范围是:2^20个字节,即1M字节空间。但由于8086/8088所使用的寄存器都是16位。能够表示的地址范围只有0~64K,要小于1M地址空间。所以为了在8086/8088下能够访问1M内存,Intel采取了分段寻址模式:16位段基地址:16位偏移地址。其绝对地址计算方法为:16位基地址左移4位+16位偏移地址=20位地址 比如: CS=1000H IP=FFFFH 那么绝对地址就为: 10000H + 0FFFFH = 1FFFFH 地址单元 。通过这种方法来实现使用 16位寄存器访问1M的地址空间,这种技术是处理器内部实现的。
通过上述分段技术模式,能够表示的最大内存为:FFFFh:FFFFh=FFFF0h+FFFFh=10FFEFh=1M+64K-16Bytes(1M多余出来的部分被称做高端内存区HMA:High Memory Area)。但8086/8088只有20位地址线,只能够访问1M地址范围的数据,所以如果访问100000h~10FFEFh之间的内存(大于1M空间),则必须有第21根地址线来参与寻址(8086/8088没有)。因此,当程序员给出超过1M(100000H-10FFEFH)的地址时,因为逻辑上正常,系统并不认为其访问越界而产生异常,而是自动从0开始计算,也就是说系统计算实际地址的时候是按照对1M求模的方式进行的。这种技术被称为wrap-around。
2)对于80286或以上的CPU通过A20 GATE来控制A20地址线。技术发展到了80286,虽然系统的地址总线由原来的20根发展为24根,这样能够访问的内存可以达到2^24=16M,但是Intel在设计80286时提出的目标是向下兼容,所以在实模式下,系统所表现的行为应该和8086/8088所表现的完全一样,也就是说,在实模式下,80386以及后续系列应该和8086/8088完全兼容仍然使用A20地址线。所以说80286芯片存在一个BUG:它开设A24地址线。如果程序员访问100000H-10FFEFH之间的内存,系统将实际访问这块内存(没有wrap-around技术),而不是象8086/8088一样从0开始。为了解决上述兼容性问题,IBM使用键盘控制器上剩余的一些输出线来管理第21根地址线(从0开始数是第20根)的有效性,被称为A20 Gate:
1> 如果A20 Gate被打开,则当程序员给出100000H-10FFEFH之间的地址的时候,系统将真正访问这块内存区域;
2> 如果A20 Gate被禁止,则当程序员给出100000H-10FFEFH之间的地址的时候,系统仍然使用8086/8088的方式即取模方式(8086仿真)。绝大多数 IBM PC兼容机默认的 A20 Gate是被禁止的。现在许多新型PC上存在直接通过 BIOS功能调用来控制 A20 Gate的功能。上面所述的内存访问模式都是实模式,在80286以及更高系列的 PC中,即使A20 Gate被打开,在实模式下所能够访问的内存最大也只能为10FFEFH,尽管它们的地址总线所能够访问的能力都大大超过这个限制。为了能够访问10FFEFH以上的内存,则必须进入保护模式。
保护模式: 经常缩写为 p-mode,在 Intel iAPX 286程序员参考手册中( iAPX 286是Intel 80286的另一种叫法)它又被称作为虚拟地址保护模式。尽管在Intel 80286手册中已经提出了虚地址保护模式,但实际上它只是一个指引,真正的32位地址出现在Intel 80386上。保护模式本身是80286及以后兼容处理器序列之后产成的一种操作模式,它具有许多特性设计为提高系统的多道任务和系统的稳定性。例如内存的保护,分页机制和硬件虚拟存储的支持。现代多数的x86处理器操作系统都运行在保护模式下,包括Linux, Free BSD,和Windows3.0(它也运行在实模式下,为了和 Windows 2.x应用程序兼容)及以后的版本。
实模式和保护模式的区别: 从表面上看,保护模式和实模式并没有太大的区别,二者都使用了内存段、中断和设备驱动来处理硬件,但二者有很多不同之处。我们知道,在实模式中内存被划分成段,每个段的大小为 64KB,而这样的段地址可以用 16 位来表示。内存段的处理是通过和段寄存器相关联的内部机制来处理的,这些段寄存器( CS 、 DS 、 SS 和 ES )的内容形成了物理地址的一部分。具体来说,最终的物理地址是由 16 位的段地址和 16 位的段内偏移地址组成的。用公式表示为:物理地址 = 左移 4 位的段地址 + 偏移地址。
===================下面的不太懂
在保护模式下,段是通过一系列被称之为 “ 描述符表 ” 的表所定义的。段寄存器存储的是指向这些表的指针。用于定义内存段的表有两种:全局描述符表 (GDT) 和局部描述符表 (LDT) 。 GDT 是一个段描述符数组,其中包含所有应用程序都可以使用的基本描述符。在实模式中,段长是固定的 ( 为 64KB) ,而在保护模式中,段长是可变的,其最大可达 4GB 。 LDT 也是段描述符的一个数组。与 GDT 不同, LDT 是一个段,其中存放的是局部的、不需要全局共享的段描述符。每一个操作系统都必须定义一个 GDT ,而每一个正在运行的任务都会有一个相应的 LDT。当段寄存器被加载的时候,段基地址就会从相应的表入口获得。描述符的内容会被存储在一个程序员不可见的影像寄存器 (shadow register) 之中,以便下一次同一个段可以使用该信息而不用每次都到表中提取。物理地址由 16 位或者 32 位的偏移加上影像寄存器中的基址组成。
计算机刚启动的时候,CPU首先以实模式的方式工作,直到启动操作系统后才会切换到保护模式下工作;从8086到80386,虽然位数从16位扩展成了32位,但CPU的体系结构却发生了质的改变。其中,寻址方式从实模式到保护模式的转变对CPU的计算能力起到了至关重要的作用。80386的后续型号(如80486,奔腾,奔腾4等)虽然计算速度在飞速提高,但最核心的体系结构基本上没有多大变化。所以人们把80386及其后续型号统称为“x86”或“i386”。x86体系的处理器刚开始时只有20根地址线,寻址寄存器是16位。可以访问64K的地址空间,如果程序要想访问大于64K的内存,就需要把内存分段,每段64K,用段地址+偏移量的方式来访问,这样使20根地址线全用上,最大的寻址空间就可以到1M字节,这在当时已经是非常大的内存空间了。实模式将整个物理内存看成分段的区域,程序代码和数据位于不同区域,系统程序和用户程序并没有区别对待,而且每一个指针都是指向实际的物理地址。这样一来,用户程序的一个指针如果指向了系统程序区域或其他用户程序区域,并修改了内容,那么对于这个被修改的系统程序或用户程序,其后果就很可能是灾难性的。再者,随着软件的发展,1M的寻址空间已经远远不能满足实际的需求了。最后,对处理器多任务支持需求也日益紧迫,所有这些都促使新技术的出现。为了克服实模式下的内存非法访问问题,并满足飞速发展的内存寻址和多任务需求,处理器厂商开发出保护模式。在保护模式中,除了内存寻址空间大大提高;提供了硬件对多任务的支持;物理内存地址也不能直接被程序访问,程序内部的地址(虚拟地址)要由操作系统转化为物理地址去访问,程序对此一无所知。至此,进程(程序的运行态)有了严格的边界,任何其他进程根本没有办法访问不属于自己的物理内存区域,甚至在自己的虚拟地址范围内也不是可以任意访问的,因为有一些虚拟区域已经被放进一些公共系统运行库。这些区域也不能随便修改,若修改就会有出现linux中的段错误,或Windows中的非法内存访问对话框。