vmalloc_to_page 及相关的 page 系列函数

2024-12-04 150 0

在 Linux 内核中,vmalloc_to_page 及相关的 page 系列函数用于处理内核虚拟地址与物理页的映射关系。这些函数在管理 vmalloc 分配的虚拟地址、访问物理页以及操作页表时非常重要。以下是对这些函数的详细解析。

vmalloc_to_page

vmalloc_to_page 是一个内核函数,用于将 vmalloc分配的虚拟地址转换为其对应的物理页。

定义

struct page *vmalloc_to_page(const void *vmalloc_addr);

参数

vmalloc_addr: 由 vmalloc 分配的虚拟地址。

返回值

对应的 struct page 结构,表示该虚拟地址对应的物理页。

工作原理

vmalloc 分配的虚拟地址是虚拟连续但物理上可能不连续的。
vmalloc_to_page 会遍历页表,找到虚拟地址对应的物理页。

示例

#include <linux/vmalloc.h>
#include <linux/mm.h>

void example_vmalloc_to_page(void)
{
    void *buffer = vmalloc(1024 * 1024);  // 分配 1 MB 虚拟连续内存
    if (!buffer) {
        printk(KERN_ERR "vmalloc failed\n");
        return;
    }

    // 将 buffer 的一个虚拟地址转换为物理页
    struct page *page = vmalloc_to_page(buffer);
    if (page) {
        printk(KERN_INFO "Physical page frame number: %lu\n", page_to_pfn(page));
    }

    vfree(buffer);  // 释放内存
}

virt_to_page

virt_to_page 将内核直接映射的虚拟地址转换为对应的物理页。

定义

struct page *virt_to_page(const void *kaddr);

参数

kaddr: 内核直接映射的虚拟地址。

返回值

对应的 struct page 结构。

限制

只能用于内核直接映射区域(即物理地址和虚拟地址之间简单偏移的区域,例如 kmalloc 分配的内存)。 不能用于 vmalloc 分配的地址,因为 vmalloc 使用的是虚拟连续地址,映射方式不同。

示例

void example_virt_to_page(void)
{
    void *buffer = kmalloc(4096, GFP_KERNEL);  // 分配 4 KB 内存
    if (!buffer) {
        printk(KERN_ERR "kmalloc failed\n");
        return;
    }

    struct page *page = virt_to_page(buffer);
    printk(KERN_INFO "Page frame number: %lu\n", page_to_pfn(page));

    kfree(buffer);  // 释放内存
}

pfn_to_page

pfn_to_page 将物理页帧号PFN转换为 struct page

定义

struct page *pfn_to_page(unsigned long pfn);

参数

pfn: 物理页帧号。

返回值

对应的 struct page 结构。

示例

void example_pfn_to_page(void)
{
    unsigned long pfn = 0x12345;  // 示例页帧号
    struct page *page = pfn_to_page(pfn);
    printk(KERN_INFO "Page address: %p\n", page);
}

page_to_pfn

page_to_pfnstruct page 转换为物理页帧号。

定义

unsigned long page_to_pfn(const struct page *page);

参数

page: struct page 结构。

返回值

物理页帧号。

示例

void example_page_to_pfn(void)
{
    struct page *page = alloc_page(GFP_KERNEL);  // 分配一个页
    if (!page) {
        printk(KERN_ERR "alloc_page failed\n");
        return;
    }

    unsigned long pfn = page_to_pfn(page);
    printk(KERN_INFO "Physical frame number: %lu\n", pfn);

    __free_page(page);  // 释放页
}

page_address

page_addressstruct page 转换为内核直接映射的虚拟地址。

定义

void *page_address(const struct page *page);

参数

page: struct page 结构。

返回值

内核直接映射的虚拟地址。

限制

只能用于内核直接映射区域,不适用于 vmalloc 地址。

示例

void example_page_address(void)
{
    struct page *page = alloc_page(GFP_KERNEL);  // 分配一个页
    if (!page) {
        printk(KERN_ERR "alloc_page failed\n");
        return;
    }

    void *addr = page_address(page);
    printk(KERN_INFO "Direct-mapped virtual address: %p\n", addr);

    __free_page(page);  // 释放页
}

函数适用场景对比

函数名 输入 输出 适用场景
vmalloc_to_page vmalloc 分配的虚拟地址 对应的物理页 (struct page) 用于访问 vmalloc 地址对应的物理页
virt_to_page 内核直接映射的虚拟地址 对应的物理页 (struct page) 用于 kmalloc 等内存分配的地址
pfn_to_page 物理页帧号 (PFN) 对应的物理页 (struct page) PFN 转换到 struct page
page_to_pfn struct page 对应的物理页帧号 struct page 获取物理地址
page_address struct page 内核直接映射的虚拟地址 获取页的直接映射虚拟地址

总结

vmalloc_to_page 是专门为 vmalloc 地址设计的,可以获取虚拟地址对应的物理页。 virt_to_pagepage_address 主要用于直接映射区域(如 kmalloc 分配的内存)。 pfn_to_pagepage_to_pfn 提供页帧号与 struct page 的相互转换。 根据具体内存分配方式和需求,选择合适的函数操作页表或物理页结构。

相关文章

发布评论