Linux 内核内存管理 virt_to_page 函数

这篇具有很好参考价值的文章主要介绍了Linux 内核内存管理 virt_to_page 函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

一、virt_to_page

virt_to_page宏根据内核虚拟地址返回其struct page 结构体指针。

x86_64:

// linux-5.4.18/arch/x86/include/asm/page.h

/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT	12
#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)

virt_to_page(kaddr) 宏通过__pa宏将虚拟地址转换为物理地址,然后右移PAGE_SHIFT(12位)位将物理地址转换为页帧号pfn,最后调用pfn_to_page将页帧号pfn转换为struct page 结构体指针,实现了将虚拟地址转换为对应struct page结构体指针的功能。

内核虚拟起始地址 --> 物理页面的物理起始地址 --> 页帧号pfn --> struct page 

其中__pa宏用来内核虚拟地址转化为物理地址:

// linux-5.4.18/arch/x86/include/asm/page_64.h

static inline unsigned long __phys_addr_nodebug(unsigned long x)
{
	unsigned long y = x - __START_KERNEL_map;

	/* use the carry flag to determine if x was < __START_KERNEL_map */
	x = y + ((x > y) ? phys_base : (__START_KERNEL_map - PAGE_OFFSET));

	return x;
}

#define __phys_addr(x)		__phys_addr_nodebug(x)

#define __pa(x)		__phys_addr((unsigned long)(x))

aarch64:

#if defined(CONFIG_SPARSEMEM_VMEMMAP)

#define virt_to_page(x)	({						\
	u64 __idx = (__tag_reset((u64)x) - PAGE_OFFSET) / PAGE_SIZE;	\
	u64 __addr = VMEMMAP_START + (__idx * sizeof(struct page));	\
	(struct page *)__addr;						\
})

二、demo

测试平台:centos 7 x86_64

# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mm_types.h>
# include <linux/mm.h>
# include <linux/gfp.h>

//内核模块初始化函数
static int __init lkm_init(void)
{
    //调用伙伴系统接口分配 2^2 = 4 个连续的物理页,返回其内核虚拟起始地址
    unsigned long virt_address = __get_free_pages(GFP_KERNEL, 2);

    printk("virtual addr = 0x%lx\n", virt_address);
    printk("sizeof(struct page) = 0x%lx\n", sizeof(struct page));

    int i;
    for(i = 0; i < 4; i++ ){
        unsigned long virt_address_1 = virt_address + i * 4096;
        unsigned long phys_address_1 = __pa(virt_address_1);
        unsigned int pfn_1 = __phys_to_pfn(phys_address_1);
        struct page *page_1 = pfn_to_page(pfn_1);

        struct page *page_2 = virt_to_page(virt_address_1);
        printk("virt_address = 0x%lx, phys_address = 0x%lx, pfn = %d, struct page address = 0x%p, struct page address = 0x%p\n",
                virt_address_1, phys_address_1,pfn_1, page_1, page_2);
    }

    free_pages(virt_address, 2);

    return 0;

}

//内核模块退出函数
static void __exit lkm_exit(void)
{
	printk("Goodbye\n");
}


module_init(lkm_init);
module_exit(lkm_exit);

MODULE_LICENSE("GPL");

结果展示:

[199302.056485] virtual addr = 0xffff9d991cbd0000
[199302.056491] sizeof(struct page) = 0x40
[199302.056498] virt_address = 0xffff9d991cbd0000, phys_address = 0x5cbd0000, pfn = 379856, struct page address = 0xffffe2784172f400, struct page address = 0xffffe2784172f400
[199302.056504] virt_address = 0xffff9d991cbd1000, phys_address = 0x5cbd1000, pfn = 379857, struct page address = 0xffffe2784172f440, struct page address = 0xffffe2784172f440
[199302.056509] virt_address = 0xffff9d991cbd2000, phys_address = 0x5cbd2000, pfn = 379858, struct page address = 0xffffe2784172f480, struct page address = 0xffffe2784172f480
[199302.056514] virt_address = 0xffff9d991cbd3000, phys_address = 0x5cbd3000, pfn = 379859, struct page address = 0xffffe2784172f4c0, struct page address = 0xffffe2784172f4c0

可以看到当通过伙伴系统接口申请连续的物理内存,每个物理页内核虚拟地址连续,物理地址连续,相差4096(0x1000),即页帧号也连续,相差1。struct page结构体也要占用实际的物理内存,其物理内存地址也连续,相差0x40。

参考资料

Linux 5.4.18

https://blog.csdn.net/hu1610552336/article/details/113083454文章来源地址https://www.toymoban.com/news/detail-651723.html

