Linux内核API page_address

page_address宏功能描述:page_address( )宏的功能是获得物理页的逻辑地址。page_address( )的定义有多个版本,随内核编译时配置不同而不同。在笔者的机器上,page_address( )被定义成一个宏。

page_address文件包含

#include<linux/mm.h>

page_address宏定义

在内核源码中的位置:linux-3.19.3/include/linux/mm.h

宏定义格式:

#if   ! defined(HASHED_VIRTUAL) && ! defined(WANT_PAGE_VIRTUAL)
    #define   page_address(page)   lowmem_page_address(page)
#endif

page_address输入参数说明

参数page指向一个物理页框,它是该页的描述符指针。关于结构体page的定义参考alloc_pages( )函数的分析。

page_address返回值说明

返回值是一个逻辑地址,它也是所给页的虚拟地址。

page_address实例解析

编写测试文件:page_address.c

头文件及全局变量声明如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
MODULE_LICENSE("GPL");
static int __init page_address_init(void);
static void __exit page_address_exit(void);
struct page * page = NULL;

模块初始化函数:

int __init page_address_init(void)
{
    page = alloc_pages(GFP_KERNEL, 0);  //分配一个物理页
    if(! page)
    {
        printk("alloc_pages failed! \n");
        return -ENOMEM;
    }
    else
    {
        printk("addr = 0x%lx\n", (unsigned long)page);
        printk("virtual addr = 0x%lx\n", (unsigned long)page_address(page));
                                          // 输出该page的逻辑地址
    }
    return 0;
}

模块退出函数:

void __exit page_address_exit(void)
{
    if(page)
        __free_pages(page,0);             //释放分配的物理页
    printk("exit! \n");
}

模块初始化及退出函数调用:

module_init(page_address_init);
module_exit(page_address_exit);

实例运行结果及分析:

首先编译模块,执行命令page_address.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。

Linux内核API page_address

结果分析:

在测试程序中,首先调用alloc_pages( )分配一个物理页框,由输出结果可知,该物理页框描述符的起始地址为0xffffea00014e8300,然后调用page_address( )函数获得其逻辑地址为0xffff880053a0c000。最后在模块退出时,调用__free_pages( )函数释放分配的物理页。

关于函数alloc_pages( )和__free_pages( )的功能,参考极客笔记网这两个函数的分析。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程