【C语言】linux内核pci_iomap

news2024/11/17 8:31:32

一、pci_iomap

/*
 * pci_iomap 是一个用于映射 PCI 设备的 BAR(Base Address Register,基地址寄存器)的函数。
 * 此函数返回指向内存映射 IO 的指针,用于直接访问 PCI 设备的内存或 I/O 空间。
 * 
 * 参数:
 * dev - 指向pci_dev结构的指针,表示PCI设备。
 * bar - 表示要映射的基地址寄存器的索引(0-5)。
 * maxlen - 要映射的最大长度;如果为0,则映射整个BAR空间。
 * 
 * 返回值:
 * 成功时,函数返回指向映射区域的指针。
 * 如果映射失败,返回NULL。
 *
 * 注意: 当不再需要访问映射的内存时,应调用pci_iounmap来释放映射的资源。
 */
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
    return pci_iomap_range(dev, bar, 0, maxlen);
}
EXPORT_SYMBOL(pci_iomap); // 将 pci_iomap 函数导出,使得其它模块也能够调用该函数

这个函数 pci_iomap 是一个辅助函数,实际上它调用了 pci_iomap_range 函数,但是将 offset 设置为0,目的是简化对整个BAR的映射,而不是基于某个特定的起始偏移量。`pci_iomap` 在许多PCI驱动程序中被用来初始化设备操作所需的地址映射。

函数定义:lib\pci_iomap.c

二、pci_iomap_range

/**
 * pci_iomap_range - 为PCI BAR创建一个虚拟映射
 * @dev: 拥有BAR的PCI设备
 * @bar: BAR编号
 * @offset: 从BAR中给定的偏移量开始映射内存
 * @maxlen: 要映射的最大内存长度
 *
 * 使用该函数可以获得指向设备BAR的__iomem地址。
 * 可以使用ioread*()和iowrite*()来进行访问。这些函数会隐藏
 * 是MMIO还是PIO地址空间的细节,并且会按照预期的方式正确地工作。
 *
 * @maxlen 指定了要映射的最大长度。如果您想访问从偏移量到结束的完整BAR,
 * 在这里传递%0。
 */
void __iomem *pci_iomap_range(struct pci_dev *dev,
                  int bar,
                  unsigned long offset,
                  unsigned long maxlen)
{
    //获取BAR资源的起始地址
    resource_size_t start = pci_resource_start(dev, bar);
    //获取BAR资源的总长度
    resource_size_t len = pci_resource_len(dev, bar);
    //获取BAR资源的标志
    unsigned long flags = pci_resource_flags(dev, bar);

    //如果资源长度不足或起始地址为0,则返回NULL
    if (len <= offset || !start)
        return NULL;
    //减去偏移量,获得新的长度
    len -= offset;
    //根据偏移量更新起始地址
    start += offset;
    //如果有指定最大长度,并且新的长度大于它,则使用最大长度
    if (maxlen && len > maxlen)
        len = maxlen;
    //如果是I/O资源,使用__pci_ioport_map进行映射
    if (flags & IORESOURCE_IO)
        return __pci_ioport_map(dev, start, len);
    //如果是内存资源,使用ioremap进行映射
    if (flags & IORESOURCE_MEM)
        return ioremap(start, len);
    //如果不是I/O资源也不是内存资源,返回NULL
    return NULL;
}
//导出pci_iomap_range符号,使其在内核其他模块中可用
EXPORT_SYMBOL(pci_iomap_range);

上述代码是Linux内核中的一个函数注释,它是用于将PCI设备的某个BAR(基址地址寄存器)区域映射到内核虚拟地址空间,以便于内核或驱动程序可以直接通过这个虚拟地址对硬件设备进行访问。这个机制是PCI驱动程序常用的方法之一。

函数定义:lib\pci_iomap.c

三、pci_iomap和pci_iomap_range

/**
 * pci_iomap_range - 为PCI设备的BAR创建虚拟映射
 * @dev: 拥有BAR的PCI设备
 * @bar: BAR编号
 * @offset: 从BAR的给定偏移量处开始映射内存
 * @maxlen: 需要映射的内存的最大长度
 *
 * 使用此函数可以获取到指向设备BAR的__iomem地址。
 * 您可以使用ioread*() 和 iowrite*() 来访问其地址。
 * 这些函数会隐藏这是一个MMIO地址还是PIO地址空间的细节,
 * 并以您期望的正确方式进行操作。
 *
 * @maxlen 指定映射的最大长度。如果您想要从偏移量到末尾访问整个BAR,
 * 请在这里传递%0(即传递0表示映射整个BAR的长度)。
 */
void __iomem *pci_iomap_range(struct pci_dev *dev,
                  int bar,
                  unsigned long offset,
                  unsigned long maxlen)
{
    // ... 实现细节略 ...
}
EXPORT_SYMBOL(pci_iomap_range);


