当前位置: 首页 > news >正文

Linux内核 -- 内存管理之scatterlist结构使用

Linux Kernel Scatterlist 使用指南

1. 简介

scatterlist 结构在 Linux 内核中主要用于 DMA(直接内存访问)操作中的内存管理。它允许将不连续的物理内存片段表示为一个逻辑上的连续块,从而使 DMA 操作可以高效地处理这些不连续的内存片段。

2. 设计思想

在 DMA 操作中,数据的源或目标可能分散在物理内存的不同位置。scatterlist 提供了一种机制,将这些分散的内存片段组合在一起,使 DMA 控制器能够处理这些数据,从而提高内存操作的效率和灵活性。

3. scatterlist 结构

scatterlist 结构体定义在 <linux/scatterlist.h> 头文件中,主要成员包括:

struct scatterlist {unsigned long   page_link;unsigned int    offset;dma_addr_t      dma_address;unsigned int    length;
};
  • page_link:指向内存页的指针及一些标志。
  • offset:内存页内的偏移量。
  • dma_address:DMA 设备使用的地址。
  • length:此段内存的长度。

4. 使用步骤

使用 scatterlist 主要包括以下几个步骤:

4.1 初始化 scatterlist

在使用 scatterlist 之前,需要先分配并初始化它。

struct scatterlist *sg;
int nents = 10; // Scatterlist 条目的数量sg = kmalloc_array(nents, sizeof(*sg), GFP_KERNEL);
if (!sg)return -ENOMEM;sg_init_table(sg, nents);

4.2 填充 scatterlist

将内存区域填充到 scatterlist 中。

for (i = 0; i < nents; i++) {sg_set_page(&sg[i], page, PAGE_SIZE, 0);
}

4.3 映射 scatterlist 到 DMA 地址空间

在进行 DMA 传输之前,需要将 scatterlist 映射到 DMA 地址空间。

dma_addr_t dma_handle;
dma_handle = dma_map_sg(dev, sg, nents, DMA_TO_DEVICE);

4.4 传输数据

使用映射后的 scatterlist 进行 DMA 数据传输。此步骤取决于你的具体 DMA 控制器和驱动程序。以下是一个简单的示例,假设你的 DMA 控制器支持 dmaengine 框架:

struct dma_async_tx_descriptor *tx;
dma_cookie_t cookie;
enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
struct dma_chan *chan = /* your DMA channel */;tx = dmaengine_prep_slave_sg(chan, sg, dma_nents, DMA_MEM_TO_DEV, flags);
if (!tx) {pr_err("Failed to prepare DMA transfer\n");goto unmap;
}cookie = tx->tx_submit(tx);
if (dma_submit_error(cookie)) {pr_err("Failed to submit DMA transfer\n");goto unmap;
}dma_async_issue_pending(chan);// 等待DMA传输完成(可以是中断或轮询)

4.5 解除映射

传输完成后,需要解除 scatterlist 的 DMA 映射。

dma_unmap_sg(dev, sg, nents, DMA_TO_DEVICE);

5. 注意事项

  1. 内存分配:确保分配的内存足够大,可以容纳所有的 scatterlist 条目。
  2. 映射和解除映射:确保在使用前正确映射 scatterlist,传输完成后及时解除映射,以防止内存泄漏或数据损坏。
  3. 内存对齐:确保内存地址和长度满足 DMA 控制器的对齐要求。
  4. 错误处理:处理好内存分配失败和 DMA 操作失败的情况。

6. 示例代码

以下是一个完整的示例,展示了如何使用 scatterlist 进行 DMA 操作:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>static int __init my_module_init(void)
{struct scatterlist *sg;int nents = 10;int i;dma_addr_t dma_handle;struct device *dev = /* your device */;struct page *page;sg = kmalloc_array(nents, sizeof(*sg), GFP_KERNEL);if (!sg)return -ENOMEM;sg_init_table(sg, nents);for (i = 0; i < nents; i++) {page = alloc_page(GFP_KERNEL);if (!page) {pr_err("Failed to allocate page
");goto out;}sg_set_page(&sg[i], page, PAGE_SIZE, 0);}dma_handle = dma_map_sg(dev, sg, nents, DMA_TO_DEVICE);if (!dma_handle) {pr_err("Failed to map scatterlist
");goto out;}// Perform DMA operation heredma_unmap_sg(dev, sg, nents, DMA_TO_DEVICE);out:for (i = 0; i < nents; i++) {if (sg[i].page_link)__free_page(sg_page(&sg[i]));}kfree(sg);return 0;
}static void __exit my_module_exit(void)
{// Cleanup code here
}module_init(my_module_init);
module_exit(my_module_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Scatterlist Example");

这个示例展示了如何分配、初始化、填充、映射和解除映射 scatterlist 进行 DMA 操作。根据具体需求,你可以在 DMA 操作中添加更多的处理逻辑。

相关文章:

  • 实现了 ApplicationContextAware 接口的bean可以接收到 ApplicationContext 的引用
  • 面试经典 150 题
  • 深入理解 Qt 的 `moveToThread`:提升多线程应用性能的关键
  • MySQL GROUP_CONCAT 函数详解与实战应用
  • 基于Java技术的B/S模式书籍学习平台
  • Python中的格式化输出
  • AntDesign上传组件upload二次封装+全局上传hook使用
  • 美国大带宽服务器租用优势和注意事项
  • git配置ssh-keygen -t rsa -c“xxxx@xxxx.com.cn出现Too many arguments.解决办法
  • ChatGPT提问提示指南PDF下载经典分享推荐书籍
  • react-fiber
  • C#运算符重载
  • flutter开发实战-Webview及dispose关闭背景音
  • c与c++ 常用的字符与字符串处理的接口介绍:
  • Xilinx FPGA:vivado关于fifo的一些零碎知识
  • C学习-枚举(九)
  • export和import的用法总结
  • github从入门到放弃(1)
  • laravel5.5 视图共享数据
  • Material Design
  • PaddlePaddle-GitHub的正确打开姿势
  • storm drpc实例
  • 构建工具 - 收藏集 - 掘金
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 以太坊客户端Geth命令参数详解
  • 译自由幺半群
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • ionic异常记录
  • 大数据全解:定义、价值及挑战
  • #Datawhale X 李宏毅苹果书 AI夏令营#3.13.2局部极小值与鞍点批量和动量
  • #stm32驱动外设模块总结w5500模块
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • $ git push -u origin master 推送到远程库出错
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (十八)SpringBoot之发送QQ邮件
  • (四)JPA - JQPL 实现增删改查
  • (转载)Linux网络编程入门
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .NET C# 使用 iText 生成PDF
  • .NET MVC之AOP
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • /etc/sudoers (root权限管理)
  • @AliasFor 使用
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [ 蓝桥杯Web真题 ]-布局切换
  • [<死锁专题>]
  • [2669]2-2 Time类的定义
  • [corCTF 2022] CoRJail: From Null Byte Overflow To Docker Escape
  • [CR]厚云填补_SEGDNet