Linux内核之临时映射内核内存:kmap_atomic用法实例(六十二)

news2024/12/27 13:56:30

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

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

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

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

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.介绍
      • 2.2.1 🐥 `kmap_atomic函数`
      • 2.2.2 🐥 `kunmap_atomic`
      • 2.2.3 🐥 用法场景
      • 2.2.4 🐥 注意问题
    • 🌻3.代码实例
      • 🐓3.1 kmap_atomic和kunmap_atomic读写页表项
      • 🐓3.2 中断上下文中使用kmap_atomic和kunmap_atomic
      • 🐓3.3 kmap_atomic和kunmap_atomic在内核中处理DMA缓冲区

🌻1.前言

本篇目的:Linux内核之临时映射内核内存:kmap_atomic用法实例

🌻2.介绍

  • kmap_atomic 和 kunmap_atomic 是 Linux 内核中用于在驱动程序中临时映射内核内存的函数。
  • 它们通常用于驱动程序中需要在中断上下文中访问内核内存时。

2.2.1 🐥 kmap_atomic函数

kmap_atomic 函数用于将给定的页面映射到内核虚拟地址空间中。这个映射是临时的,并且是为了在执行操作后立即解除映射。它在执行期间对内存区域进行了加锁,以避免其他代码修改它。
这个函数通常在驱动程序中的中断上下文中使用,因为在中断上下文中无法直接访问用户空间的内存,所以需要将需要访问的内存映射到内核空间。
使用 kmap_atomic 函数后,驱动程序可以使用返回的内核虚拟地址来访问页面的内容。

2.2.2 🐥 kunmap_atomic

kunmap_atomic 函数用于解除 kmap_atomic 函数创建的临时映射。它通常在完成对内存的访问后调用,以释放内核虚拟地址空间。
在调用 kunmap_atomic 之后,内存页面将不再映射到内核虚拟地址空间,因此不能再使用返回的指针进行访问。
解除映射后,页面可以自由地由内核重新分配或者进行其他操作。

2.2.3 🐥 用法场景

kmap_atomickunmap_atomic通常用于以下场景:

  1. 中断处理程序:当硬件中断触发,中断处理程序需要快速访问高端内存中的数据结构时,可以使用这两个函数。
  2. 软中断和任务let:在执行软中断或任务let时,如果需要访问高端内存,同样可以使用这两个函数。
  3. 底半部处理程序:底半部处理程序通常在原子上下文中执行,因此也需要使用这些函数来访问高端内存。

2.2.4 🐥 注意问题

  • 尽管kmap_atomickunmap_atomic为访问高端内存提供了一种便捷的方式,但它们的使用需要非常小心,因为不当的使用可能会导致系统不稳定。例如,如果在映射后没有及时取消映射,可能会导致映射槽耗尽,进而影响系统的正常运行。此外,由于映射是临时的,因此不能依赖于这些映射在长时间内保持有效。
  • 在非原子上下文中,Linux内核提供了其他机制来映射和取消映射高端内存,如kmapkunmap,它们允许睡眠,并且更适合在进程上下文中使用。
  • kmap_atomickunmap_atomic是Linux内核中用于在原子上下文中临时映射和取消映射高端内存页的关键函数。它们为内核提供了一种在不能睡眠的情况下访问高端内存的机制,但使用时需要谨慎,以避免潜在的系统稳定性问题。

🌻3.代码实例

🐓3.1 kmap_atomic和kunmap_atomic读写页表项

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>

