IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Linux操作系统分段和分页机制

    Vlix_Liu发表于 2015-11-07 15:23:28
    love 0

    1 基于80x86的Linux分段机制

    80386的两种工作模式:80386的工作模式包括实地址模式和虚地址模式(保护模式)。Linux主要工作在保护模式下。

    在保护模式下,80386虚地址空间可达16K个段,每段大小可变,最大达4GB。逻辑地址到线性地址的转换由80386分段机制管理。段寄存器CS、DS、ES、SS、FS或GS各标识一个段。这些段寄存器作为段选择器,用来选择该段的描述符。

    分段逻辑地址到线性地址转换图:

    分段地址转换图

    Linux对80386的分段机制使用得很有限,因为Linux的设计目标是支持绝大多数主流的CPU,而很多CPU使用的是RISC体系结构,并没有分段机制,所以2.6版内核只有在80x86结构下才使用分段,而且只是象征性地使用了一下:

     

    所有Linux进程仅仅使用四种段来对指令和数据寻址。运行在用户态的进程使用所谓的用户代码段和用户数据段。类似地,运行在内核态的所有Linux进程都使用一对相同的段对指令和数据寻址:它们分别叫做内核代码段和内核数据段。下表显示了这四个重要段的段描述符字段的值:

    段 Base G Limit S Type DPL D/B P
    用户代码段 0x00000000 1 0xfffff 1 10 3 1 1
    用户数据段 0x00000000 1 0xfffff 1 2 3 1 1
    内核代码段 0x00000000 1 0xfffff 1 10 0 1 1
    内核数据段 0x00000000 1 0xfffff 1 2 0 1 1

    相应的段描述符由宏__USER_CS,__USER_DS,__KERNEL_CS,和__KERNEL_DS分别定义。例如,为了对内核代码段寻址,内核只需要把这个宏产生的值装进cs段寄存器即可。 注意,与段相关的线性地址从0开始,达到232 -1的寻址限长。这就意味着在用户态或内核态下的所有进程可以使用相同的逻辑地址。所有段都从0x00000000开始,这可以得出另一个重要结论,那就是在Linux下逻辑地址与线性地址是一致的,即逻辑地址的偏移量字段的值与相应的线性地址的值总是一致的。

     

    如前所述,CPU的当前特权级(CPL)反映了进程是在用户态还是内核态,并由存放在cs寄存器中的段选择符的RPL字段指定。只要当前特权级被改变,一些段寄存器必须相应地更新。例如,当CPL=3时(用户态),ds寄存器必须含有用户数据段的段选择符,而当CPL=0时,ds寄存器必须含有内核数据段的段选择符。

    类似的情况也出现在ss寄存器中。当CPL为3时,它必须指向一个用户数据段中的用户栈,而当CPL为0时,它必须指向内核数据段中的一个内核栈。当从用户态切换到内核态时,Linux总是确保ss寄存器装有内核数据段的段选择符。

    当对指向指令或者数据结构的指针进行保存时,内核根本不需要为其设置逻辑地址的段选择符,因为cs寄存器就含有当前的段选择符。例如,当内核调用一个函数时,它执行一条call汇编语言指令,该指令仅指定它逻辑地址的偏移量部分,而段选择符不用设置,其隐含在cs寄存器中了。因为“在内核态执行” 的段只有一种,叫做代码段,由宏_KERNEL_CS定义,所以只要当CPU切换入内核态时足可以将__KERNEL_CS装载入cs。同样的道理也适用于指向内核数据结构的指针(隐含地使用ds寄存器)以及指向用户数据结构的指针(内核显式地使用es寄存器)。

     

    2 基于80x86的Linux分页机制

    Linux分页机制的作用:分页机制是在段机制之后进行的,它进一步将线性地址转换为物理地址。我们先来看看硬件构造:

     

    80386使用4K字节大小的页,且每页的起始地址都被4K整除。因此,早期80386把4GB字节线性地址空间划分为1M个页面,采用了两级表结构。

    两级表的第一级表称为页目录,存储在一个4K字节的页中,页目录表共有1K个表项,每个表项为4个字节,线性地址最高的10位(22-31)用来产生第一级表索引,由该索引得到的表项中的内容定位了二级表中的一个表的地址,即下级页表所在的内存块号。

    第二级表称为页表,存储在一个4K字节页中,它包含了1K字节的表项,每个表项包含了一个页的物理地址。二级页表由线性地址的中间10位(12-21)位进行索引,定位页表表项,获得页的物理地址。页物理地址的高20位与线性地址的低12位形成最后的物理地址。

    利用两级页表转换地址图:

    页表地址转换
    80x86的分页机制由CR0中的PG位启用。如PG=1,启用分页机制,并使用本节要描述的机制,把线性地址转换为物理地址。如PG=0,禁用分页机制,直接把前面段机制产生的线性地址当作物理地址使用。

     

    80386使用4K字节大小的页。每一页都有4K字节长,并在4K字节的边界上对齐,即每一页的起始地址都能被4K整除(物理地址最低12位为0)。因此,80386把4G字节的线性地址空间,划分为1G个页面,每页有4K字节大小。

     

    分页机制通过把线性地址空间中的页,重新定位到物理地址空间来进行管理,因为每个页面的整个4K字节作为一个单位进行映射,并且每个页面都对齐4K字节的边界,因此,线性地址的低12位经过分页机制直接地作为物理地址的低12位使用。

     

    线性/物理地址的转换,可将其意义扩展为允许将一个线性地址标记为无效,而不是实际地产生一个物理地址。有两种情况可能使页被标记为无效:其一是线性地址是操作系统不支持的地址;其二是在虚拟存储器系统中,线性地址对应的页存储在磁盘上,而不是存储在RAM存储器中。在前一种情况下,程序因产生了无效地址而必须被终止。

     

    对于后一种情况,该无效的地址实际上是请求操作系统的虚拟存储管理系统,把存放在磁盘上的页传送到物理存储器中,使该页能被程序所访问。由于无效页通常是与虚拟存储系统相联系的,这样的无效页通常称为未驻留页,并且用页表属性位中叫做存在位的属性位进行标识。未驻留页是程序可访问的页,但它不在主存储器中。对这样的页进行访问,形式上是发生异常,实际上是通过异常进行缺页处理。

     

    2.1 页全局目录

     

    页全局目录表,最多可包含1024个页目录项,每个页目录项为4个字节,算起来正好一个页面,结构如图所示:

    页全局目录

     
    ·第0位是存在位,Present标志:如果被置为1,所指的页(或页表)就在主存中;如果该标志为0,则这一页不在主存中,此时这个表项剩余的位可由操作系统用于自己的目的。如果执行一个地址转换所需的页表项或页目录项中Present标志被清0,那么分页单元就把该线性地址存放在控制寄存器cr2中,并产生14号异常:缺页异常。(我们将在后面的一系列博客中重点讨论Linux如何使用这个字段)。
    ·第1位是读/写位,第2位是用户/管理员位,Read/Write标志:含有页或页表的存取权限(Read/Write或Read);User/Supervisor标志:含有访问页或页表所需的特权级。这两位为页目录项提供硬件保护。当特权级为3的进程要想访问页面时,需要通过页保护检查,而特权级为0的进程就可以绕过页保护,如图所示:

    页面读写标志

     

    ·第3位是PWT(Page Write-Through)位,表示是否采用写透方式,写透方式就是既写内存(RAM)也写高速缓存,该位为1表示采用写透方式

     

    ·第4位是PCD(Page Cache Disable)位,表示是否启用高速缓存,该位为1表示启用高速缓存。

     

    ·第5位是访问位,Accessed标志:当对页目录项进行访问时,A位=1。每当分页单元对相应页框进行寻址时就设置这个标志。当选中的页被交换出去时,这一标志就可以由操作系统使用。分页单元从不重置这个标志;而是必须由操作系统去做。

     

    ·第6位Dirty标志,对于页全局目录项,其始终为1。
    ·第7位是Page Size标志,只适用于页目录项。如果置为1,页目录项指的是4MB的页面,请看后面的扩展分页。
    ·第8位是Global 标志:只应用于页表项。这个标志是在Pentium Pro引入的,用来防止常用页从TLB高速缓存中刷新出去。只有在cr4寄存器的页全局启用(Page GlobalEnable ,PGE)标志置位时这个标志才起作用。

     

    ·第9~11位由操作系统专用,Linux也没有做特殊之用

     

    2.2 页表

    80386的每个页目录项指向一个页表,页表最多含有1024个页面项,每项4个字节,包含页面的起始地址和有关该页面的信息。页面的起始地址也是4K的整数倍,所以页面的低12位也留作它用,如图所示。

    页目录项

     

     

    第31~12位是20位物理页面地址,除第6位外第0~5位及9~11位的用途和页目录项一样,第6位是页面项独有的,当对涉及的页面进行写操作时,D位被置1。

     

    4GB的存储器只有一个页目录,它最多有1024个页目录项,每个页目录项又含有1024个页面项,因此,存储器一共可以分成1024×1024=1M个页面。由于每个页面为4K个字节,所以,存储器的大小正好最多为4GB。

    2.3 线性地址到物理地址的转换

     

    当访问一个操作单元时,如何由分段结构确定的32位线性地址通过分页操作转化成32位物理地址呢?过程如图所示。

    线性地址转换

     

    第一步,CR3包含着页目录的起始地址,用32位线性地址的最高10位A31~A22作为页目录的页目录项的索引,将它乘以4,与CR3中的页目录的起始地址相加,形成相应页表的地址。

     

    第二步,从指定的地址中取出32位页目录项,它的低12位为0,这32位是页表的起始地址。用32位线性地址中的A21~A12位作为页表中的页面的索引,将它乘以4,与页表的起始地址相加,形成32位页面地址。



沪ICP备19023445号-2号
友情链接