/**
 * pci_iomap - 为PCI设备的BAR创建虚拟映射
 * @dev: 拥有BAR的PCI设备
 * @bar: BAR编号
 * @maxlen: 需要映射的内存的长度
 *
 * 使用此函数可以获取到指向设备BAR的__iomem地址。
 * 您可以使用ioread*() 和 iowrite*() 来访问这个地址。
 * 这些函数会隐藏这是一个MMIO地址还是PIO地址空间的细节,
 * 并以您期望的正确方式进行操作。
 *
 * @maxlen 指定映射的最大长度。如果您想要访问整个BAR而不首先检查其长度,
 * 请在这里传递%0(即传递0表示映射整个BAR的长度)。
 */
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
    // ... 实现细节略 ...
}
EXPORT_SYMBOL(pci_iomap);

这两个函数都是用来建立PCI设备的BAR(Base Address Register,基址寄存器)到进程的虚拟地址空间的映射。通过这个映射,程序可以通过标准的I/O访问函数来读写设备的硬件寄存器。
pci_iomap_range允许指定一个起始偏移量和最大映射长度,可以用来映射BAR内部一段特定的内存区域。
pci_iomap是一个简化的版本,它默认从BAR的起始处映射整个区域,或者是指定长度的内存。(当maxlen为0时映射整个BAR)。
EXPORT_SYMBOL宏用于导出符号,使得这些函数可以在内核模块之间共享。 

ChatGPT

在Linux内核中,`pci_iomap`是一个用于将PCI设备的内存或I/O端口映射到内核虚拟地址空间的内核函数。这使得内核代码可以通过正常的指针操作来访问PCI设备的资源。
函数的原型通常如下所示:

void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen);

参数解释:
- dev:指向`pci_dev`结构的指针,它表示要映射的PCI设备。
- bar:要映射的PCI设备的Base Address Register (BAR) 索引,其值从0开始。
- maxlen:映射区域的最大长度。如果该值为0,则表示映射从BAR开始的整个区域。
返回值:
该函数返回一个`void __iomem *类型的指针,它指向请求的映射区域的起始地址,如果映射失败,则返回NULL`。
使用`pci_iomap`函数可以直接访问PCI设备的内存,这通常在设备驱动程序初始化时完成。例如,驱动程序会调用`pci_iomap`来获取指向设备寄存器的指针,之后就可以通过这个指针来读写寄存器。
在使用完毕映射的内存后,应该调用`pci_iounmap()`函数来解除映射。
例如:

#define MY_DEVICE_BAR 0

struct pci_dev *pdev; // 假设已经通过某种方式获得
void __iomem *iomem;

// 映射BAR 0
iomem = pci_iomap(pdev, MY_DEVICE_BAR, 0);
if (!iomem) {
    // 处理错误情况
}

// 使用iomem指针访问PCI设备内存
writeb(value, iomem + offset); // 写入字节
// 或者
writel(value, iomem + offset); // 写入长字

// 解除映射
pci_iounmap(pdev, iomem);

请记住,在写驱动程序时,应确保遵循操作系统的内存管理和设备操作准则,以确保系统稳定性和安全性。

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

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

相关文章

Android Jetpack Compose基础之组件的帧渲染

Android Jetpack Compose基础之组件的帧渲染 组合布局LayoutModifier示例 LayoutCompsable示例 绘制CanvasDrawModifierDrawModifier-drawWithContent示例 DrawModifier-drawBehind源码示例 DrawModifier-drawWithCache源码示例 拓展Modifier.graphicsLayer Android View 系统&…

0基础 三个月掌握C语言(13)-下

数据在内存中的存储 浮点数在内存中的存储 常见的浮点数&#xff1a;3.141592、1E10等 浮点数家族包括&#xff1a;float、double、long double类型 浮点数表示的范围&#xff1a;在float.h中定义 练习 关于&#xff08;float*)&n&#xff1a; &n&#xff1a;这是一…

基于SSM的宠物领养平台的设计与实现

基于SSM的宠物领养平台的设计与实现 获取源码——》公主号&#xff1a;计算机专业毕设大全 获取源码——》公主号&#xff1a;计算机专业毕设大全

Three.js 中的 OrbitControls 是一个用于控制相机围绕目标旋转以及缩放、平移等操作的控制器。

demo案例 Three.js 中的 OrbitControls 是一个用于控制相机围绕目标旋转以及缩放、平移等操作的控制器。下面是它的详细讲解&#xff1a; 构造函数: OrbitControls(object: Camera, domElement?: HTMLElement)object&#xff1a;THREE.Camera 实例&#xff0c;控制器将围绕…

LibFuzzer 基本使用

文章目录 前言环境搭建基础使用编写 fuzz target编译链接demo 测试 && 输出日志分析心脏滴血漏洞测试 提高代码覆盖率和测试速度指定种子语料库多核并行 Fuzz使用字典 参考 前言 相较于 AFL 来说&#xff0c;LibFuzzer 在单个进程内完成模糊测试&#xff0c;以此来避免…

Nacos部署(一)Linux部署Nacos2.3.x单机环境

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; Nacos部署&#xff08;一&#xff09;Linux部署Nacos2.3.x单机环境 ⏱️…

【NC20313】仪仗队

