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

如何在内核模块中创建页对齐缓冲区并获取其物理地址?

内核模块中创建页对齐缓冲区并获取物理地址的方法

一、创建页对齐缓冲区的可靠方法

内核提供了专门的内存分配接口来保证页对齐,以下是几种常用方式:

  • 使用__get_free_pages()/get_free_pages()
    这两个函数直接分配连续的物理页,返回的虚拟地址天然是页对齐的。__get_free_pages()是无锁版本,适合中断上下文;get_free_pages()带锁,适合进程上下文。
    示例代码:

    // 分配1个物理页(大小为PAGE_SIZE),GFP_KERNEL为分配掩码
    char *buf = (char *)__get_free_pages(GFP_KERNEL, 0);
    if (!buf) {
        // 分配失败处理
        return -ENOMEM;
    }
    
    // 若需要N个连续页,第二个参数为order(2^order个页),比如分配2个页:
    // char *buf = (char *)__get_free_pages(GFP_KERNEL, 1);
    
    // 使用完后释放内存
    // free_pages((unsigned long)buf, order);
    
  • 使用alloc_pages() + page_address()
    先获取struct page结构体指针,再转换为虚拟地址,适合需要直接操作页结构体的场景:

    // 分配1个物理页
    struct page *page = alloc_pages(GFP_KERNEL, 0);
    if (!page) {
        return -ENOMEM;
    }
    char *buf = page_address(page);
    
    // 释放内存
    // __free_pages(page, 0);
    
  • kmalloc()的页对齐用法(限小内存)
    如果缓冲区大小小于等于PAGE_SIZE,也可以用kmalloc()配合对齐掩码强制页对齐,但这种方式不如页分配函数直接可靠:

    char *buf = kmalloc(BUF_LEN, GFP_KERNEL | __GFP_ALIGN_MASK);
    

二、获取物理地址的正确方式

对于上述页对齐的缓冲区,获取物理地址推荐以下两种方式:

  • 通过struct page获取(最稳妥)
    如果持有struct page指针,直接用page_to_phys()转换:

    phys_addr_t phys_addr = page_to_phys(page);
    

    如果只有虚拟地址,可先通过virt_to_page()转换为struct page:

    struct page *page = virt_to_page(buf);
    phys_addr_t phys_addr = page_to_phys(page);
    
  • 关于virt_to_phys()的说明
    内核模块中的静态变量(如你原来的static char buf[BUF_LEN])位于线性映射区,virt_to_phys()确实可以转换其虚拟地址到物理地址,但静态数组无法保证页对齐,即便转换成功也不符合需求。对于页分配函数得到的虚拟地址,virt_to_phys()同样有效,但page_to_phys()兼容性更好,更推荐使用。

总结

你原来的静态数组无法保证页对齐,必须改用内核的页分配接口(如__get_free_pages()或alloc_pages())创建缓冲区,再通过page_to_phys()获取物理地址,就能满足SVSM环境对页对齐物理地址的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 23:35:02