到了这里,关于Linux 内核内存管理 virt_to_page 函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入理解Linux内核——内存管理(3)

    提要:本系列文章主要参考 MIT 6.828课程 以及两本书籍 《深入理解Linux内核》 《深入Linux内核架构》 对Linux内核内容进行总结。 内存管理的实现覆盖了多个领域: 内存中的物理内存页的管理 分配大块内存的伙伴系统 分配较小内存的slab、slub、slob分配器 分配非连续内存块的

    2024年02月13日
    浏览(47)
  • Linux内核内存分配函数kmalloc、kzalloc和vmalloc

    在内核环境中,常用的内存分配函数主要有kmalloc、kzalloc和vmalloc这三个。既然这三函数都能在内核申请空间,那么这三个函数有什么区别呢?如何选用呢? 首先是kmalloc,其函数原型为 函数的特点: 申请的内存 虚拟地址和物理地址都是连续 的,允许申请的内存大小较小,具

    2024年02月16日
    浏览(39)
  • arm64内核内存布局-之vmemmap(page初始化)

            vmemmap是内核中page 数据的虚拟地址。针对sparse内存模型。内核申请page获取的page地址从此开始。 section的概念: SPARSEMEM内存模型引入了section的概念,可以简单将它理解为struct page的集合(数组)。内核使用struct mem_section去描述section,定义如下: 其中的section_mem_map成员

    2024年02月15日
    浏览(47)
  • 【嵌入式环境下linux内核及驱动学习笔记-(10-内核内存管理)】

    对于包含MMU(内存管理单元)的处理器而言,linux系统以虚拟内存的方式为每个进程分配最大4GB的内存。这真的4GB的内存空间被分为两个部分–用户空间 与 内核空间。用户空间地地址分布为0~3GB,剩下的3 ~ 4GB 为内核空间。如下图。 用户进程通常只能访问用户空间的虚拟地址

    2024年02月11日
    浏览(58)
  • 深入理解Linux内核——内存管理(4)——伙伴系统(1)

    提要:本系列文章主要参考 MIT 6.828课程 以及两本书籍 《深入理解Linux内核》 《深入Linux内核架构》 对Linux内核内容进行总结。 内存管理的实现覆盖了多个领域: 内存中的物理内存页的管理 分配大块内存的伙伴系统 分配较小内存的slab、slub、slob分配器 分配非连续内存块的

    2024年02月10日
    浏览(53)
  • 深入分析linux内核的内存分配函数devm_kzalloc

    在分析驱动代码的时候,经常会遇到使用devm_kzalloc()为一个设备分配一片内存的情况。devm_kzalloc()是内核用来分配内存的函数,同样可以分配内存的内核函数还有devm_kmalloc, kzalloc, kmalloc。它们之间的区别在于devm_XXX分配的内存可以跟设备进行绑定,当设备跟驱动分离时,跟设备

    2024年02月02日
    浏览(42)
  • 【Linux 内核源码分析】内存管理——Slab 分配器

    在Linux内核中,伙伴分配器是一种内存管理方式,以页为单位进行内存的管理和分配。但是在内核中,经常会面临结构体内存分配问题,而这些结构体的大小通常是小于一页的。如果使用伙伴分配器来分配这些小内存,将造成很大的内存浪费。因此,为了解决这个问题,Sun公

    2024年02月22日
    浏览(60)
  • Linux内核中内存管理相关配置项的详细解析5

    接前一篇文章:Linux内核中内存管理相关配置项的详细解析4 对应配置变量为:CONFIG_SHUFFLE_PAGE_ALLOCATOR。 此项只有选中和不选中两种状态,默认为选中。 此项的内核源码详细解释为: Randomization of the page allocator improves the average utilization of a direct-mapped memory-side-cache. See section 5

    2024年02月08日
    浏览(41)
  • Linux内核中内存管理相关配置项的详细解析15

    接前一篇文章:Linux内核中内存管理相关配置项的详细解析14 对应配置变量为:CONFIG_PTE_MARKER_UFFD_WP。 此项只有选中和不选中两种状态,默认为选中。 此项的内核源码详细解释为: Allows to create marker PTEs for userfaultfd write protection purposes. It is required to enable userfaultfd write protecti

    2024年02月08日
    浏览(45)
  • Netty内存管理--Chunk&Page

    1. Netty网络应用基础 2. Java I/O 3. IO/模型 4. 网络应用编解码 5. Netty Pipeline 6. Netty EventLoopGroupEventLoop 7. Netty ThreadLocalFastThreadLocal 8. Netty FuturePromise 9. Netty内存管理–(旧)PoolChunk伙伴分配 10. Netty内存管理–内存池空间规格化SizeClasses 11. Netty内存管理–PoolChunkPoolSubPage 12. Netty内存管理

    2023年04月21日
    浏览(95)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包