深入浅出内存管理--高端内存映射之fixmap(固定映射)

本文深入探讨Linux内核中的fixmap机制,这是一种用于高端内存映射的方法,尤其适用于中断上下文。与pkmap不同,fixmap不会因映射区满而阻塞,而是覆盖现有映射,确保每次调用都能成功执行。文章详细解析了fixmap的实现原理,包括其入口函数kmap_atomic的工作流程,以及如何通过固定类型索引访问映射页面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们知道系统中的高端内存是不能作为直接映射区映射到内核空间的,那么我们想要使用它怎么办呢?前面的文章我们已经有过相关的介绍,可以使用三种方法,分别是pkmap(永久映射)/fixmap(临时固定映射)/vmlloc,本文主要介绍fixmap,也就是固定映射又叫临时映射。

关键点

通过前面的介绍我们知道,fixmap和pkmap的最大区别是fixmap不会被阻塞,因此可以在中断上下文中使用。那会不会遇到一个问题呢?pkmap在申请映射时发现映射区已经被申请完了所以才会阻塞等待,那么fixmap如何处理这种场景呢?实际上每次fixmap都是可以成功执行映射的,原因是fixmap不会动态申请映射,它是以固定映射的方式进行的,如果我们传入了一个映射type,它就肯定会执行对应的映射,而把之前的映射冲刷掉,因此fixmap的映射关系是靠内核代码来进行维护的,所以内核需要保证同一个映射区不被重复使用,从而出现错误。

入口函数

