原文:linux内核笔记之高端内存映射

在32位的系统上,内核使用第3GB~第4GB的线性地址空间,共1GB大小。内核将其中的前896MB与物理内存的0~896MB进行直接映射,即线性映射,将剩余的128M线性地址空间作为访问高于896M的内存的一个窗口。

引入高端内存映射这样一个概念的主要原因就是我们所安装的内存大于1G时,内核的1G线性地址空间无法建立一个完全的直接映射来触及整个物理内存空间,而对于80x86开启PAE的情况下,允许的最大物理内存可达到64G,因此内核将自己的最后128M的线性地址空间腾出来,用以完成对高端内存的暂时性映射。

而在64位的系统上就不存在这样的问题了,因为可用的线性地址空间远大于可安装的内存。下图描述了内核1GB线性地址空间是如何划分的。

其中PAGE_OFFSET表示内核使用的1GB线性地址的起始处(第3GB),high_memory往右的部分则表示高端内存,共 128M 的线性地址。可以用来完成上述映射目的的区域为vmalloc area,Persistent kernel mappings区域和固定映射线性地址空间中的FIX_KMAP区域,这三个区域对应的映射机制分别为 非连续内存分配 , 永久内核映射和 临时内核映射 。

永久内核映射

在内核初始化页表管理机制时,专门用pkmap_page_table这个变量保存了PKMAP_BASE对应的页表项的地址,由pkmap_page_table来维护永久内核映射区的页表项的映射,页表项总数为LAST_PKMAP个。

这里的永久并不是指调用kmap()建立的映射关系会一直持续下去无法解除,而是指在调用kunmap()解除映射之间这种映射会一直存在,这是相对于临时内核映射机制而言的。

需要注意一点的是,当永久内核映射区没有空闲的页表项可供映射时,请求映射的进程会被阻塞,因此永久内核映射请求不能发生在中断和可延迟函数中。

临时内核映射

临时内核映射和永久内核映射相比,其最大的特点就是不会阻塞请求映射页框的进程,因此临时内核映射请求可以发生在中断和可延迟函数中。系统中的每个CPU都有自己的13个临时内核映射窗口,根据不同的需求(用于内核控制路径),选择不同的窗口来创建映射。每个CPU的映射窗口集合用 enum km_type 数据结构表示,该数据结构中的每个符号,如 KM_BOUNCE_READ 、 KM_USER0 或 KM_PTE0 ,标识了窗口的线性地址,其实是一个下标。当要内核建立一个临时映射时,通过 cpu_id 和 窗口下标 来确定线性地址。

临时内核映射的实现也比永久内核映射要简单,当一个进程申请在某个窗口创建映射,即使这个窗口已经在之前就建立了映射,新的映射也会建立并且覆盖之前的映射,所以说这种映射机制是临时的,并且不会阻塞当前进程。

非连续内存分配

非连续内存分配是指将物理地址不连续的页框映射到线性地址连续的线性地址空间,主要应用于大容量的内存分配。采用这种方式分配内存的主要优点是避免了外部碎片,而缺点是必须打乱内核页表,而且访问速度较连续分配的物理页框慢。

非连续内存分配的线性地址空间是从 VMALLOC_START 到 VMALLOC_END ,每当内核要用vmalloc类的函数进行非连续内存分配,就会申请一个vm_struct结构来描述对应的vmalloc区,两个vmalloc区之间的间隔至少为一个页框的大小,即PAGE_SIZE。

总结

由于内核的线性地址空间有限,因此采取上面介绍的三种方式来映射高端内存。但是每种映射的本质都是通过页表来建立线性地址与物理地址之间的联系。

永久内核映射和临时内核映射,都由内核指定了需要进行映射的页面,也就是说指定了页描述符(页描述符和物理页框之间的关系是固定不可变的)。在永久内核映射中,内核只需要在永久内核映射区找到空闲的,也就是未被映射的线性地址对应的页表项,然后将其分配给page即可,若找不到则将阻塞申请建立映射的进程;而临时内核映射更直接,连进行映射的线性地址窗口都是固定的,若是其已经分配给了某个页框,则直接抢过来用,因此之前的映射就被覆盖了,体现出了临时性。

非连续内存分配,内核不用指定具体的页框,只需指定要申请的内存大小,内核将在非连续内存分配区找到一块相应大小虚拟地址空间,然后再由伙伴系统分配页框,还要通过slab分配器为一些数据结构分配内存,最后再用同样的方式(设置PTE表项)来建立映射。

