文档介绍:第4章内存管理
第4章内存管理
本章介绍Linux内存管理子系统的整体概念,讨论存储层次结构、x86存储管理硬件和Linux虚存系统及相关系统工具。
Linux内核的设计要考虑到在各种不同的微处理器上的实现,所以不能仅仅针对i386结构来设计它的映射机制,而要以虚拟的微处理器和内存管理单元MMU(Memory Management Unit)为基础,设计出一种通用的模式,再将其分别落实到具体的微处理器上。Linux在内存管理的软件实现方面,提供了不同的接口,可以用于各种各样不同地址线宽度的CPU。
Intel 的80386提供了两层影射的页式内存管理的件支持,一层是页面目录称为PGD(Page Directory),另一层是页表称为PT(Page Tables),PT的表项称为PTE(Page Table Elements)。通过它们实现从线性地址到物理地址的转换。这种两层影射方式对于32位地址线的386是很合适的。但Linux要设计成可在不同的CPU下运行,考虑到大于32位地址线宽度的CPU(例如64位的CPU),Linux内核的映射机制被设计成3层,在页面目录和页表之间增设了一层“中间目录”PMD(Page Mid-level Directory)在逻辑上,相应地也把线性地址从高到低分为4个位段,各占若干位,分别用作目录PGD的下标、中间目录PMD的下标、页表中的下标和物理页面内的位移。。PGD、PMD、PT都是数组。Page Frame是最后得到的物理页。
三层影射过程如下:
(1)从控制寄存器CR3中找到页目录的基址。
(2) 以线性地址的最高位段作为下标在PGD中找到确定中间目录的表项的指针。
(3) 以线性地址的次位段作为下标在PMD中找到确定页面表的表项的指针。
(4) 在线性地址的接下来位段为下标在PTE中找到页的指针。
(5)  最后线性地址的位段中为在此页中偏移量。
这样,最终完成了线性地址到物理地址的转换。
假如当要执行某个函数的第一个句子时,CPU会通过32位地址线寻址(2的32次方,可以寻址4G的线性地址空间)。通过MMU执行以上的影射过程,就会在计算机的内存中找到这个句子的物理地址,如果要找的那一句不在物理页中,就会发生一次异常中断,使硬盘和内存发生交互。
在Linux原码的 include/asm-i386/ 定义了能够包容不同CPU的接口:
# if CONFIG_X86_PAE //假如在PAE模式下,用三层影射结构
#include <asm/pgtable->
#else
#include<asm/pgtable-> //否则用两层
#endif
在pgtable-,PMD的结构。
#define PGDIR_SHIFT 22 //页目录是线性地址的31~22位
#define PTRS_PER_PGD 1024 //总共有1024个页目录
#define PMDIR_SHIFT 22 //中间目录不用了
#define PTRS_PER_PMD 1
#define PTRS_PER_PTE1024 //每个页表有1023页
在32位线性地址中的4G虚拟空间中,其中有1G做为内核空间,从0XC0000000到0XFFFFFFFF。每个进程都有自己的3G用户空间,它们共享1G的内核空间。当一个进程从用户空间进入内核空间时,它就不在有自己的进程空间了。
在物理空间中,内核总是从0地址开始的,而在虚拟空间中是丛0XC0000000开始的。内核中的影射是很简单的线性影射,所以0XC0000000就是两者的偏移量。
:
#define__PAGE_OFFSET (0xc0000000)
#definePAGE_OFFSET ((unsigned long ) __PAGE_OFFSET )
#defne __pa(x) ( (unsigned lonsg) (x) – PAGE_OFFSET)
// 内核虚拟地址转换到物理地址
#define __va(x) ((void *) ((unsigned long) (x) + PAGE_OFFSET))
// 内核从物理地址到虚拟地址的转换
 对i386微处理器来说,CPU实际上不是按3层而是按两层的模型来进行地址映射,这就需要将虚拟的3层映射落实到具体的两层的映射,跳过中间的PMD层次。
80386有实方式和保护方式两种工作方式。尽管实方式下80386的功能较Intel先前的微处理器有很大的提高,但只有在保护方式下,803