kmap_atomic:

  void *kmap_atomic(struct page *page)
 {
     unsigned int idx;
     unsigned long vaddr;
     void *kmap;
     int type;
 
     pagefault_disable();
     if (!PageHighMem(page))
         return page_address(page);
 
 #ifdef CONFIG_DEBUG_HIGHMEM
     /*
      * There is no cache coherency issue when non VIVT, so force the
      * dedicated kmap usage for better debugging purposes in that case.
      */
     if (!cache_is_vivt())
         kmap = NULL;
     else
 #endif
         kmap = kmap_high_get(page);
     if (kmap)
         return kmap;
 
     type = kmap_atomic_idx_push();
 
     idx = type + KM_TYPE_NR * smp_processor_id();
     vaddr = __fix_to_virt(idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
    /*
     * With debugging enabled, kunmap_atomic forces that entry to 0.
     * Make sure it was indeed properly unmapped.
     */
    BUG_ON(!pte_none(get_fixmap_pte(vaddr)));
#endif
    /*
     * When debugging is off, kunmap_atomic leaves the previous mapping
     * in place, so the contained TLB flush ensures the TLB is updated
     * with the new mapping.
     */
    set_fixmap_pte(idx, mk_pte(page, kmap_prot));

    return (void *)vaddr;
}

内核中为每个CPU定义了KM_TYPE_NR个fixmap页面,每个页面地址用一个type来表示,那么我们寻找一个对应type的地址时可以使用如下方式:


#define KM_TYPE_NR 16

 idx = type + KM_TYPE_NR * smp_processor_id();
 vaddr = __fix_to_virt(idx);

内核中对type在linux-4.0版本中没有明确的定义,只是通过如下方式进行了获取,实际上时按照调用顺序来进行分配的。

 DECLARE_PER_CPU(int, __kmap_atomic_idx);
 
 static inline int kmap_atomic_idx_push(void)
 {
     int idx = __this_cpu_inc_return(__kmap_atomic_idx) - 1;
 
 #ifdef CONFIG_DEBUG_HIGHMEM
     WARN_ON_ONCE(in_irq() && !irqs_disabled());
     BUG_ON(idx >= KM_TYPE_NR);
 #endif
     return idx;
 }   

<think>好的,用户想了解物理内存中的高端地址相关概念和配置,尤其是分配与管理。我需要结合提供的引用资料来整理答案。首先,根据引用[3],高端物理内存指的是超过内核直接映射区域的物理内存,也就是在32位系统中高于896MB的部分。这时候内核无法直接访问,必须通过动态映射,比如vmalloc或者固定映射。 接下来,用户可能想知道高端地址的分配方式。引用[3]提到,vmalloc用于分配虚拟地址连续但物理地址不一定连续的内存,而kmalloc则保证物理连续。由于高端内存无法直接映射,所以通常使用vmalloc或类似的机制。同时,引用[4]提到伙伴系统和slab分配器,但伙伴系统处理的是较大块的物理内存,可能用于高端内存的分页。而slab可能用于小对象,但kmalloc可能不适用于高端内存,因为它需要物理连续。 另外,引用[2]提到NUMA节点的例子,每个节点有1TB内存,分布在4个节点上,地址空间分散。这说明高端内存管理在NUMA架构中更为复杂,可能需要考虑节点的本地内存分配,减少跨节点访问延迟。 管理机制方面,伙伴系统负责大块内存的分配和释放,避免外部碎片,而slab处理小块,解决内部碎片。但在高端内存中,可能需要非连续分配,如vmalloc,这会导致页表项增多,影响性能,如引用[3]所说,TLB抖动的问题。因此内核优先使用kmalloc,但高端情况下只能用vmalloc。 用户可能还关心如何配置,比如在32位系统中如何管理超过896MB的内存,或者64位系统中是否还存在高端内存的问题。根据资料,64位系统因为地址空间巨大,可能没有高端内存的概念,但实际中可能仍有类似机制处理稀疏地址。 最后,需要总结优缺点,比如非连续分配带来的灵活性和性能损耗,以及配置时的注意事项,如避免频繁使用vmalloc,优化内存访问模式等。同时,生成相关问题时要覆盖碎片处理、NUMA影响、分配器区别和应用场景。</think>### 物理内存中高端地址的分配与管理 #### 1. 高端地址的概念 在Linux内存管理中,**高端物理内存(High Memory)** 指超出内核直接线性映射区域的物理内存。在32位系统中,由于虚拟地址空间限制(通常内核仅能直接映射约896MB的物理内存),超过该范围的物理内存被称为高端内存[^3]。 在64位系统中,虚拟地址空间极大(如256TB),理论上无需高端内存概念,但仍可能通过稀疏映射方式管理大容量物理内存[^2]。 #### 2. 高端内存的分配方式 - **非连续内存分配(vmalloc)** 通过`vmalloc`函数分配虚拟地址连续但物理地址不连续的内存区域。例如: ```c void *addr = vmalloc(1024 * 1024); // 分配1MB非连续物理内存 ``` 此方式需动态建立页表映射,可能导致TLB抖动,性能低于直接映射[^3]。 - **固定映射Fixmap)** 内核为临时访问高端内存预留的固定虚拟地址区域,适用于短期操作(如硬件寄存器访问)。 - **伙伴系统与NUMA优化** 在NUMA架构中,物理内存分散于不同节点。伙伴系统通过`alloc_pages`函数从特定NUMA节点分配高端内存页,减少跨节点访问延迟。 #### 3. 管理机制与挑战 - **页表映射开销** 高端内存需动态维护虚拟地址到物理地址的映射,增加了页表项管理复杂度。例如,4KB页面的映射需逐项更新页表。 - **碎片问题** - **外部碎片**:伙伴系统通过合并空闲页减少外部碎片,但高端内存可能因频繁分配/释放导致碎片化[^4]。 - **内部碎片**:Slab分配器优化小于4KB的内存请求,但高端内存中仍需按页分配[^4]。 - **性能权衡** `kmalloc`(物理连续)适用于频繁访问场景(如DMA缓冲区),而`vmalloc`(物理非连续)适合大块但访问频率低的内存(如模块加载)。 #### 4. 配置实践 - **32位系统配置** 通过内核编译选项`CONFIG_HIGHMEM`启用高端内存支持,调整`highmem`参数分配高端内存比例。 - **64位系统优化** 利用稀疏地址映射(如`SPARSEMEM`模型)管理物理内存,支持TB级内存高效分配[^2]。 #### 5. 优缺点总结 | **优点** | **缺点** | |------------------------------|------------------------------| | 支持大容量物理内存访问 | 映射开销大,TLB抖动显著 | | 灵活适应非连续物理内存需求 | 碎片问题可能影响分配效率 | | 适配NUMA架构,减少访问延迟 | 需权衡分配策略与性能 | ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值