Linux内核之页面映射到虚拟地址:insert_page用法实例(六十五)

news2024/11/18 3:47:53

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

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

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

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

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.insert_page介绍
      • 🐓2.1 问题一:Linux内核中"页面"表示的含义是什么?
      • 🐓2.2 Linux物理地址和物理页面什么关系?
    • 🌻3.代码实例
      • 🐓3.1 字符设备驱动
      • 🐓3.2 网络设备驱动
      • 🐓3.3 内存映射设备驱动

🌻1.前言

本篇目的:Linux内核之页面映射到虚拟地址:insert_page用法实例

🌻2.insert_page介绍

  • insert_page() 函数是 Linux 内核中用于将页面映射到虚拟地址空间的关键函数之一。其作用是将给定的页面映射到指定的虚拟地址空间中的指定地址,并设置页面的保护标志。这个函数通常用于虚拟内存管理中,用于建立物理页面和虚拟地址之间的映射关系。

  • 在 Linux 内核中,虚拟内存管理是一项重要的任务,负责管理物理内存和虚拟地址空间之间的映射关系。这种映射关系允许进程使用虚拟地址来访问物理内存,而不需要关心物理内存的实际位置。insert_page() 函数在这个过程中扮演着重要的角色。

  • 该函数首先检查给定的页面是否是匿名页面(即不属于文件系统或设备),如果是,则表示该页面是由内核管理的,不需要进一步的处理。然后,函数会刷新给定页面的数据缓存,确保页面中的数据与内存中的一致。接下来,函数会获取给定地址的页表项,并检查该地址是否已经被映射。如果已经被映射,则函数会返回错误码,表示地址已被占用。如果地址尚未被映射,则函数会增加页面的引用计数,增加页面的计数器,并将页面添加到文件映射中,最后设置页面表项,将页面映射到指定地址。

  • 在实际使用中,insert_page() 函数通常由虚拟内存管理子系统调用,用于建立进程的虚拟地址空间和物理内存之间的映射关系。例如,在内存映射、页表操作或设备映射等场景中,可能需要使用 insert_page() 函数来实现页面的映射和管理。

  • 总的来说,insert_page() 函数在 Linux 内核中扮演着关键的角色,用于虚拟内存管理中页面的映射和管理,确保进程能够正确地访问物理内存。

🐓2.1 问题一:Linux内核中"页面"表示的含义是什么?

在操作系统的上下文中,"页面"通常指的是一块物理内存,它的大小是固定的,通常是4KB(在某些系统中可能是其他大小,比如2KB、8KB等)。
物理页面是物理内存的最小单位,操作系统使用页面作为内存管理的基本单元。

当我们说将"页面"映射到虚拟地址时,这里的"页面"确实指的是物理页面,而不是物理地址。
虚拟地址是进程中使用的地址,而物理页面是实际的物理内存单元。
虚拟地址和物理地址之间的映射关系是由操作系统的内存管理单元管理的,其中包括页表、页目录等数据结构。

因此,当我们说将页面映射到虚拟地址时,实际上是建立了虚拟地址和物理页面之间的映射关系,使得进程可以通过虚拟地址来访问相应的物理页面。在这个过程中,操作系统负责管理这种映射关系,包括分配物理页面、更新页表等操作。

🐓2.2 Linux物理地址和物理页面什么关系?

物理地址和物理页面之间是一种多对一的关系。

物理页面是物理内存的最小单位,通常是操作系统管理物理内存的基本单元。
每个物理页面都有一个唯一的地址,即物理地址,用于在内存中定位该页面的位置。
物理地址是一个特定的地址值,用于表示物理内存中的一个特定的字节。

然而,虚拟地址空间和物理内存之间的映射关系是通过页表来实现的。
页表将虚拟地址映射到物理页面上,使得进程可以通过虚拟地址来访问物理内存。
虚拟地址和物理地址之间的映射关系是一对一的,而物理页面和物理地址之间的关系是多对一的,即多个物理页面可能映射到同一个物理地址上。

