Linux 内存管理之highmem简介

来源:互联网 发布:怎么安装软件 编辑:程序博客网 时间:2024/06/06 14:01

一、Linux内核地址空间

一般来说Linux 内核按照 3:1 的比率来划分虚拟内存(X86等):3 GB 的虚拟内存用于用户空间,1GB 的内存用于内核空间。当然有些体系结构如MIPS使用2:2 的比率来划分虚拟内存:2 GB 的虚拟内存用于用户空间,2 GB 的内存用于内核空间,另外像ARM架构的虚拟空间是可配置(1:3、2:2、3:1)。内核线性地址空间用于为内核的运行提供最基本的支持,也是操作系统赖以存在的基础。所谓内核线性地址空间就是说内核态下虚拟地址与物理地址是线性关系,两者相差一个固定偏差,计算公式为VA(虚拟地址)=PA(物理地址)+PAGE_OFFSET。

二、什么是高端内存

以x86为例linux中内核使用3G-4G的线性地址空间,也就是说总共只有1G的地址空间可以用来映射物理地址空间。但是,如果内存大于1G的情况下内核态线性地址就不够用了。为此内核引入了一个高端内存的概念,把1G的线性地址空间划分为两部分:小于896M物理地址空间的称之为低端内存,这部分内存的物理地址和3G开始的线性地址是一一对应映射的,也就是说内核使用的线性地址空间(VA)3G--(3G+896M)和物理地址空间(PA)0-896M一一对应,PAGE_OFFSET=0xC0000000;剩下的128M的线性空间用来映射剩下的大于896M的物理地址空间,这也就是我们通常说的高端内存区,这部分空间需要MMU通过TLB表来建立动态的映射关系。

三、高端内存映射

高端内存映射有三种方式:

1、  临时映射空间

固定映射空间是内核线性空间中的一组保留虚拟页面空间,位于内核线性地址的末尾即最高地址部分。其地址编译时确定,用于特定用途(如VSYSCALL系统调用,MIPS的cache着色)。由枚举类型  fixed_addresses决定,内核在FIXADDR_START 到 FIXADDR_TOP 之间

在这个空间中,有一部分用于高端内存的临时映射。这块空间具有如下特点: 每个 CPU 占用一块空间;可以用在中断处理函数和可延迟函数的内部,从不阻塞,禁止内核抢占;在每个 CPU 占用的那块空间中,又分为多个小空间,每个小空间大小是 1 个 page,每个小空间用于一个目的,这些目的定义在 kmap_types.h 中的 km_type 中。

当要进行一次临时映射的时候,需要指定映射的目的,根据映射目的,可以找到对应的小空间,然后把这个空间的地址作为映射地址。这意味着一次临时映射会导致以前的映射被覆盖。

接口函数:kmap_atomic/kunmap_atomic。 使用从FIX_KMAP_BEGIN到FIX_KMAP_END之间的物理页

2、  长久映射空间

长久映射地址空间是预留的线性地址空间。访问高内存的一种手段。使用方式是先通过alloc_page() 获得了高端内存对应的 page,然后内核从专门为此留出的线性空间分配一个虚拟地址,在 PKMAP_BASE 到 FIXADDR_START 之间。

接口函数:void*kmap(struct *page)、 void kumap(struct *page)

该接口函数在高/低内存都能使用,可以睡眠,数量有限。对于不使用的的 page,及应该时从这个空间释放掉(也就是解除映射关系)。

#definePKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE * (LAST_PKMAP + 1)) & PMD_MASK)

#defineLAST_PKMAP 1024

3、非连续映射地址空间

非连续映射地址空间适用于为不频繁申请释放内存的情况,这样不会频繁的修改内核页表。总的来说,内核主要在以下情况使用非连续映射地址空间:映射设备的I/O空间;为内核模块分配空间;为交换分区分配空间

每个非连续内存区都对应一个类型为vm_struct 的描述符,通过next字段,这些描述符被插入到一个vmlist链表中。

这种方式下高端内存使用简单,因为通过vmalloc() ,在”内核动态映射空间“申请内存的时候,就可能从高端内存获得页面(参看 vmalloc 的实现),因此说高端内存有可能映射到”内核动态映射空间“中。

接口函数:vmalloc(vfree):物理内存(调用alloc_page)和线性地址同时申请,物理内存是 __GFP_HIGHMEM类型(分配顺序是HIGH, NORMAL , DMA )(可见vmalloc不仅仅可以映射HIGHMEM页框,它的主要目的是为了将零散的,不连续的页框拼凑成连续的内核逻辑地址空间... );

vmap(vumap):vmalloc的简化版;

ioremap(iounmap):分配I/O映射空间;

下图简单表达了linux内核对虚拟地址的映射,其中highmem区域用于对高端内存映射:

 

四、MIPS的高端内存

         Mips的highmem管理可参见其官方简介:http://www.linux-mips.org/wiki/Highmem

在MIPS32 CPU中不经过MMU转换的内存窗口只有kseg0和kseg1 的512MB的大小,而且这两个内存窗口映射到同一得0~512M的物理地址空间。其余的3G虚拟地址空间需要经过MMU转换成物理地址,这个转换规则是由CPU 厂商实现的。换句话说,在MIPS32 CPU下面访问高于512M的物理地址空间,必须通过MMU地址转换。即按VA=PA+PAGE_OFFSET公式映射的空间最大只有512M,其中PAGE_OFFSET=0x80000000,而在Linux中MIPS32只使用其中的256MB。

  MIPS在higmem使用过程中需要注意两个问题:一是要考虑由higmem带来的整个系统性能和稳定性间的平衡,二是highmem不支持cache aliases。

五、总结

高端内存含义为:线性地址空间 PAGE_OFFSET+HIGHSTART至4G的最后线性地址 <==映射==> HIGHSTART以上的物理页框,非直接映射。有3种方法:非连续内存区映射,永久内核映射,临时内核映射(固定映射)。

用户空间当然可以使用高端内存,而且是正常的使用,内核在分配那些不经常使用的内存时,都用高端内存空间(如果有),所谓不经常使用是相对来说的,比如内核的一些数据结构就属于经常使用的,而用户的一些数据就属于不经常使用的。

用户在启动一个应用程序时,是需要内存的,而每个应用程序都有3G的线性地址,给这些地址映射页表时就可以直接使用高端内存。

总之,内核的高端线性地址是为了访问内核固定映射以外的内存资源。实际上高端内存是针对内核一段特殊的线性空间提出的概念,和实际的物理内存是两码事。进程在使用内存时,触发缺页异常,具体将哪些物理页映射给用户进程是内核考虑的事情。在用户空间中没有高端内存这个概念。

注:1、本文中本文中虚拟地址和线性地址没做细致区分,可认为是一个概念。
2、关于highmem的代码分析可参见《关于高端内存的一些笔记》一文:http://bbs.chinaunix.net/thread-1938084-1-1.html
原创粉丝点击