Linux内核之virt_to_page实现与用法实例(五十)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.Linux内核virt_to_page介绍
        • 总结
    • 🌻3.virt_to_page宏实现
      • 🐓3.1 virt_to_page宏展开过程
        • <1>.virt_to_page
        • <2>.pfn_to_page展开
        • <3>.__pfn_to_section展开
    • 🌻4.virt_to_page代码实例
      • 🐓4.1 字符设备驱动示例
      • 🐓4.2 平台设备驱动示例
      • 🐓4.3 SPI设备驱动示例

🌻1.前言

本篇目的:Linux内核之virt_to_page实现与用法实例

🌻2.Linux内核virt_to_page介绍

  • virt_to_page是Linux内核中用于将虚拟地址转换为对应的页描述符(page descriptor)的函数。在Linux内核中,每个物理内存页都有一个对应的struct page结构,该结构包含了页的详细信息,如页的状态、引用计数、映射信息等。当内核需要操作一个特定的虚拟地址时,它通常会使用virt_to_page来获取该虚拟地址对应的page结构。
  • 在Linux内核中,虚拟地址空间被划分为多个区域,如内核空间、用户空间等。每个区域内部又被划分为多个页,每页大小通常为4KB。内核使用页表来管理虚拟地址到物理地址的映射。virt_to_page函数利用这些信息来查找给定虚拟地址对应的page结构。
  • virt_to_page被调用时,它首先会检查提供的虚拟地址是否有效,即是否属于内核地址空间。如果地址有效,函数会进一步确定该地址所在的页表项,并从中提取出对应的物理页号(PFN)。PFN是物理页的一个唯一标识符。一旦PFN被确定,virt_to_page会通过PFN来查找对应的page结构。
  • page结构是内核中表示物理页的主要数据结构,它包含了页的各种属性,如页的状态(是否被分配、是否脏等)、页的访问权限、页的映射信息等。通过page结构,内核可以执行各种内存管理操作,如页的分配、释放、标记脏页以便回写等。
  • virt_to_page的使用在内核中非常普遍,尤其是在内存管理、页缓存、文件系统等模块中。例如,当内核需要访问一个特定的内核虚拟地址时,它可能会使用virt_to_page来获取对应的page结构,然后检查页的状态或执行其他操作。
  • 然而,值得注意的是,virt_to_page通常只应用于内核虚拟地址。对于用户空间虚拟地址,内核使用不同的函数来获取对应的page结构,因为用户空间的虚拟地址可能涉及到更复杂的内存管理机制,如页表共享、写时复制等。
  • virt_to_page是Linux内核中的一个关键函数,它简化了内核对虚拟地址到物理页的转换过程,使得内核能够高效地管理内存资源。
总结
  • virt_to_page 是 Linux 内核中的一个函数,它的作用是将一个虚拟地址转换为对应的 struct page 结构体指针。在 Linux 内核中,struct page 结构体用于表示物理内存页。这个函数在内核中用于管理虚拟地址和物理地址之间的映射关系,通常在内核代码中进行内存管理和页表操作时会用到。

  • 具体而言,当内核需要访问某个虚拟地址对应的物理页时,可以使用 virt_to_page 函数将虚拟地址转换为对应的 struct page 结构体指针,然后通过这个指针可以获取到物理页的相关信息,比如页面状态、页面的引用计数等。

  • 这个函数在内核的内存管理、页面交换、页面分配等方面都有着重要的作用,能够帮助内核更加高效地管理系统内存。

🌻3.virt_to_page宏实现

🐓3.1 virt_to_page宏展开过程

<1>.virt_to_page
#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
<2>.pfn_to_page展开
#define pfn_to_page __pfn_to_page

#define __pfn_to_page(pfn)				\
({	unsigned long __pfn = (pfn);			\
	struct mem_section *__sec = __pfn_to_section(__pfn);	\
	__section_mem_map_addr(__sec) + __pfn;		\
})
<3>.__pfn_to_section展开
static inline struct mem_section *__pfn_to_section(unsigned long pfn)
{
	return __nr_to_section(pfn_to_section_nr(pfn));
}

