标签:内存空间分配 x86 详细 use 特性 特殊 直接映射 无法 这不
我们展示给你的下一个内存分配函数是 vmlloc, 它在虚拟内存空间分配一块连续的内存 区. 尽管这些页在物理内存中不连续 (使用一个单独的对 alloc_page 的调用来获得每个 页), 内核看它们作为一个一个连续的地址范围. vmalloc 返回 0 ( NULL 地址 ) 如果发 生一个错误, 否则, 它返回一个指向一个大小至少为 size 的连续内存区.
我们这里描述 vmalloc 因为它是一个基本的 Linux 内存分配机制. 我们应当注意, 但是, vmalloc 的使用在大部分情况下不鼓励. 从 vmalloc 获得的内存用起来稍微低效些, 并 且, 在某些体系上, 留给 vmalloc 的地址空间的数量相对小. 使用 vmalloc 的代码如果 被提交来包含到内核中可能会受到冷遇. 如果可能, 你应当直接使用单个页而不是试图使 用 vmalloc 来掩饰事情.
让我们看看 vmalloc 如何工作的. 这个函数的原型和它相关的东西(ioremap, 严格地不 是一个分配函数, 在本节后面讨论)是下列:
#include <linux/vmalloc.h>
void *vmalloc(unsigned long size); void vfree(void * addr);
void *ioremap(unsigned long offset, unsigned long size);
void iounmap(void * addr);
NUMA (非统一内存存取) 计算机是多处理器系统, 这里内存对于特定的处理器组("节点")是"局部的". 对局部内
存的存取比存取非局部内存更快. 在这样的系统, 在当前节点分配内存是重要的. 驱动作者通常不必担心 NUMA 问题, 但是.
值得强调的是 kmalloc 和 _get_free_pages 返回的内存地址也是虚拟地址. 它们的实际 值在它用在寻址物理地址前仍然由 MMU (内存管理单元, 常常是 CPU 的一部分)管理.[31]31 vmalloc 在它如何使用硬件上没有不同, 不同是在内核如何进行分配任务上.
kmalloc 和 get_free_pages 使用的(虚拟)地址范围特有一个一对一映射到物理内存, 可能移位一个常量 PAGE_OFFSET 值; 这些函数不需要给这个地址范围修改页表. vmalloc 和 ioremap 使用的地址范围, 另一方面, 是完全地合成的, 并且每个分配建立(虚拟)内 存区域, 通过适当地设置页表.
这个区别可以通过比较分配函数返回的指针来获知. 在一些平台(例如, x86), vmalloc 返回的地址只是远离 kmalloc 使用的地址. 在其他平台上(例如, MIPS, IA-64, 以及 x86_64 ), 它们属于一个完全不同的地址范围. 对 vmalloc 可用的地址在从 VMALLOC_START 到 VAMLLOC_END 的范围中. 2 个符号都定义在 <asm/patable.h> 中.
vmalloc 分配的地址不能用于微处理器之外, 因为它们只在处理器的 MMU 之上才有意义. 当一个驱动需要一个真正的物理地址(例如一个 DMA 地址, 被外设硬件用来驱动系统的总 线), 你无法轻易使用 vmalloc. 调用 vmalloc 的正确时机是当你在为一个大的只存在于 软件中的顺序缓冲分配内存时. 重要的是注意 vamlloc 比 get_free_pages 有更多开 销, 因为它必须获取内存并且建立页表. 因此, 调用 vmalloc 来分配仅仅一页是无意义 的.
在内核中使用 vmalloc 的一个例子函数是 create_module 系统调用, 它使用 vmalloc 为在创建的模块获得空间. 模块的代码和数据之后被拷贝到分配的空间中, 使用 copy_from_user. 在这个方式中, 模块看来是加载到连续的内存. 你可以验证, 同过看
/proc/kallsyms, 模块输出的内核符号位于一个不同于内核自身输出的符号的内存范围.
使用 vmalloc 分配的内存由 vfree 释放, 采用和 kfree 释放由 kmalloc 分配的内存的 相同方式.
如同 vmalloc, ioremap 建立新页表; 不同于 vmalloc, 但是, 它实际上不分配任何内存. ioremap 的返回值是一个特殊的虚拟地址可用来存取特定的物理地址范围; 获得的虚拟地 址应当最终通过调用 iounmap 来释放.
ioremap 对于映射一个 PCI 缓冲的(物理)地址到(虚拟)内核空间是非常有用的. 例如, 它可用来存取一个 PCI 视频设备的帧缓冲; 这样的缓冲常常被映射在高端物理地址, 在 内核启动时建立的页表的地址范围之外. PCI 问题在 12 章有详细解释.
由于可移植性, 值得注意的是你不应当直接存取由 ioremap 返回的地址好像是内存指针. 你应当一直使用 readb 和 其他的在第 9 章介绍的 I/O 函数. 这个要求适用因为一些平 台, 例如 Alpha, 无法直接映射 PCI 内存区到处理器地址空间, 由于在 PCI 规格和 Alpha 处理器之间的在数据如何传送方面的不同.
实际上, 一些体系结构定义"虚拟"地址为保留给寻址物理内存. 当这个发生了, Linux 内核利用这个特性, 并且
kernel 和 get_free_pages 地址都位于这些地址范围中的一个. 这个区别对设备驱动和其他的不直接包含到内存管理 内核子系统中的代码是透明的.
ioremap 和 vmalloc 是面向页的(它通过修改页表来工作); 结果, 重分配的或者分配的 大小被调整到最近的页边界. ioremap 模拟一个非对齐的映射通过"向下调整"被重映射的 地址以及通过返回第一个被重映射页内的偏移.
vmalloc 的一个小的缺点在于它无法在原子上下文中使用, 因为, 内部地, 它使用 kmalloc(GFP_KERNEL) 来获取页表的存储, 并且因此可能睡眠. 这不应当是一个问题 -- 如果 get_free_page 的使用对于一个中断处理不足够好, 软件设计需要一些清理.
标签:内存空间分配 x86 详细 use 特性 特殊 直接映射 无法 这不
原文地址:https://www.cnblogs.com/fanweisheng/p/11142129.html