static int __init kmap_example_init(void)
{
    unsigned long phys_addr = 0x100000; // 物理地址
    pgd_t *pgd;
    pte_t *pte;
    unsigned long *virt_addr;
    unsigned long page_num;
    
    // 获取对应物理地址的页面框号
    page_num = phys_addr >> PAGE_SHIFT;
    
    // 通过物理地址找到对应的页表项
    pgd = pgd_offset_k(phys_addr);
    if (pgd_none(*pgd) || pgd_bad(*pgd)) {
        pr_err("Invalid pgd\n");
        return -EINVAL;
    }
    
    pte = pte_offset_kernel(pgd, phys_addr);
    if (!pte || pte_none(*pte)) {
        pr_err("Invalid pte\n");
        return -EINVAL;
    }
    
    // 使用kmap_atomic将物理页面映射到内核空间
    virt_addr = (unsigned long *)kmap_atomic(pfn_to_page(page_num));
    if (!virt_addr) {
        pr_err("Failed to map physical address\n");
        return -ENOMEM;
    }
    
    // 在内核空间中写入数据到页面
    *virt_addr = 0xDEADBEEF;
    
    // 输出写入的数据
    pr_info("Data written: 0x%lx\n", *virt_addr);
    
    // 使用kunmap_atomic解除映射
    kunmap_atomic(virt_addr);
    
    return 0;
}

static void __exit kmap_example_exit(void)
{
    pr_info("kmap_example unloaded\n");
}

module_init(kmap_example_init);
module_exit(kmap_example_exit);

MODULE_LICENSE("GPL");

🐓3.2 中断上下文中使用kmap_atomic和kunmap_atomic

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/mm.h>

#define SHARED_IRQ 1

static irqreturn_t irq_handler(int irq, void *dev_id)
{
    unsigned long *virt_addr;
    
    // 获取一个物理页面
    virt_addr = (unsigned long *)kmap_atomic(alloc_page(GFP_ATOMIC));
    if (!virt_addr) {
        pr_err("Failed to allocate memory\n");
        return IRQ_NONE;
    }
    
    // 写入数据到页面
    *virt_addr = 0xCAFEBABE;
    
    // 输出写入的数据
    pr_info("Data written in interrupt context: 0x%lx\n", *virt_addr);
    
    // 解除映射
    kunmap_atomic(virt_addr);
    
    return IRQ_HANDLED;
}

static int __init kmap_interrupt_init(void)
{
    if (request_irq(SHARED_IRQ, irq_handler, IRQF_SHARED, "kmap_interrupt", (void *)irq_handler)) {
        pr_err("Failed to register interrupt handler\n");
        return -EBUSY;
    }
    
    pr_info("kmap_interrupt module loaded\n");
    return 0;
}

static void __exit kmap_interrupt_exit(void)
{
    free_irq(SHARED_IRQ, (void *)irq_handler);
    pr_info("kmap_interrupt module unloaded\n");
}

module_init(kmap_interrupt_init);
module_exit(kmap_interrupt_exit);

MODULE_LICENSE("GPL");

🐓3.3 kmap_atomic和kunmap_atomic在内核中处理DMA缓冲区

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>

#define DMA_BUFFER_SIZE (1024 * 1024) // 1MB DMA缓冲区大小

static dma_addr_t dma_buffer_phys;
static void *dma_buffer_virt;

static int __init dma_example_init(void)
{
    // 分配DMA缓冲区
    dma_buffer_virt = dma_alloc_coherent(NULL, DMA_BUFFER_SIZE, &dma_buffer_phys, GFP_KERNEL);
    if (!dma_buffer_virt) {
        pr_err("Failed to allocate DMA buffer\n");
        return -ENOMEM;
    }
    
    // 使用kmap_atomic将DMA缓冲区映射到内核空间
    dma_buffer_virt = kmap_atomic(pfn_to_page(PHYS_PFN(dma_buffer_phys)));
    if (!dma_buffer_virt) {
        pr_err("Failed to map DMA buffer\n");
        dma_free_coherent(NULL, DMA_BUFFER_SIZE, dma_buffer_virt, dma_buffer_phys);
        return -ENOMEM;
    }
    
    // 在DMA缓冲区中执行操作,例如写入数据
    
    // 使用kunmap_atomic解除映射
    kunmap_atomic(dma_buffer_virt);
    
    pr_info("DMA buffer allocated and mapped\n");
    return 0;
}