🌻4.virt_to_page代码实例

🐓4.1 字符设备驱动示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/mm.h> // 包含 virt_to_page 函数

#define DEVICE_NAME "virt_to_page_example"
#define BUF_SIZE 1024

static char buffer[BUF_SIZE];
static unsigned long vaddr = 0x12345678; // 要处理的虚拟地址

static int device_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device opened.\n");
    return 0;
}

static ssize_t device_read(struct file *file, char *buf, size_t count, loff_t *offset) {
    struct page *page_ptr = virt_to_page(vaddr); // 将虚拟地址转换为页面指针

    // 将页面内容复制到用户空间
    if (copy_to_user(buf, page_address(page_ptr), count)) {
        printk(KERN_ERR "Error copying data to user.\n");
        return -EFAULT;
    }

    return count;
}

static struct file_operations fops = {
    .open = device_open,
    .read = device_read,
};

static int __init init_module(void) {
    printk(KERN_INFO "Initializing virt_to_page example module.\n");
    register_chrdev(0, DEVICE_NAME, &fops); // 注册字符设备驱动
    return 0;
}

static void __exit cleanup_module(void) {
    printk(KERN_INFO "Cleaning up virt_to_page example module.\n");
    unregister_chrdev(0, DEVICE_NAME); // 注销字符设备驱动
}

MODULE_LICENSE("GPL");
module_init(init_module);
module_exit(cleanup_module);

🐓4.2 平台设备驱动示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/mm.h> // 包含 virt_to_page 函数

#define DRIVER_NAME "virt_to_page_platform_driver"
#define VADDR 0x87654321 // 要处理的虚拟地址

static struct resource *res;

static int my_platform_driver_probe(struct platform_device *pdev) {
    struct page *page_ptr = virt_to_page(VADDR); // 将虚拟地址转换为页面指针

    // 在这里可以使用 page_ptr 对页面进行操作

    return 0;
}

static int my_platform_driver_remove(struct platform_device *pdev) {
    return 0;
}

static struct platform_driver my_platform_driver = {
    .driver = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
    },
    .probe = my_platform_driver_probe,
    .remove = my_platform_driver_remove,
};

static int __init my_platform_driver_init(void) {
    return platform_driver_register(&my_platform_driver); // 注册平台设备驱动
}

static void __exit my_platform_driver_exit(void) {
    platform_driver_unregister(&my_platform_driver); // 注销平台设备驱动
}

MODULE_LICENSE("GPL");
module_init(my_platform_driver_init);
module_exit(my_platform_driver_exit);

🐓4.3 SPI设备驱动示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/mm.h> // 包含 virt_to_page 函数

#define DRIVER_NAME "virt_to_page_spi_driver"
#define VADDR 0xAABBCCDD // 要处理的虚拟地址

static int my_spi_probe(struct spi_device *spi) {
    struct page *page_ptr = virt_to_page(VADDR); // 将虚拟地址转换为页面指针

    // 在这里可以使用 page_ptr 对页面进行操作

    return 0;
}

static int my_spi_remove(struct spi_device *spi) {
    return 0;
}

static struct spi_driver my_spi_driver = {
    .driver = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
    },
    .probe = my_spi_probe,
    .remove = my_spi_remove,
};

static int __init my_spi_init(void) {
    return spi_register_driver(&my_spi_driver); // 注册SPI设备驱动
}

static void __exit my_spi_exit(void) {
    spi_unregister_driver(&my_spi_driver); // 注销SPI设备驱动
}

MODULE_LICENSE("GPL");
module_init(my_spi_init);
module_exit(my_spi_exit);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/553684.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 使用 pip 安装 matplotlib 模块(精华版)

