linux 之dma_buf (8)- ION简化版本

一、前言

我们学习了如何使用 alloc_page() 方式来分配内存,但是该驱动只能分配1个PAGE_SIZE。本篇我们将在上一篇的基础上,实现一个简化版的ION驱动,以此来实现任意 size 大小的内存分配。

二、准备

为了和 kernel 标准 ion 驱动兼容,本篇引用了 driver/staging/android/uapi/ion.h 头文件,目的是为了方便 userspace 直接使用 struct ion_allocation_data 和 ION_IOC_ALLOC 宏:

struct ion_allocation_data {__u64 len;__u32 heap_id_mask;__u32 flags;__u32 fd;__u32 unused;
};#define ION_IOC_MAGIC		'I'
#define ION_IOC_ALLOC		_IOWR(ION_IOC_MAGIC, 0, \struct ion_allocation_data)

 本篇 ion 驱动只使用 ion_allocation_data 结构体中的 len 和 fd 这两个元素,其它元素不做处理。

三、示例

 exporter-ion.c

#include <linux/dma-buf.h>
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>struct ion_allocation_data {__u64 len;__u32 heap_id_mask;__u32 flags;__u32 fd;__u32 unused;
};#define ION_IOC_MAGIC           'I'
#define ION_IOC_ALLOC           _IOWR(ION_IOC_MAGIC, 0, \struct ion_allocation_data)struct ion_data {int npages;struct page *pages[];
};static int ion_attach(struct dma_buf *dmabuf, struct device *dev,struct dma_buf_attachment *attachment)
{pr_info("dmabuf attach device: %s\n", dev_name(dev));return 0;
}static void ion_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attachment)
{pr_info("dmabuf detach device: %s\n", dev_name(attachment->dev));
}static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,enum dma_data_direction dir)
{struct ion_data *data = attachment->dmabuf->priv;struct sg_table *table;struct scatterlist *sg;int i;table = kmalloc(sizeof(*table), GFP_KERNEL);sg_alloc_table(table, data->npages, GFP_KERNEL);sg = table->sgl;for (i = 0; i < data->npages; i++) {sg_set_page(sg, data->pages[i], PAGE_SIZE, 0);sg = sg_next(sg);}dma_map_sg(NULL, table->sgl, table->nents, dir);return table;
}static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment,struct sg_table *table,enum dma_data_direction dir)
{dma_unmap_sg(NULL, table->sgl, table->nents, dir);sg_free_table(table);kfree(table);
}static void ion_release(struct dma_buf *dma_buf)
{struct ion_data *data = dma_buf->priv;int i;pr_info("dmabuf release\n");for (i = 0; i < data->npages; i++)put_page(data->pages[i]);kfree(data);
}
static void *ion_vmap(struct dma_buf *dma_buf)
{struct ion_data *data = dma_buf->priv;return vm_map_ram(data->pages, data->npages, 0, PAGE_KERNEL);
}static void ion_vunmap(struct dma_buf *dma_buf, void *vaddr)
{struct ion_data *data = dma_buf->priv;vm_unmap_ram(vaddr, data->npages);
}static int ion_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
{struct ion_data *data = dma_buf->priv;unsigned long vm_start = vma->vm_start;int i;for (i = 0; i < data->npages; i++) {remap_pfn_range(vma, vm_start, page_to_pfn(data->pages[i]),PAGE_SIZE, vma->vm_page_prot);vm_start += PAGE_SIZE;}return 0;
}static int ion_begin_cpu_access(struct dma_buf *dmabuf,enum dma_data_direction dir)
{struct dma_buf_attachment *attachment;struct sg_table *table;attachment = list_first_entry(&dmabuf->attachments, struct dma_buf_attachment, node);table = attachment->sgt;dma_sync_sg_for_cpu(NULL, table->sgl, table->nents, dir);return 0;
}static int ion_end_cpu_access(struct dma_buf *dmabuf,enum dma_data_direction dir)
{struct dma_buf_attachment *attachment;struct sg_table *table;attachment = list_first_entry(&dmabuf->attachments, struct dma_buf_attachment, node);table = attachment->sgt;dma_sync_sg_for_device(NULL, table->sgl, table->nents, dir);return 0;
}static const struct dma_buf_ops exp_dmabuf_ops = {.attach = ion_attach,.detach = ion_detach,.map_dma_buf = ion_map_dma_buf,.unmap_dma_buf = ion_unmap_dma_buf,.release = ion_release,.mmap = ion_mmap,.vmap = ion_vmap,.vunmap = ion_vunmap,.begin_cpu_access = ion_begin_cpu_access,.end_cpu_access = ion_end_cpu_access,
};
static struct dma_buf *ion_alloc(size_t size)
{DEFINE_DMA_BUF_EXPORT_INFO(exp_info);struct dma_buf *dmabuf;struct ion_data *data;int i, npages;npages = PAGE_ALIGN(size) / PAGE_SIZE;data = kmalloc(sizeof(*data) + npages * sizeof(struct page *),GFP_KERNEL);data->npages = npages;for (i = 0; i < npages; i++)data->pages[i] = alloc_page(GFP_KERNEL);exp_info.ops = &exp_dmabuf_ops;exp_info.size = npages * PAGE_SIZE;exp_info.flags = O_CLOEXEC;exp_info.priv = data;dmabuf = dma_buf_export(&exp_info);return dmabuf;
}static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{struct dma_buf *dmabuf;struct ion_allocation_data alloc_data;/* currently just only support ION_IOC_ALLOC ioctl */if (cmd != ION_IOC_ALLOC)return -EINVAL;copy_from_user(&alloc_data, (void __user *)arg, sizeof(alloc_data));dmabuf = ion_alloc(alloc_data.len);alloc_data.fd = dma_buf_fd(dmabuf, O_CLOEXEC);copy_to_user((void __user *)arg, &alloc_data, sizeof(alloc_data));return 0;
}static struct file_operations ion_fops = {.owner   = THIS_MODULE,.unlocked_ioctl   = ion_ioctl,
};static struct miscdevice mdev = {.minor = MISC_DYNAMIC_MINOR,.name = "ion",.fops = &ion_fops,
};static int __init ion_init(void)
{return misc_register(&mdev);
}static void __exit ion_exit(void)
{misc_deregister(&mdev);
}module_init(ion_init);
module_exit(ion_exit);