因此,物理地址是用于表示物理内存中特定位置的地址。
而物理页面是用于管理和分配物理内存的基本单位。
虚拟地址通过页表映射到物理页面上,实现了进程对物理内存的访问。

🌻3.代码实例

🐓3.1 字符设备驱动

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "insert_page_char_driver"

static int char_device_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Character Device Driver: Device opened\n");
    // 在进程的虚拟地址空间中插入页面
    struct page *page = alloc_page(GFP_KERNEL);
    if (!page) {
        printk(KERN_ALERT "Character Device Driver: Failed to allocate page\n");
        return -ENOMEM;
    }
    if (insert_page(vma, addr, page, PAGE_SIZE) != 0) {
        __free_page(page);
        return -EFAULT;
    }
    return 0;
}

static struct file_operations fops = {
    .open = char_device_open,
};

static int __init char_driver_init(void) {
    printk(KERN_INFO "Character Device Driver: Initializing driver\n");
    // 注册字符设备驱动
    return register_chrdev(0, DEVICE_NAME, &fops);
}

static void __exit char_driver_exit(void) {
    unregister_chrdev(0, DEVICE_NAME);
    printk(KERN_INFO "Character Device Driver: Exiting driver\n");
}

module_init(char_driver_init);
module_exit(char_driver_exit);

MODULE_LICENSE("GPL");

🐓3.2 网络设备驱动

#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>

#define DEVICE_NAME "insert_page_net_driver"

static int net_device_open(struct net_device *dev) {
    printk(KERN_INFO "Network Device Driver: Device opened\n");
    // 在进程的虚拟地址空间中插入页面
    struct page *page = alloc_page(GFP_KERNEL);
    if (!page) {
        printk(KERN_ALERT "Network Device Driver: Failed to allocate page\n");
        return -ENOMEM;
    }
    if (insert_page(vma, addr, page, PAGE_SIZE) != 0) {
        __free_page(page);
        return -EFAULT;
    }
    return 0;
}

static const struct net_device_ops netdev_ops = {
    .ndo_open = net_device_open,
};

static int __init net_driver_init(void) {
    struct net_device *dev;
    printk(KERN_INFO "Network Device Driver: Initializing driver\n");
    // 注册网络设备驱动
    dev = alloc_netdev(0, DEVICE_NAME, NET_NAME_UNKNOWN, ether_setup);
    if (!dev) {
        printk(KERN_ALERT "Network Device Driver: Failed to allocate network device\n");
        return -ENOMEM;
    }
    dev->netdev_ops = &netdev_ops;
    register_netdev(dev);
    return 0;
}

static void __exit net_driver_exit(void) {
    struct net_device *dev = dev_get_by_name(&init_net, DEVICE_NAME);
    if (dev)
        unregister_netdev(dev);
    printk(KERN_INFO "Network Device Driver: Exiting driver\n");
}

module_init(net_driver_init);
module_exit(net_driver_exit);

MODULE_LICENSE("GPL");

🐓3.3 内存映射设备驱动

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/mm.h>

#define DEVICE_NAME "insert_page_mapping_driver"
#define BUF_SIZE    PAGE_SIZE

static char *buffer;

static int mapping_device_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Memory Mapping Device Driver: Device opened\n");
    // 在进程的虚拟地址空间中插入页面
    struct page *page = alloc_page(GFP_KERNEL);
    if (!page) {
        printk(KERN_ALERT "Memory Mapping Device Driver: Failed to allocate page\n");
        return -ENOMEM;
    }
    if (insert_page(vma, addr, page, PAGE_SIZE) != 0) {
        __free_page(page);
        return -EFAULT;
    }
    return 0;
}

static struct file_operations fops = {
    .open = mapping_device_open,
};

static int __init mapping_driver_init(void) {
    printk(KERN_INFO "Memory Mapping Device Driver: Initializing driver\n");
    // 注册内存映射设备驱动
    if (register_chrdev(0, DEVICE_NAME, &fops) < 0) {
        printk(KERN_ALERT "Memory Mapping Device Driver: Failed to register device\n");
        return -EFAULT;
    }
    return 0;
}