pip 安装 matplotlib 模块 1.使用pip安装matplotlib(五步实现):2.使用下载的matplotlib画图: 1.使用pip安装matplotlib(五步实现): 长话短说&#xff1a;本人下载 matplotlib 花了大概三个半小时屡屡碰壁&#xff0c;险些暴走。为了不让新来的小伙伴走我的弯路&#xff0c;特意…

IPAguard--iOS代码混淆工具(免费)

IPAguard是一款为iOS开发者设计的代码混淆工具&#xff0c;旨在为开发者提供方便制作和分析马甲包的解决方案。通过高效的匹配算法&#xff0c;IPAguard可以在保证代码混淆的同时&#xff0c;保证编译后的代码质量&#xff0c;减少了因混淆引起的bug&#xff0c;使得开发者能够…

写后端项目的分页查询时,解决分页不更新

写基于VueSpringBoot项目&#xff0c;实现分页查询功能时&#xff0c;改完代码后&#xff0c;发现页数不更新&#xff1a; 更改处如下&#xff1a; 显示如图&#xff1a; 发现页数没有变化&#xff0c;两条数据还是显示在同一页&#xff0c;而且每页都10条。且重启项目也没有更…

代码随想录算法训练营第一天 | 704. 二分查找 | 27. 移除元素