从上面可以看出,任意大小的参数,在驱动中就是for循环申请页。因为申请的内存不一定时连续物理内存,所以使用sg table .

应用程序

ion_test.c

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>struct ion_allocation_data {__u64 len;__u32 heap_id_mask;__u32 flags;__u32 fd;__u32 unused;
};#define PAGE_SIZE 4096int main(int argc, char *argv[])
{int fd;struct ion_allocation_data alloc_data;fd = open("/dev/ion", O_RDWR);alloc_data.len = 3 * PAGE_SIZE;ioctl(fd, ION_IOC_ALLOC, &alloc_data);printf("ion alloc success: size = %llu, dmabuf_fd = %u\n",alloc_data.len, alloc_data.fd);close(fd);return 0;
}

该应用程序通过 ION_IOC_ALLOC ioctl 请求分配了3个 page 的物理 buffer,如果底层驱动分配成功,则会将该 dma-buf 所对应的 fd 返回给应用程序,以便后续执行 mmap 操作或将 fd 传给其它模块。

需要注意的是,这里的3个 pages 是通过3次调用 alloc_page() 来分配的,因此每个 page 之间可能是不连续的,也可以近似的认为该 ion 驱动分配的 buffer 属于 ION_HEAP_TYPE_SYSTEM。如果要分配物理连续的 pages,请使用 alloc_pages() 进行分配。

上面的驱动中,通过变长数组,实现虚拟地址连续,但是物理地址不一定连续的方法。

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

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