【转载】linux内核笔记之高端内存映射的更多相关文章

  1. 高端内存映射之kmap持久内核映射--Linux内存管理(二十)

    1 高端内存与内核映射 尽管vmalloc函数族可用于从高端内存域向内核映射页帧(这些在内核空间中通常是无法直接看到的), 但这并不是这些函数的实际用途. 重要的是强调以下事实 : 内核提供了其他函数 ...

  2. kmalloc分配物理内存与高端内存映射--Linux内存管理(十八)

    1 前景回顾 1.1 内核映射区 尽管vmalloc函数族可用于从高端内存域向内核映射页帧(这些在内核空间中通常是无法直接看到的), 但这并不是这些函数的实际用途. 重要的是强调以下事实 : 内核提供 ...

  3. linux arm的高端内存映射

    linux arm的高端内存映射(1) vmalloc 高端内存映射   与高端映射对立的是低端映射或所谓直接映射,内核中有关变量定义它们的它们的分界点,全局变量high_memory,该变量定义在m ...

  4. Linux高端内存映射(上)【转】

    转自:http://blog.csdn.net/vanbreaker/article/details/7579941 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 高端内 ...

  5. 高端内存映射之kmap_atomic固定映射--Linux内存管理(二十一)

    1 固定映射 1.1 数据结构 linux高端内存中的临时内存区为固定内存区的一部分, 对于固定内存在linux内核中有下面描述 x86 arm arm64 arch/x86/include/asm/ ...

  6. 高端内存映射之vmalloc分配内存中不连续的页--Linux内存管理(十九)

    1 内存中不连续的页的分配 根据上文的讲述, 我们知道物理上连续的映射对内核是最好的, 但并不总能成功地使用. 在分配一大块内存时, 可能竭尽全力也无法找到连续的内存块. 在用户空间中这不是问题,因为 ...

  7. linux用户空间和内核空间(内核高端内存)_转

    转自:Linux用户空间与内核空间(理解高端内存) 参考: 1. 进程内核栈.用户栈 2. 解惑-Linux内核空间 3. linux kernel学习笔记-5 内存管理   Linux 操作系统和驱 ...

  8. Linux内核高端内存 转

        Linux内核地址映射模型x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图.   Linux内核地址空间划分 通 ...

  9. Linux用户空间与内核空间(理解高端内存)

    Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...

随机推荐

  1. hibernate笔记01

  2. sql 循环语句几种方式

    --第一   declare @orderNum varchar(255) create table #ttableName(id int identity(1,1),Orders varchar(2 ...

  3. Mongodb 笔记06 副本集的组成、从应用程序连接副本集、管理

    副本集的组成 1. 同步:MongoDB的复制功能是使用操作日志oplog实现的,操作日志包含了主节点的每一次写操作.oplog是主节点的local数据库中的一个固定集合.备份节点通过查询整个集合就可 ...

  4. linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-59416.html linux设备驱动归纳总结(三):1.字符型设备之设备申请 操作系统:Ubunru ...

  5. datatables中columns.render的使用

    可直接在columns申明中对应列下方使用render改变该列样式 也可单独在columnsDefs中用targets指定目标. "render":function(data,ty ...

  6. CentOS6.5系统软件仓库及挂载NTFS

    第一步:下载rpmforge,下载对应的版本,就是对应CentOS版本,还有32位与64位也要对应上.rpmforge拥有4000多种CentOS的软件包,被CentOS社区认为是最安全也是最稳定的一 ...

  7. 【JQGRID DOCUMENTATION】.学习笔记.4.Navigator

    Navigator是一个将查找或编辑记录的动作,变得非常容易达到用户交互特性.开发者可以创建自定义动作,也可以使用六个预定义的动作.jqGrid为预定义的动作提供icon button图形. 一组完整 ...

  8. Oracle触发器使用介绍

    触发器,函数,包都是可以再生利用的东西,所以在创建的时候都要用到create or replace这个万能语句,接着就是主角trigger的出现了,主角出现还需要一点点波动,通常大人物都不是随随便便就 ...

  9. StringBuffer类的方法

    public class Page116 { /** * StringBuffer类的练习 * @param args * @throws IOException */ public static v ...

  10. [ios]纯代码实现UITableViewCell的自定义扩展

    (转)参考:http://blog.sina.com.cn/s/blog_65cbfb2b0101cd60.html 第一种, 简单的增加UITableViewCell一些小功能 例如在cell上面添 ...