题目 仪仗队 欧拉函数&#xff0c;找规律 思路 这好像是一道非常简单的找规律问题&#xff0c;所以你从 1 1 1 开始枚举&#xff0c;计算出当 N i Ni Ni 时的结果 a n s i ans_i ansi​&#xff0c;所以你得出了以下结果&#xff1a; Nans10233549513621725837 令人失望…

招聘自媒体编辑岗位的人才测评方案

人才测评工具在招聘入职的方案&#xff0c;在线工具网根据自媒体岗位的特性和需求来分析&#xff0c;并制定自媒体主编的测评方案。 自媒体作为互联网时代的产物&#xff0c;自然也为我们带来了很多的福利&#xff0c;例如&#xff1a;海量的信息、快捷的传媒方式&#xff0c;那…

学习次模函数-第2章 定义

纵观本专著&#xff0c;我们认为及其幂集&#xff08;即&#xff0c; 所有子集的集合&#xff09;&#xff0c;其基数为。我们也考虑一个实值集函数&#xff0c;使得。 与凸函数的一般约定相反&#xff08;见附录A&#xff09;&#xff0c;我们不允许函数有无穷大的值。 次模分…

一文搞懂数据链路层

数据链路层 1. 简介2. MAC3. 以太网 1. 简介 &#xff08;1&#xff09;概念 链路(link)是一条无源的点到点的物理线路段&#xff0c;中间没有任何其他的交换结点。 数据链路(data link) 除了物理线路&#xff08;双绞线电缆、同轴电缆、光线等介质&#xff09;外&#xff0…

Java获取方法参数名称方案||SpringBoot配置顺序注解

一: Java获取方法参数名称的方法 普盲: getDeclaredMethods与getMethods的的区别 1、getMethods返回一个包含某些 Method 对象的数组&#xff0c;这些对象反映此 Class 对象所表示的类或接口的公共 member 方法。 2、getDeclaredMethods返回 Method 对象的一个数组&#xff0c…

STM32+ESP8266水墨屏天气时钟:简易多级菜单(数组查表法)

项目背景 本次的水墨屏幕项目需要做一个多级菜单的显示&#xff0c;所以写出来一起学习&#xff0c;本篇文章不单单适合于水墨屏&#xff0c;像0.96OLED屏幕也适用&#xff0c;区别就是修改显示函数。 设计思路 多级菜单的实现&#xff0c;一般有两种实现的方法 1.通过双向…

HTTPS协议的工作原理:保护网络通信的安全盾牌

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

力扣每日一题 2024/3/24 零钱兑换

题目描述 用例说明 思路讲解 动态规划五步法 第一步确定dp数组的含义&#xff1a;dp[i]为凑到金额为i所用最少的硬币数量 第二步确定动态规划方程&#xff1a;凑足金额为j-coins[i]所需最少的硬币个数为dp[j-coins[i]]&#xff0c;那凑足金额为j所用的最少硬币数为dp[j-coin…

【C语言】C语言实现扫雷三子棋

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;C语言_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.C语言实现三子棋 1.1 整体思路 1.2 游戏菜单的创建 1.3 游戏主体的实现 1.3.1 棋盘的初始化 1.3.2 打印棋盘 1.3.3 玩家下…

3分钟搞懂示波器测原副边波形

大家好&#xff0c;我是砖一。 今天分享一下如何用示波器测试原副边的波形&#xff0c;验证电源设计规格准确性。 一&#xff0c;试验目的 假设我们现在拿到的样品是属于开关电源类型的。 1&#xff0c;我们对于电源工程师设计出的一个开关电源样品测试原副边波形&#xff…

手撕算法-爬楼梯

描述 分析 一维动态规划。dp[i] dp[i-1] dp[i-2]; 初始状态&#xff1a;d[0] 0, dp[1] 1, dp[2] 2; 返回值:dp[n]; 代码 class Solution {public int climbStairs(int n) {if (n < 2)return n;int[] dp new int[n 1];dp[1] 1;dp[2] 2;for (int i 3; i < …

matlab批量读取目录下的文件的方法

批量处理可以提高效率&#xff0c;这里提供一个可以批量读取nc文件的代码&#xff1a; address C:\Users\Hello World!!\DESKTOP\TerraClimate_ppt\; % Get the list of files udir address; form *.nc; % Get the list of station names files GetFiles(udir,form); [n,p…

MySQL--select count(*)、count(1)、count(列名) 的区别你知道吗?

MySQL select count(*)、count(1)、count(列名) 的区别&#xff1f; 这里我们先给出正确结论&#xff1a; count(*)&#xff0c;包含了所有的列&#xff0c;会计算所有的行数&#xff0c;在统计结果时候&#xff0c;不会忽略列值为空的情况。count(1)&#xff0c;忽略所有的列…

IIS7/iis8/iis10安装II6兼容模块 以windows2022为例

因安全狗的提示 安全狗防护引|擎安装失败 可能原因是: IIS7及以上版本末安装1IS6兼容模块! .所以操作解决 如下. 在开始菜单中,找到服务器管理器.找到下图的IIS,右键添加角色和功能,找到web服务器的管理工具选项,iis6管理兼容性 打钩并安装. 如下图