704. 二分查找 int search(int* nums, int numsSize, int target) {int left 0, right numsSize, mid;while (left < right) {mid left (right -left) / 2;if (nums[mid] < target) {left mid 1;} else if (nums[mid] > target) {right mid;} else {return mid…

民兵档案管理系统-退伍军人档案管理全流程追踪

民兵档案管理系统&#xff08;智档案DW-S403&#xff09;是依托互3D技术、云计算、大数据、RFID技术、数据库技术、AI、视频分析技术对RFID智能仓库进行统一管理、分析的信息化、智能化、规范化的系统。 RFID档案管理系统是以先进的RFID技术为基础&#xff0c;结合数据库技术、…

压缩感知的概述梳理(1)

参考文献 An efficient visually meaningful image compression and encryption scheme based on compressive sensing and dynamic LSB embedding 基本内容 基本关系梳理 压缩感知核心元素 信号 x 长度&#xff1a;N动态稀疏或可用变换表示&#xff1a;x &#x1d74d;s …

AI实践与学习4_大模型之检索增强生成RAG实践

背景 针对AI解题业务场景&#xff0c;靠着ToT、CoT等提示词规则去引导模型的输出答案&#xff0c;一定程度相比Zero-shot解答质量更高&#xff08;正确率、格式&#xff09;等。但是针对某些测试CASE&#xff0c;LLM仍然不能输出期望的正确结果&#xff0c;将AI解题应用生产仍…

「不羁联盟/XDefiant」4月20号开启服务器测试,游戏预下载安装教程

XDefiant》开启Alpha测试&#xff0c;这是一款免费游玩的快节奏 FPS 竞技游戏&#xff0c;可选择特色阵营&#xff0c;搭配个性化的装备&#xff0c;体验 6v6 对抗或是线性游戏模式。高品质射击竞技端游XDefiant以6v6双边对抗为核心&#xff0c;对局模式分为区域与线性两大类&a…

LeetCode108:讲有序数组转换为平衡二叉搜索树

题目描述 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡二叉搜索树。 代码 class Solution { public:TreeNode* traversal(vector<int>& nums, int left, int right) {if (left > right) return nullptr;int …

单片机学习笔记——LED点阵

代码如下&#xff0c;注意管脚和扫描所用的hc595_write_data函数 #include "reg51.h"typedef unsigned int u16; //对系统默认数据类型进行重定义 typedef unsigned char u8;//定义74HC595控制管脚 sbit SRCLKP3^6; //移位寄存器时钟输入 sbit RCLKP3^5; //存储寄存…

Java | Leetcode Java题解之第36题有效的数独

题目&#xff1a; 题解&#xff1a; class Solution {public boolean isValidSudoku(char[][] board) {int[][] rows new int[9][9];int[][] columns new int[9][9];int[][][] subboxes new int[3][3][9];for (int i 0; i < 9; i) {for (int j 0; j < 9; j) {char …

内网代理技术总结

代理技术就是解决外网和内网的通信问题&#xff0c;例如&#xff0c;我的一个外网主机想要找到另外一个网段下的一个内网主机&#xff0c;理论上是无法找到的。如果我们想要进行通信的话就要使用代理技术。我们可以找到一个与目标内网主机在容易网段下可以通信的外网主机&#…

Android 12 如何加载 native 原生库

在 Android 7.0 及更高版本中&#xff0c;系统库与应用库是分开的。 图1. 原生库的命名空间 原生库的命名空间可防止应用使用私有平台的原生 API&#xff08;例如使用 OpenSSL&#xff09;。该命名空间还可以避免应用意外使用平台库&#xff08;而非它们自己的库&#xff09;的…

LangChain入门:22.使用 arXiv 工具开发科研助理

有一些工具&#xff0c;比如 SerpAPI&#xff0c;你已经用过了&#xff0c;这里我们再来用一下 arXiv 工具。arXiv 本身就是一个论文研究的利器&#xff0c;里面的论文数量比 AI 顶会还早、还多、还全。那么把它以工具的形式集成到 LangChain 中&#xff0c;能让你在研究学术最…

高精度PWM脉宽调制信号转模拟信号隔离变送器1Hz-10KHz转0-5V/0-10V/1-5V,0-10mA/0-20mA/4-20mA

主要特性: >>精度等级&#xff1a;0.1级。产品出厂前已检验校正&#xff0c;用户可以直接使用 >>辅助电源&#xff1a;8-32V 宽范围供电 >>PWM脉宽调制信号输入: 1Hz~10KHz >>输出标准信号&#xff1a;0-5V/0-10V/1-5V,0-10mA/0-20mA/4-20mA等&…

动手写sql 《牛客网80道sql》

第1章&#xff1a;SQL编写基础逻辑和常见问题 基础逻辑 SELECT语句: 选择数据表中的列。FROM语句: 指定查询将要从哪个表中检索数据。WHERE语句: 过滤条件&#xff0c;用于提取满足特定条件的记录。GROUP BY语句: 对结果进行分组。HAVING语句: 对分组后的结果进行条件过滤。O…

根据 Figma 设计稿自动生成 Python GUI | 开源日报 No.221

ParthJadhav/Tkinter-Designer Stars: 8.0k License: BSD-3-Clause Tkinter-Designer 是一个用于快速创建 Python GUI 的工具&#xff0c;通过使用 Figma 设计软件&#xff0c;可以轻松地生成美观的 Tkinter GUI。 主要功能和优势包括&#xff1a; 拖放界面设计比手写代码更快…

Computer Organization/Architecture 计算机组织/架构/结构 重要观念和笔记(陆续更新中,2024/04/17周三,已更新)

前情提要&#xff1a;我的说法比较白话&#xff0c;希望可以更好理解其中一些观念&#xff0c;这篇会以中文为主&#xff0c;专有名词还是用英文&#xff0c;好吧应该会中英穿插&#xff0c;自己学的时候感觉听中文会吸收比较快&#xff0c;也可能是我英文比较烂的关系&#xf…

每日算法4/17

1552. 两球之间的磁力 题目 在代号为 C-137 的地球上&#xff0c;Rick 发现如果他将两个球放在他新发明的篮子里&#xff0c;它们之间会形成特殊形式的磁力。Rick 有 n 个空的篮子&#xff0c;第 i 个篮子的位置在 position[i] &#xff0c;Morty 想把 m 个球放到这些篮子里&…

点击广告就能日赚收益1000+?开发一款看广告赚收益的APP靠谱吗?

APP对接广告变现是开发者获得收益的重要方式之一&#xff0c;对一些体量较小的APP来说&#xff0c;甚至是唯一的收益来源。开发者是否可以单独开发一款全是广告的APP&#xff0c;拿出一部分的广告收益给点击者&#xff0c;类似在快手极速版里看广告获得金币一个原理&#xff0c…