static void __exit dma_example_exit(void)
{
    // 释放DMA缓冲区
    dma_free_coherent(NULL, DMA_BUFFER_SIZE, dma_buffer_virt, dma_buffer_phys);
    pr_info("DMA buffer freed\n");
}

module_init(dma_example_init);
module_exit(dma_example_exit);

MODULE_LICENSE("GPL");

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

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

相关文章

解决Android Studio安卓开发写入文件问题

有很多小伙伴想把文件写进安卓系统储存失败&#xff0c;类似下面的代码 val file File("account.txt")val writer BufferedWriter(FileWriter(file))writer.use {it.write(username "," password)} 用java方式写入读出文件但是显示成功但是找不到文件…

react-lib 读取本地模板创建PDF

读取本地文件和读取远程的一样&#xff0c;都使用fetch去获取 async function modifyPdf() {let url ./template.pdflet existingPdfBytes await fetch(url).then(res > res.arrayBuffer()) // 这里也有问题要转一下const d new Uint8Array(existingPdfBytes)const pdfDo…

鸿蒙开发面试真题——面向对象

鸿蒙开发面向对象的面试题是近年来在软件开发领域中备受关注的话题。作为一种新兴的操作系统&#xff0c;鸿蒙系统的开发者需要具备扎实的面向对象编程知识和丰富的开发经验。在面试中&#xff0c;面试官常常会通过一系列的问题来考察面试者对于鸿蒙开发面向对象的理解和应用能…

第1章 手写WebServer

1.1 Web原理 1.1.1 Web概述 Web是指互联网上的万维网&#xff08;World Wide Web&#xff09;&#xff0c;是一个由超文本、超链接和多媒体内容组成的信息空间。Web的基础技术是HTTP协议、URL、HTML、CSS和JavaScript等。Web被广泛应用于信息检索、在线购物、社交媒体、在线游…

区块链交易所开发

在当今数字化时代&#xff0c;区块链技术以其独特的去中心化、安全性和透明性&#xff0c;正在逐步改变我们的生活。其中&#xff0c;区块链交易所作为连接区块链技术与广大投资者的桥梁&#xff0c;其开发与发展备受关注。本文将从技术进步与市场需求两个维度&#xff0c;探讨…

【前端】表格合并如何实现?

简言 介绍实现表格合并的一种方法。 表格合并 表格合并操作是一个比较复杂的操作&#xff0c;它主要分为以下步骤&#xff1a; 获取选中区域选择合并显示的单元格实现合并操作。 我们就逐一实现这三步&#xff0c;最后实现一个较完整的合并操作。&#xff08;不考虑边界情…

点成分享 | 温度控制的艺术:TX150系列水浴中的稳定性与均匀性解析

前言 在实验室和工业生产中&#xff0c;温度控制对于确保实验结果的精确性和产品的高质量至关重要&#xff0c;尤其是针对温度敏感的样品和原材料&#xff0c;如蛋白酶等&#xff0c;微小的温度误差都会对实验结果可靠性和生产质量造成影响。而在控温性能中&#xff0c;稳定性…

Pytorch入门实战 P08-YOLOv5里面的C3模块实现

目录 1、YOLOv5骨干网络模型图&#xff1a; 2、C3模块介绍&#xff1a; 3、C3模块的主要代码&#xff1a; 4、完整的code 5、运行结果展示&#xff1a; &#xff08;1&#xff09;使用SGD优化器 &#xff08;2&#xff09;使用Adam优化器 &#x1f368; 本文为&#x1f…

2024年必应bing广告推广开户有什么条件?

必应Bing作为全球领先的搜索引擎之一&#xff0c;其广告平台正为无数企业开辟着新的市场蓝海。如果您正寻求在必应Bing上投放广告&#xff0c;提升品牌影响力和市场份额&#xff0c;那么了解开户条件并找到一位可靠的合作伙伴至关重要。云衔科技&#xff0c;作为数字营销领域的…

Jetson Orin NX L4T35.5.0平台LT6911芯片 调试记录(2)vi discarding frame问题调试

