全部文章 | 测试技术 | python脚本 | 安全技术 | 项目管理 | 感悟休闲

作者: amions   发表日期: 2008-09-03 09:14   复制链接




 
  当我们说一个CPU是“16位”或“32位”时,指的是处理器中ALU的宽度,数据总线具有和ALU相同的宽度,并且地址总线应该也具有相同的宽度,因为一个地址,也就是一个指针,最好是与一个整数的长度一致,但一个8位的地址只能用来寻访256个不同的地址单元,这显然太小了,所以8位CPU的地址总线都是16位的,这也导致8位的CPU指令系统中都是16位的操作。
  当CPU从8位升级到16位,本来数据总线和地址总线的宽度可以一致了,但人们又觉得16位地址总线所决定的空间(64K)太小了,所以Intel结合当时的情况,决定把地址空间增加16倍,即1M。如果地址空间增加到1M,那么地址总线的宽度就要增加到20位,但CPU中的ALU宽度只有16位,也就是说直接加以运算的指针的长度是16位。为了解决这个问题,Intel在8086CPU中设置了四个段寄存器:CS、DS、SS、ES,分别为代码段、数据段、堆栈段、附加段,每个段寄存器都是16位,对应于地址总线中的高16位,每条访问内存指令中的内部地址都是16位的,但是在送上地址总线之前都在CPU内部自动地与某个段寄存器中的内容相加,形成一个20位的实际地址。这样就实现了从16为内部地址到20位实际地址的转换。
  但是又发现了新的问题,对于每一个由段寄存器的内容确定的“基地址”,一个进程总是能够访问从此开始64K字节的连续地址空间,而无法加以限制。同时,可以用来改变段寄存器内容的指令也不是什么特权指令,也就是说通过改变段寄存器的内容,一个进程可以随心所欲的访问内存中的任何单元。由于8086的这种内存寻址方式缺乏对内存空间的保护,所以为了区别于后来出现的“保护模式”,就成为“实地址模式”。
  针对8086的这个缺陷,Intel从80286开始实现其保护模式,同时不久以后的32位80386CPU也开发成功,从80386以后,虽然又出现了80486、80586,速度上提高了很多,但和80386属于同一种系统结构,所以统称为“i386”结构。80386作为一个产品系列中的一员,虽然已经是32位,但仍必须维持段寄存器,还要同时支持实地址模式和保护模式。Intel选择了在段寄存器的基础上构筑保护模式的构思,并且保留16位的段寄存器。为了实现保护模式,段寄存器中不再是单纯的基地址,而是指向一个地址段描述数据结构的指针。当一条访问内存的指令发出一个内存地址时,CPU就可以这样找到实际数据总线的地址:
  (1)根据指令的性质来确定应该使用哪个段寄存器,这点和“实模式”相同。
  (2)根据段寄存器的内容,找到相应的“地址段描述结构”。
  (3)从地址段描述结构中得到基地址。
  (4)将指令中发出的地址作为位移,与地址段描述结构中规定的段长度相比,看看是否越界。
  (5)根据指令的性质和地址段描述结构中的访问权限来确定是否越权。
  (6)将指令中发出的地址作为位移,与基地址相加得出实际的“物理地址”。
  首先,在80386的CPU中增设了两个寄存器,一个是全局性的段描述表寄存器GDTR,另一个是局部性的段描述表寄存器LDTR,分别用来指向存储在内存中的一个段描述结构数组,访问这两个寄存器的专用指令便设计成“特权指令”。在此基础上,段寄存器的高13位用做访问段描述表中具体描述结构的下标,再把这个下标和GDTR/LDTR指针结合,才能得到描述表项的起始地址。段寄存器的低3位分别用来表示使用GDT(0)还是LDT(1),和优先级(2位)。每个段描述表项是64位,里面含有段的基地址和段的大小,和一些其它的信息。如果把每个段积存其都指向同一个描述项,而在该描述项中将基地址设成0,并将段的长度设成最大,这样便形成一个从0开始覆盖整个32位地址空间的一个整段,此时物理地址和逻辑地址相同,CPU放到地址总线上去的地址就是在指令中给出的地址,Intel称其为平面地址。它是段式内存管理的一种特例。
  利用80386对段式内存管理的硬件支持,可以实现段式虚存管理。当一个段寄存器的内容改变时,CPU要根据新的段寄存器内容以及GDTR/LDTR的内容找到相应的段描述项并装入CPU中,在这个过程中,CPU会检查该描述项中的p标志位,如果p标志位为0,就表示该描述项所指的那一段内容不在内存中,此时CPU会产生一次异常,而相应的服务程序便可以从磁盘交换区将这一段的内容读入内存,并据此设置描述项中的基地址,再将p标志位设置成1。相应的,内存中暂时不用的存储段也可以写入磁盘,并将其描述项中的p标志位改成0。
  段式存储管理机制的灵活性和效率都比较差,一方面,“段”是可变长度的,这就给盘区交换操作带来了不便,另一方面,如果为了增加灵活性而将一个进程的空间划分成很多小段,就势必要求在程序中频繁地改变段寄存器的内容。同时,如果将段分小,虽然一个段描述表中可以容纳8192个描述项,也未必就能保证足够使用。所以,比较好的办法还是采用页式存储管理。本来页式存储管理并不需要建立在段式存储管理的基础之上,这是两种不同的机制。可是在80386中,保护模式的实现是与段式存储密不可分的,因此就无法绕过段式存管来实现页式存管。这也意味着,页式存管的作用是在由段式存管所映射而成的地址上再加上一层地址映射。由于此时由段式存管映射而成的地址不再是物理地址了,Intel就称之为“线性地址”。
  线性地址的格式如下(假设指针的ps为1):
  typedef struct{
    unsigned int dir:10 /*页面目录下标,用于指向页面表。*/
    unsigned int page:10 /*页面表下标,用于指向物理页面。*/
    unsigned int offset:12 /*在4K字节内的物理页面偏移*/
  };
  80386把线性地址空间划分成32位的页面,每个页面可以被映射至物理存储空间中任意一块32位的区间。并且不像段式存储,连续的线性地址经过映射后在物理空间不一定是连续的。虽然页式存管是建立在段式存管的基础之上,但一旦启用了页式存管,所有的线性地址都要经过页式映射,连GDTR/LDTR中给出的段描述表起始地址也不例外。
  32位的线性地址,31~22位表示页面目录,21~12位表示页面表,11~0位表示页内的偏移。这样,从线性地址到物理地址的映射过程为:
  (1)从CR3(指向当前页面目录的指针)中取得页面目录的基地址。
  (2)以线性地址中的31~22位为下标,在目录中取得相应页面表的基地址。
  (3)以线性地址中的21~12位为下标,在页面表中取得相应页面的描述项。
  (4)将页面描述项中给出的页面基地址与线性地址中的11~0位段相加,得到物理地址。
  这里有个疑问,就是为什么页式存管要使用两个层次,而不是像在使用段寄存器时那样一步到位呢?这是出于空间效率的考虑,如果将线性地址中的dir和page两个位段合并在一起,就是20位,这样页面表就有1048676个表项,而每个页面的大小为4K,总的空间大小则为4K*1048676=4G,正好是32位地址空间的大小,但是实际上很难有一个进程会用到4G的全部空间,所以大部分表项是空着的,可是一个数组中,即使空着不用的表项也会占用空间,这就造成了浪费。而分成两层,则页表可以视需要而设置,如果目录中某项为空,就不必设立相应的页表,从而剩下了存储空间。另外,一个页面的大小是4K,而每个页面表项或目录项的大小是4个字节,1024个表项正好也是4K字节,恰好可以放在一个页面中。也正因为如此,64位的CPU中的页面大小是8K字节,因为目录表项和页面表项的大小都变成了8个字节。
  如前所述,目录项中含有指向一个页面表4的指针,而页面表项中含有指向一个页面起始地址的指针,由于页面表和页面的起始地址总是在4K字节的边界上,所以这些指针的低12位(4K字节大小)永远都是0,这样在目录项和页表项中都只要有20位用于指针就够了,而余下的12位可以用于控制或其他目的使用。用一个结构表示:
  typedef struct{
    unsigned int ptba : 20; /*页表基地址的高20位*/
    unsigned int avail : 3; /*供系统程序员使用*/
    unsigned int g : 1; /*是否为全局性页面*/
    unsigned int ps : 1; /*页面大小,0表示4K字节,1表示4M字节。*/
    unsigned int reserved : 1; /*保留,永远是0。*/
    unsigned int a : 1; /*accessed,是否被访问过*/
    unsigned int pcd : 1; /*关闭缓冲存储器*/
    unsigned int pwt : 1; /*Write-Through*/
    unsigned int u_s : 1; /*0表示系统权限,1表示用户权限*/
    unsigned int r_w : 1; /*只读或可写*/
    unsigned int p : 1; /*0表示页面不在内存中*/
  };
  其中最低位p用于虚拟内存的管理,在前面已经介绍过。当指针中的ps位为1时,页面大小就成了4M字节,而页表就不再使用了,这时线性地址中的低22位就全部用作在4M字节页面中的位移,这样总的寻址能力还是没有改变,但是映射的过程少了一个层次,随着内存容量和磁盘容量的日益增加,磁盘访问速度显著提高,以及对图像处理要求的日益增加,4M字节的页面大小有可能会成为主流,这是Intel设计上一个很有远见的地方。


阅读全文(113) | 回复(0) | 推送
欢迎到 amions 的个人主页看更多内容



  共0条回复