摘要:本文讲述8086怎样进行芯片级别的内存寻址,linux又是如何在这些硬件的基础上进行寻址的。本文主要讨论硬件和linux寻址的基本原理,后续将讨论分页机制的具体实现,内核如何给自己分配主存,怎样给进程分配线性地址。
一、寻址流程
逻辑地址经过分段单元形成线性地址,然后经过分页单元形成物理地址。
二、硬件中的分段
1.段选择符和段寄存器
32位的逻辑地址包含16位的段选择符和36位的偏移量。处理器的段寄存器用于存放段选择符。其中cs寄存器有一个重要功能:指明当前特权级。
2.段描述符
每个段由8位的段描述符表示,存放在GDT和LDT中,GDT和LDT在主存中的位置和大小存放在gdtr和ldtr寄存器中。
关于段选择符和段描述符,可以参考:保护模式编程之(一)——分段机制与GDT/LDThttp://blog.csdn.net/trochiluses/article/details/8968750
快速访问段描述符
每当一个段选择符被装入寄存器的时候,相应的段描述符号就从内存装入相应的非编程CPU寄存器,从此,逻辑地址的转换不经过主存中的GDT或者LDT而是直接应用相关CPU寄存器即可。只有寄存器内容发生改变,才会访问GDT或者LDT。
3.分段单元
逻辑地址的转换过程如下:
三、硬件中的分页
i386 CPU实现内存管理的基本思路是通过页目录和页表两极映射实现从线性地址到物理地址的转换。原因:4GB的线性地址空间,如果我们采用一级映射,页大小是4K,那么需要的页表项数量为4G/4K=1M;另外,一个页表项的大小是8B,如此一个进程的页表需要的存储空间位8M。实际情况下,可能线性地址空间仅仅某一部分有效(例如0x00000000~0x0000ffff),此时如果采用二级页表,可以避免一些无用线性地址的映射(如果相应的线性地址无效,那么对应的页目录项设置为空)。
其中寄存器cr3用于存放当前进程正在使用的页目录基地址。dir用于指明目录项,table用于指明表项,offset用于指明页内偏移。8086处理器分页原理如下图:
页目录项和页表项有同样的结构;
它们都有4B共32b,具体布局如下:
其中每个位的作用如下:
P--位0是存在(Present)标志,用于指明表项对地址转换是否有效。P=1表示有效;P=0表示无效。在页转换过程中,如果说涉及的页目录或页表的表项无效,则会导致一个异常。如果P=0,那么除表示表项无效外,其余位可供程序*使用,如图4-18b所示。例如,操作系统可以使用这些位来保存已存储在磁盘上的页面的序号。
R/W--位1是读/写(Read/Write)标志。如果等于1,表示页面可以被读、写或执行。如果为0,表示页面只读或可执行。当处理器运行在超级用户特权级(级别0、1或2)时,则R/W位不起作用。页目录项中的R/W位对其所映射的所有页面起作用。
U/S--位2是用户/超级用户(User/Supervisor)标志。如果为1,那么运行在任何特权级上的程序都可以访问该页面。如果为0,那么页面只能被运行在超级用户特权级(0、1或2)上的程序访问。页目录项中的U/S位对其所映射的所有页面起作用。
A--位5是已访问(Accessed)标志。当处理器访问页表项映射的页面时,页表表项的这个标志就会被置为1。当处理器访问页目录表项映射的任何页面时,页目录表项的这个标志就会被置为1。处理器只负责设置该标志,操作系统可通过定期地复位该标志来统计页面的使用情况。
D--位6是页面已被修改(Dirty)标志。当处理器对一个页面执行写操作时,就会设置对应页表表项的D标志。处理器并不会修改页目录项中的D标志。
AVL--该字段保留专供程序使用。处理器不会修改这几位,以后的升级处理器也不会。
PAGE SIZE只用于页目录项,如果为1表示启用大页,2M或者4M
3.2扩展 分页
从pentium开始,8086处理器引入了扩展分页模式,它允许页框大小是4M而非4K,它用于把大段连续的物理地址转换成相应的物理地址。在这种情况下,内核不使用中间页表进行地址转换,进而节省内存并保留TLB项。扩展分页机理如下:
扩展分页的页目录项和普通分页基本相同,除了:
1)page size位必须被设置
2)20位物理地址字段只有高10位是有意义的
通过设置cr4处理器寄存器的PSE标志能使得拓展分页和常规分页共存。
3.3物理 地址扩展(PAE)分页机制
3.4 64位系统中的分页
首先,32位下的分页机制不再适用。因为如果仍然是4K页,我们用48位线性地址来进行寻址,那么剩下48-12=52位,如果我们用其中的48位建立二级分页机制,那么每个进程的页目录项和页表项将含有2^18,太大了。
X86_64下,页大小是4K,寻址位数是48,分页级别是4,地址划分:9+9+9+9+12
3.5硬件高速缓存
处理器的cr0寄存器用于启用或者禁用硬件高速缓存,cr0中的nw标志表明是通写还是写回策略。
3.6TLB
TLB相当于页表的cache,每个cpu都有自己的TLB,与cache不同,TLB中的对应项不用同步,但是cpu的cr3寄存器发生修改的时候,表明当前运行进程发生了变化,此时要使得TLB所有项目无效。
四、控制寄存器CR0与CR3
控制寄存器(CR0~CR3)用于控制和确定处理器的操作模式以及当前执行任务的特性,CR0中含有控制处理器操作模式和状态的系统控制标志;CR1保留不用;CR2含有导致页错误的线性地址;CR3中含有页目录表物理内存基地址,因此该寄存器也被称为页目录基地址寄存器PDBR(Page-Directory
Base address Register)。
4.1CR0中的保护控制位:
(1)PE:CR0的位0是启用保护(Protection Enable)标志。当设置该位时即开启了保护模式;当复位时即进入实地址模式。这个标志仅开启段级保护,而并没有启用
分页机制。若要启用
分页机制,那么PE和PG标志都要置位。
(2)PG:CR0的位31是分页(Paging)标志。当设置该位时即开启了分页机制;当复位时则禁止分页机制,此时所有
线性地址等同于
物理地址。在开启这个标志之前必须已经或者同时开启PE标志。即若要启用分页机制,那么PE和PG标志都要置位。
(3)WP:对于Intel 80486或以上的CPU,CR0的位16是
写保护(Write Proctect)标志。当设置该标志时,处理器会禁止
超级用户程序(例如
特权级0的程序)向用户级只读页面执行写操作;当该位复位时则反之。该标志有利于UNIX类操作系统在创建进程时实现写时复制(Copy
on Write)技术。
当改变PE和PG位时,必须小心。只有当执行程序至少有部分代码和数据在线性地址空间和物理地址空间中具有相同地址时,我们才能改变PG位的设置。此时这部分具有相同地址的代码在分页和未分页世界之间起着桥梁的作用。无论是否开启分页机制,这部分代码都具有相同的地址。另外,在开启分页(PG=1)之前必须先刷新页高速缓冲TLB。
在修改该了PE位之后程序必须立刻使用一条跳转指令,以刷新处理器执行管道中已经获取的不同模式下的任何指令。在设置PE位之前,程序必须初始化几个系统段和控制寄存器。在系统刚上电时,处理器被复位成PE=0和PG=0(即实模式状态),以允许引导代码在启用分段和分页机制之前能够初始化这些寄存器和数据结构。
4.2CR2和CR3
CR2和CR3用于分页机制。CR3含有存放页目录表页面的物理地址(注意,是物理地址!!!),因此CR3也被称为PDBR。因为页目录表页面是页对齐的,所以该寄存器只有高20位是有效的。而低12位保留供更高级处理器使用,因此在往CR3中加载一个新值时低12位必须设置为0。
使用MOV指令加载CR3时具有让页高速缓冲无效的副作用。为了减少地址转换所要求的总线周期数量,最近访问的页目录和页表会被存放在处理器的页高速缓冲器件中,该缓冲器件被称为转换查找缓冲区(Translation
Lookaside Buffer,TLB)。只有当TLB中不包含要求的页表项时才会使用额外的总线周期从内存中读取页表项。
即使CR0中的PG位处于复位状态(PG=0),我们也能先加载CR3。以允许对分页机制进行初始化。当切换任务时,CR3的内容也会随之改变。但是如果新任务的CR3值与原任务的一样,处理器就无需刷新页高速缓冲。这样共享页表的任务可以执行得更快。
CR2用于出现页异常时报告出错信息。在报告页异常时,处理器会把引起异常的线性地址存放在CR2中。因此操作系统中的页异常处理程序可以通过检查CR2的内容来确定线性地址空间中哪一个页面引发了异常。