相关文章

身为UI设计老鸟,不学点3D,好像要被潮流抛弃啦,卷起来吧。

当前3D原则在UI设计中运用的越来越多&#xff0c;在UI设计中&#xff0c;使用3D元素可以为界面带来以下几个价值&#xff1a; 增强视觉冲击力&#xff1a;3D元素可以通过立体感和逼真的效果&#xff0c;为界面增添视觉冲击力&#xff0c;使得设计更加生动、吸引人&#xff0c;并…

AI PC 的曙光:微软大胆出击与苹果竞争

AI PC 的曙光&#xff1a;微软大胆出击与苹果竞争 AI PC 的曙光&#xff1a;微软大胆出击与苹果竞争 概述 微软已正式进入 AI PC 时代&#xff0c;并且毫不避讳地直接向苹果的 MacBook 发起攻击。随着代号为“Copilot”的笔记本电脑的推出&#xff0c;微软准备彻底改变我们与…

面试数据库八股文十问十答第九期

面试数据库八股文十问十答第九期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;MySQL 读写分离 MySQL 读写…

AI大模型如何“开窍”?算法、数据与架构的三重奏

一、算法创新 1. 探索新的学习范式 自监督学习&#xff1a;利用未标注数据让模型自我学习&#xff0c;提高模型的泛化能力。元学习&#xff1a;让模型学会如何学习&#xff0c;以便在不同任务之间快速迁移。强化学习&#xff1a;通过试错与奖励机制&#xff0c;使模型在与环境…

012、哈希_应用场景

图为关系型数据表记录的两条用户信息,用户的属性作为表的列,每条用户信息作为行。 如果将其用哈希类型存储,如图所示。 相比于使用字符串序列化缓存用户信息,哈希类型变得更加直观,并且在更新操作上会更加便捷。可以将每个用户的id定义为键后缀,多对field-value对应每…

Flutter 中的 RotatedBox 小部件:全面指南

Flutter 中的 RotatedBox 小部件&#xff1a;全面指南 在 Flutter 的丰富组件库中&#xff0c;RotatedBox 是一个简单而强大的小部件&#xff0c;它能够对子组件进行旋转。这使得 RotatedBox 成为实现某些布局效果和动画的理想选择。本文将详细介绍 RotatedBox 的使用方法&…

Springboot 开发 -- 集成 JWT 构建安全的API接口服务

一、JWT简介 JSON Web Token&#xff08;JWT&#xff09;是一种基于JSON的开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用于在各方之间以JSON对象的形式安全地传输信息。JWT可以被签名&#xff0c;确保信息在传输过程中的完整性和可信度。JWT通常用于身份验证和信息…

vue2和3区别

Vue2和Vue3在**源码架构、性能提升以及API设计**等方面存在区别。具体分析如下&#xff1a; 1. **源码架构** - **Vue2**&#xff1a;Vue2的源码相对更传统&#xff0c;主要使用Options API来构建组件。这种方式要求开发者在一个对象中定义组件的各种属性&#xff08;如data、m…

微软 Edge 深度探索:现代浏览器的蜕变

微软 Edge 浏览器经历了令人瞩目的转变&#xff0c;从备受诟病的 Internet Explorer 继任者&#xff0c;发展成为功能强大、特性丰富的浏览器&#xff0c;与 Google Chrome 和 Mozilla Firefox 等行业巨头正面竞争。本文将深入探讨 Edge&#xff0c;从用户体验、功能、内容、平…

Android 14.0 SystemUI状态栏屏蔽掉通知栏不显示通知

1.概述 在14.0的系统产品开发中,在SystemUI定制化开发中,有产品需求要求屏蔽通知显示,由于对状态栏的通知管控的比较严,所以要求屏蔽掉通知栏的通知不显示通知 接下来就需要对通知栏的显示流程分析,屏蔽掉通知就可以了 2.SystemUI状态栏屏蔽掉通知栏不显示通知的核心类 f…