基于上篇调试记录 Jetson Orin NX L4T35.5.0平台LT6911芯片 调试记录(1)MIPI问题调试-CSDN博客 1.前言 当通过gstreamer持续捕获视频设备时,帧数会下降,并且I输入越高,丢失的帧数越多。 当达到4k30hz时,它完全无法使用,系统会在几秒钟的收集后崩溃并重新启动 4k30hz …

使用yolo识别模型对比两张图片并标记不同(2)

上篇文章有漏洞&#xff0c;在这里补充下&#xff0c;比如要识别第二张图相对于第一张图的违建是否拆除了 第一步旋转对其后&#xff0c;图片会有黑色的掩码&#xff0c;如果旋转角度大的话&#xff0c;没识别出来的框可能不是已经拆除了&#xff0c;而是因为黑色掩码遮挡&…

Laravel 框架请求生命周期

Laravel 框架请求的生命周期 目录 请求图示 说明 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ 请求图示 说明 ① 所有的请求都是经Web 服务器&#xff08;Apache/Nginx&#xff09;配置引导到Laravel 应用的入口public/index.php文件。index.php 加载框架其它部分。 如下图&#xff…

基于FPGA的数字信号处理(3)--什么是浮点数?

科学计数法 你可能不了解「浮点数」&#xff0c;但你一定了解「科学记数法」。 10进制科学记数法把一个数表示成a与10的n次幂相乘的形式&#xff08;1≤|a|<10&#xff0c;a不为分数形式&#xff0c;n为整数&#xff09;&#xff0c;例如&#xff1a; 19970000000000 1.9…

关系(五)利用python绘制连接散点图

关系&#xff08;五&#xff09;利用python绘制连接散点图 连接散点图&#xff08;Connected Scatterplot&#xff09;简介 连接散点图&#xff08;点线图&#xff09;是折线图的一种&#xff0c;与散点图类似。但添加了按数据点出现顺序的连线&#xff0c;以此来表示两个变量…

币圈Cryptosquare论坛

Cryptosquare综合性资讯论坛汇集了币圈新闻、空投信息、社会热点以及与Web3相关的工作信息。让我们一起解锁加密世界的种种可能性&#xff0c;探索Cryptosquare论坛带来的精彩&#xff01; 币圈新闻板块&#xff1a; Cryptosquare论坛的币圈新闻板块是用户获取最新加密货币行业…

vite打包配置

目录 minify默认是esbuild&#xff0c;不能启动下面配置 使用&#xff1a; plugins: [viteMockServe({mockPath: mock})]根目录新建mock/index.ts. 有例子Mock file examples&#xff1a;https://www.npmjs.com/package/vite-plugin-mock-server 开发环境生产环境地址替换。根…

Matlab|含sop的33节点配电网优化

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序以IEEE33节点为例&#xff0c;分析含sop的配电网优化&#xff0c;包括sop有功约束、无功约束和容量约束&#xff0c;非线性部分通过转换为旋转锥约束进行编程&#xff0c;并且包括33节点配电网潮流及对应…

python自动化操作docx

使用Python自动化处理Word文档 在日常工作中&#xff0c;我们经常需要处理大量的Word文档&#xff0c;这时自动化脚本就显得尤为重要。本文将介绍如何使用Python中的python-docx库来创建和修改Word文档。 安装python-docx库 在开始之前&#xff0c;确保你已经安装了python-d…

基于JWT实现的Token认证方案

JSON Web Token是什么&#xff1f; JSON Web Token&#xff08;JWT&#xff09;是目前最流行的跨域身份验证解决方案。 JSON Web Token&#xff08;JWT&#xff09;是一个开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用…

电脑文件误删除如何恢复?这5个策略亲测有效!

“求助&#xff01;在电脑上不小心删除了文件还有机会找回来吗&#xff1f;一不小心我就删除了一个重要的工作文件&#xff01;大家快帮帮我吧&#xff01;” 保存在电脑里的文件对电脑用户来说很多都是非常重要的&#xff0c;我们可能生活中、学习上以及工作上都需要使用这些文…