static void __exit mapping_driver_exit(void) {
    unregister_chrdev(0, DEVICE_NAME);
    printk(KERN_INFO "Memory Mapping Device Driver: Exiting driver\n");
}

module_init(mapping_driver_init);
module_exit(mapping_driver_exit);

MODULE_LICENSE("GPL");

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卫星通信现状与展望三 -- 6G

作者:私语茶馆 6G星地一体远景规划 中国信通院《6G总体远景与潜在关键技术白皮书》指出6G将实现地面网络、不同轨道高度上 的卫星(高中低轨卫星)以及不同空域飞行器等融合而成全新的移动信息网络,通过地面网络实现城市热点常态化覆盖,利用天基、空基网络实现偏远地…

Flink学习(九)-jar 包提交给 flink 集群执行

一、界面执行 1&#xff0c;点击左侧的 submit new job&#xff0c;然后点击add New 2&#xff0c;粘贴程序入口&#xff0c;设置并行度 3&#xff0c;执行后&#xff0c;就可以在 taskManager 中找到相关任务了 二、控制台执行 在命令行中&#xff0c;在flink 的安装目录下&…

C++ 矩阵

目录 了解矩阵的数学原理&#xff08;大学线性代数&#xff09; 矩阵及转置矩阵 矩阵乘法 矩阵快速幂 相伴矩阵模板 [相伴矩阵,快速矩阵幂]CSES1722 Fibonacci Numbers 了解矩阵的数学原理&#xff08;大学线性代数&#xff09; 矩阵及转置矩阵 这里A就是一个矩阵&…

pyqt 按钮常用格式Qss设置

pyqt 按钮常用格式Qss设置 QSS介绍按钮常用的QSS设置效果代码 QSS介绍 Qt Style Sheets (QSS) 是 Qt 框架中用于定制应用程序界面样式的一种语言。它类似于网页开发中的 CSS&#xff08;Cascading Style Sheets&#xff09;&#xff0c;但专门为 Qt 应用程序设计。使用 QSS&am…

2024 五一杯高校数学建模邀请赛(C题)| 煤矿深部开采冲击地压危险预测 |建模秘籍文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍团队独辟蹊径&#xff0c;构建了这一题的详细解答哦&#xff01; 为大家量身打造创新解决方案。小秘籍团队&#xff0c;始终引领着建模问题求解的风潮。 抓紧小秘籍&#xff0c;我们出发吧~ 让我们看看五一杯的C题&#xff01; 完…

【展会邀请】百华鞋业邀您参加2024山东省休闲旅游产业展!

2024山东省休闲旅游产业展将于4月25日—27日在临沂国际博览中心精彩亮相。本届展会由山东省旅游行业协会、山东省文化产业发展协会主办&#xff0c;山东新琅琊投资发展集团有限公司承办的2024休闲旅游产业展&#xff0c;将在临沂国际博览中心精彩亮相。山东百华鞋业将作为临沂户…

MySQL中索引的数据结构

2.3.1. 索引数据结构 索引就是能够提高查询速度的一种数据结构&#xff0c;在数据插入时就进行了排序&#xff08;会影响插入和更新的性能&#xff09;&#xff0c;索引广泛使用的是B树索引。 B树索引结构&#xff1a; 目前是基于磁盘排序效率最高的数据结构&#xff0c;树非…

Leetcode—657. 机器人能否返回原点【简单】

2024每日刷题&#xff08;121&#xff09; Leetcode—657. 机器人能否返回原点 实现代码 class Solution { public:bool judgeCircle(string moves) {int rnum 0, lnum 0, unum 0, dnum 0;for(int i 0; i < moves.size(); i) {switch(moves[i]) {case R:rnum;break;c…

Electron+Vue3+Vite+ElectronForge整合-全部ts开发 - 一键启动两个服务 一键打包两个服务

说明 本文介绍一下 Electron Vue3 Vite Electron Forge 的高级整合操作。vue3 : 使用 TS 的语法开发&#xff1b; Electron : 使用 TS 的语法开发。 补充 &#xff1a; 目前Electron的开发还是以JS为主&#xff0c;不过我们可以直接使用TS开发&#xff0c;在执行和打包时&a…

