You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AArch64 Linux内核模块内存别名映射失败问题咨询

AArch64内核内存别名映射失效问题排查与修复

在AArch64架构下开发Linux内核模块时,目标是为4个物理页创建1024个虚拟页的循环别名映射(每4个虚拟页共享同一个物理页),但实际测试中写入不同虚拟别名地址后读取结果不一致,别名映射未生效。以下是问题排查与修复方案:


一、测试代码的直接错误

你当前的测试地址访问逻辑存在严重偏差:

// 错误:将虚拟地址视为指针数组,访问的是第0个指针元素(偏移量为0 * sizeof(char*))
((char**)v->addr)[0] = ...;
// 错误:访问的是第PAGE_SIZE*4个指针元素(偏移量为 PAGE_SIZE*4 * sizeof(char*))
((char**)v->addr)[PAGE_SIZE*4] = ...;

正确的访问方式应将虚拟地址视为字节数组,直接访问目标偏移的字节:

// 访问第0个虚拟页的第0字节
((char*)v->addr)[0] = 0x12;
// 访问第4个虚拟页的第0字节(对应同一个物理页)
((char*)v->addr)[PAGE_SIZE * 4] = 0x34;
// 验证结果
printk(KERN_INFO "addr[0] = 0x%x, addr[4*PAGE_SIZE] = 0x%x\n",
       ((char*)v->addr)[0], ((char*)v->addr)[PAGE_SIZE * 4]);

这是导致你看到结果不一致的核心原因之一——你并未访问到预期的虚拟页位置。


二、map_one_page函数的问题与修正

当前的页表遍历和映射逻辑存在不符合AArch64内核规范的地方,修正后的函数如下:

static int map_one_page(unsigned long va, struct page *page) {
    pgd_t *pgd;
    p4d_t *p4d;
    pud_t *pud;
    pmd_t *pmd;
    pte_t *pte;
    int err = 0;

    // 使用内核专属的页表偏移宏,替代init_mm相关的偏移
    pgd = pgd_offset_k(va);
    if (pgd_none(*pgd))
        return -ENOMEM;

    err = __p4d_alloc(&init_mm, pgd, va);
    if (err)
        return err;
    p4d = p4d_offset(pgd, va);

    err = __pud_alloc(&init_mm, p4d, va);
    if (err)
        return err;
    pud = pud_offset(p4d, va);

    err = __pmd_alloc(&init_mm, pud, va);
    if (err)
        return err;
    pmd = pmd_offset(pud, va);

    err = __pte_alloc_kernel(pmd, va);
    if (err)
        return err;
    pte = pte_offset_kernel(pmd, va);

    // 构建PTE并显式确保可写属性(PAGE_KERNEL默认包含,但显式确认更安全)
    pte_t entry = pfn_pte(page_to_pfn(page), PAGE_KERNEL);
    entry = pte_mkwrite(entry);

    // 安装PTE,内核地址场景下使用&init_mm是合规的
    set_pte_at(&init_mm, va, pte, entry);

    // 刷新TLB,确保新映射立即生效
    flush_tlb_kernel_range(va, va + PAGE_SIZE);
    return 0;
}

关键修正点:

  1. 页表遍历方式:用pgd_offset_k(va)替代pgd_offset(init_mm_ptr, va),这是AArch64内核虚拟地址页表遍历的标准方式,避免依赖用户空间的init_mm描述符带来的潜在问题。
  2. PTE属性确认:显式调用pte_mkwrite确保映射具备可写权限,避免因内核配置差异导致的权限不足。
  3. 函数指针有效性:确保__p4d_alloc、__pud_alloc等函数指针正确指向内核原生实现,否则页表项分配会失败,映射无法建立。

三、其他注意事项

  • 虚拟地址空间校验:确保get_vm_area_fn返回的area->addr不为NULL,确认1024页的连续虚拟地址空间分配成功。
  • 内存泄漏防护:模块卸载时需释放物理页和虚拟地址空间:
    for (int i = 0; i < 4; i++)
        if (frames[i])
            __free_page(frames[i]);
    if (area)
        vfree(area->addr);
    
  • 硬件兼容性:部分嵌入式AArch64平台可能限制内存别名映射,需确认目标平台MMU配置允许该操作。

内容的提问来源于stack exchange,提问作者Gal Kaptsenel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 09:54:53