12-常用类

1. 包装类 针对八种基本数据类型封装的相应的引用类型。 有了类的特点&#xff0c;就可以调用类中的方法。&#xff08;为什么要封装&#xff09; 基本数据类型包装类booleanBooleanchar CharacterbyteByteshortShortintIntegerlongLongfloatFloatdoubleDouble 1.1 …

C# Sdcb.PaddleInference 中文分词、词性标注

C# Sdcb.PaddleInference 中文分词、词性标注 目录 效果 项目 代码 下载 参考 效果 项目 代码 using Sdcb.PaddleNLP.Lac; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Windows.Forms; namespace C__Sdcb.Pad…

kafka-消费者组-点对点测试

文章目录 1、点对点测试1.1、获取 kafka-consumer-groups.sh 的帮助信息1.2、列出所有的 消费者组1.3、创建消费者1并指定组 my_group11.4、创建消费者2并指定组 my_group11.5、创建消费者3并指定组 my_group11.6、创建生产者发送消息到 my_topic1 主题1.6.1、发送第一条消息ro…

华为WLAN无线组网技术与解决方案

WLAN无线组网技术与解决方案 网络拓扑采用AP和AC旁挂式无线组网 配置思路&#xff1a; 1.让AP上线 1.1&#xff0c;使得AP能够获得IP地址 配置步骤&#xff1a; 1.把AC当作一个一个有管理功能的三层交换机 sys Enter system view, return user view with CtrlZ. [AC6605]vlan …

多态的好处

使用多态&#xff08;Polymorphism&#xff09;在C中有多个重要的原因&#xff0c;这些原因使得多态成为面向对象编程中不可或缺的一部分。以下是使用多态的一些关键原因&#xff1a; 代码复用和灵活性&#xff1a; 多态允许我们编写可以处理多种类型对象的通用代码。通过使用…

为什么MySQL需要binlog、undo log、redo log 3种日志?

binlog是 server层生成的日记&#xff0c;而 undo log、redo log 是Innodb 存储引擎层生成的日志 binlog&#xff0c;是 binary log的英文缩写&#xff0c;翻译为二进制日志或者归档日志&#xff08;带有业务含义&#xff09;&#xff0c;它是从 MySQL 3.23.14版本引入的。bin…

高并发处理

高并发处理是对系统在同时处理大量请求能力的一种考验。在设计高并发系统时&#xff0c;通常会涉及到多个层面的优化&#xff0c;包括应用程序、数据库、服务器和网络架构等方面的优化。以下是一些建议如何设计和优化高并发系统&#xff1a; 应用程序层面 &#xff1a; 异步处…

【Qt】Qt框架文件处理精要:API解析与应用实例:QFile

文章目录 前言&#xff1a;1. Qt 文件概述2. 输入输出设备类3. 文件读写类3.1. 打开open3.2. 读read / readline/ readAll3.3. 写write3.4. 关闭close 4. 读写文件示例5. 文件件和目录信息类总结&#xff1a; 前言&#xff1a; 在现代软件开发中&#xff0c;文件操作是应用程序…

【贪吃蛇game】

好的&#xff0c;我将为您编写一个简单的贪吃蛇游戏的代码。这个游戏将使用Python语言和pygame库来实现。首先&#xff0c;请确保您的环境中已经安装了pygame库。如果尚未安装&#xff0c;可以使用pip install pygame命令进行安装。 接下来&#xff0c;我将编写代码。代码完成后…

如何恢复已删除/丢失或未保存的 PDF 文件?

许多用户曾因某些问题删除或丢失 PDF 文件。此外&#xff0c;一些用户在关闭应用程序时未保存 PDF 文件&#xff0c;从而丢失 PDF 文件。您可以尝试一些解决方案来恢复已删除的 PDF 文件、恢复未保存的 PDF 文件&#xff0c;以及在任何其他数据丢失情况下挽救丢失的 PDF 文件。…