MaskFormer

This repository has been archived by the owner on Aug 30, 2023. It is now read-only.不建议复现

linux系统的rsync命令实现本机到远程主机之间目录的复制和同步

一、rsync命令介绍 在Linux中&#xff0c;rsync 是一个强大的命令行工具&#xff0c;用于同步文件和目录。它可以在本地或通过网络在远程系统之间复制文件。 二、远程目录复制的条件 1、系统要已经安装rsync工具 要使用 rsync 复制远程目录&#xff0c;需要确保系统上安装了 …

高效率的做事方法?

高效率的做事方法可以帮助我们更好地管理时间和资源&#xff0c;以下是一些建议&#xff1a; 1.明确目标和计划&#xff1a; 在开始任何任务之前&#xff0c;先明确你的目标是什么。 制定一个详细的计划&#xff0c;包括步骤、时间表和预期结果。 将任务分解成小块&#xff0…

浅谈Agent AI智能体的未来

Agent AI智能体的未来非常广阔和潜力巨大。随着技术的发展和应用场景的不断拓展&#xff0c;我们可以期待以下几个方面的发展&#xff1a; 更加智能化&#xff1a;Agent AI智能体将会变得越来越智能&#xff0c;具备更强大的学习、推理和决策能力。它们可以通过大数据和机器学习…

修改word文件的创作者方法有哪些?如何修改文档的作者 这两个方法你一定要知道

在数字化时代&#xff0c;文件创作者的信息往往嵌入在文件的元数据中&#xff0c;这些元数据包括创作者的姓名、创建日期以及其他相关信息。然而&#xff0c;有时候我们可能需要修改这些创作者信息&#xff0c;出于隐私保护、版权调整或者其他实际需求。那么&#xff0c;有没有…

Linux系统启动Canal错误

说明&#xff1a;记录在Linux系统&#xff08;Cent OS 7&#xff09;中使用Canal的错误&#xff1b; 场景 将下载的Canal包解压&#xff0c;启动Canal时&#xff0c;Canal没有启动&#xff0c;如下&#xff1a; 分析&#xff1a;hs_err_pid13418.log是JVM运行异常生成的日志文…

SDKMAN!

概述 官网&#xff0c;SDKMAN是一款管理多版本SDK的工具&#xff0c;可以实现在多个版本间的快速切换。 其他特性&#xff1a; 易用&#xff1a;安装SDK不再需要去Google想安装的某个软件的官网的下载页&#xff0c;或找其他下载页面&#xff0c;然后下载安装包、解压、设置…

Apollo Dreamview+之播放离线数据包

前提条件 完成 Dreamview 插件安装&#xff0c;参见 Studio 插件安装 。 操作步骤 您可以通过包管理和源码两种方式快速体验离线数据包播放操作。其中进入 docker 环境和启动 dreamview 的命令有所区别&#xff0c;请您按照命令进行操作。 步骤一&#xff1a;启动并打开 Dr…

踏上R语言之旅:解锁数据世界的神秘密码(三)

多元相关与回归分析及R使用 文章目录 多元相关与回归分析及R使用一.变量间的关系分析1.两变量线性相关系数的计算2.相关系数的假设检验 二.一元线性回归分析的R计算三、回归系数的假设检验总结 一.变量间的关系分析 变量间的关系及分析方法如下&#xff1a; 1.两变量线性相关…

openlayer 使用ol-ext插件实现凸显区域

使用ol-ext插件实现凸显多变形 效果如图 1、创建openlayer var map; var view; var tileLayer, source, vector;function init() {tileLayer new ol.layer.Tile({source: new ol.source.TileArcGISRest({url: "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStr…

java 远程debug

java -agentlib:jdwptransportdt_socket,servery,suspendn,address50050 -Xmx1536m -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath./ -jar ${JAR_NAME} >/dev/null 2>&1 &参数说明 -agentlib:jdwptransportdt_socket,servery,suspendn,address50050: 这个参数…