【C语言】linux内核pci_iomap

一、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);

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IP如何异地共享文件?

【天联】 组网由于操作简单、跨平台应用、无网络要求、独创的安全加速方案等原因&#xff0c;被几十万用户广泛应用&#xff0c;解决了各行业客户的远程连接需求。采用穿透技术&#xff0c;简单易用&#xff0c;不需要在硬件设备中端口映射即可实现远程访问。 异地共享文件 在…

使用GO对PostgreSQL进行有意思的多线程压测

前言 针对PostgreSQL进行压缩&#xff0c;有很多相关的工具。有同学又要问了&#xff0c;为何还要再搞一个&#xff1f;比如&#xff0c;pgbench, sysbench之类的&#xff0c;已经很强大了。是的&#xff0c;它们都很强大。但有时候&#xff0c;在一些特殊的场景&#xff0c;可…

功能强大的国外商业PHP在线教育系统LMS源码/直播课程系统

功能强大的国外商业PHP在线教育系统LMS/在线教育市场源码/直播课程系统 Proacademy是在线教育一体化的解决方案&#xff0c;用于创建类似于Udemy、Skillshare、Coursera这种在线教育市场。 这个平台提供在线课程&#xff0c;现场课程&#xff0c;测验等等&#xff0c;并有一个…

单链表交叉分离,运用头插法,尾插法(算法库应用)

原文博客链接:单链表分离(头插法和尾插法的结合,理解指针变换)_3.对任务1或者2中创建的某一个单链表{a1,b1,a2,b2,...,an,bn},编写一个算法将-CSDN博客 函数实现: /************************************************** 函数名:separate_LinkList 功 能: 把一个链表,交叉新建…

如何在jupyter使用新建的虚拟环境以及改变jupyter启动文件路径。

对于刚刚使用jupyter的新手来说&#xff0c;经常不知道如何在其中使用新建的虚拟环境内核&#xff0c;同时&#xff0c;对于默认安装的jupyter&#xff0c;使用jupyter notebook命令启动 jupyter 以后往往默认是C盘的启动路径&#xff0c;如下图所示&#xff0c;这篇教程将告诉…

HBase的Python API操作(happybase)

一、Windows下安装Python库&#xff1a;happyhbase pip install happybase -i https://pypi.tuna.tsinghua.edu.cn/simple 二、 开启HBase的Thrift服务 想要使用Python API连接HBase&#xff0c;需要开启HBase的Thrift服务。所以&#xff0c;在Linux服务器上&#xff0c;执行…

软考数据库

目录 分值分布1. 事务管理1.1 事物的基本概念1.2 数据库的并发控制1.2.1 事务调度概念1.2.2 并发操作带来的问题1.2.3 并发控制技术1.2.4 隔离级别&#xff1a; 1.3 数据库的备份和恢复1.3.1 故障种类1.3.2 备份方法1.3.3 日志文件1.3.4 恢复 SQL语言 分值分布 1. 事务管理 1.…

读所罗门的密码笔记04_社会信用

1. 人工智能 1.1. 人工智能可以帮助人们处理复杂的大气问题&#xff0c;完善现有的气候变化模拟&#xff0c;帮助我们更好地了解人类活动对环境造成的危害&#xff0c;以及如何减少这种危害 1.2. 人工智能也有助于减少森林退化和非法砍伐 1.3. 人工智能甚至可以将我们从枯燥…

【数据结构】树、二叉树与堆(长期维护)

下面是关于树、二叉树、堆的一些知识分享&#xff0c;有需要借鉴即可。 一、初识树&#xff08;了解即可&#xff09; 1.树的概念 概念&#xff1a;一种非线性数据结构&#xff0c;逻辑形态上类似倒挂的树 树的构成&#xff1a;由一个根左子树右子树构成&#xff0c;其中子树…

springboot使用com.github.binarywang 包实现微信网页上的支付和退款

前提 微信小程序中实现微信支付是从小程序中调去微信支付的界面直接进行支付&#xff0c;那么在pc端需要实现微信的支付呢&#xff0c;是需要出现一个二维码让用户使用扫码支付的。 注意&#xff1a; 需要实现pc端的微信支付&#xff0c;需要在微信商户平台开通native支付&…

CUDA版本支持的pytorch版本

PyTorch 1.0.x - 支持 CUDA 7.5 PyTorch 1.1.x - 支持 CUDA 8.0 PyTorch 1.2.x - 支持 CUDA 9.0 PyTorch 1.3.x - 支持 CUDA 9.2 PyTorch 1.4.x - 支持 CUDA 10.1 PyTorch 1.5.x - 支持 CUDA 10.2 PyTorch 1.6.x - 支持 CUDA 11.0 PyTorch 1.7.x - 支持 CUDA 11.0/11.1 PyTorch…

QtCreator调试时无法显示std::string的内容

在银河麒麟V10或Ubuntu下使用QtCreator调试代码时&#xff0c;std::string类型变量在大多数情况下不显示实际内容&#xff0c;而是显示"<无法访问>"字样&#xff0c;鼠标点击进去也是看不见任何有用信息&#xff0c;这样非常影响调试效率&#xff0c;为此&…

Android-Handler详解_使用篇

本文我将从Handler是什么、有什么、怎们用、啥原理&#xff0c;四个方面去分析。才疏学浅&#xff0c;如有错误&#xff0c;欢迎指正&#xff0c;多谢。 1.是什么 因为Android系统不允许在子线程访问UI组件&#xff0c;否则就会抛出异常。所以咱们平实用的最多的可能是在子线…

国际伦敦金行情分析中的趋势分析方法

国际伦敦金行情走势复杂多变。近期&#xff0c;金价曾经一度刷新历史的新高点至2222&#xff0c;但就在当天&#xff0c;金价又快速下跌跌超过30美元。不过这么多变的伦敦金行情也为我们的交易创造了空间&#xff0c;有空间就等于有机会&#xff0c;只要我们能够掌握国际伦敦金…

AWS SES发送邮件时常见的错误及解决方法?

AWS SES发送邮件如何做配置&#xff1f;使用AWS SES发信的限制&#xff1f; 在使用AWS SES发送邮件时&#xff0c;可能会遇到一些常见的错误。AokSend将介绍一些常见的AWS SES发送邮件错误及其相应的解决方法&#xff0c;帮助用户更好地利用AWS SES进行邮件发送。 AWS SES发送…

在 Windows 11 上安装 MongoDB

MongoDB 是一个流行的 NoSQL 数据库&#xff0c;它提供了灵活的数据存储方案&#xff0c;而 MongoDB Compass 则是一个可视化管理工具&#xff0c;可以更轻松地与 MongoDB 数据库交互和管理。在本文中&#xff0c;我们将介绍如何在 Windows 11 上安装 MongoDB&#xff0c;并配置…

手机短信验证码自动转发到服务器

今天写一个自动化处理程序&#xff0c;需要验证码登录&#xff0c;怎么样把手机收到的短信自动转发到服务器接口呢&#xff1f; 利用ios手机快捷指令的功能 打开快捷指令点击中间自动化点击右上角号选择信息信息包含选取&#xff0c;输入验证码选择立即执行点击下一步按下图配…

JavaWeb解压缩漏洞之ZipSlip与Zip炸弹

前言 前面一篇博文《Android Zip解压缩目录穿越导致文件覆盖漏洞》介绍过 Android 系统 Zip 文件解压缩场景下的目录穿越漏洞&#xff0c;近期在学习 JavaWeb 代码审计的时候从 github 看到《OpenHarmony-Java-secure-coding-guide.md》中“从 ZipInputStream 中解压文件必须进…

搭建机器人产业发展重要展示平台“2024南京国际机器人展览会”

2024南京国际智能机器人展览会 2024 Nanjing Intelligent Robot Expo 时间:2024年11月22-24日 地点:南京国际博览中心 南京&#xff0c;这座历史悠久的文化名城&#xff0c;如今正站在机器人产业发展的前沿。随着全球科技的飞速进步&#xff0c;机器人产业已经成为推动经济社…

记一次由gzip引起的nginx转发事故

故事背景 书接前几篇文章&#xff0c;仍然是交付甲方遇到的一个特殊诉求&#xff0c;从而引发了本期的事故。甲方的诉求是前端的请求过来&#xff0c;需要加密&#xff0c;但是要经过waf&#xff0c;必须要求是请求明文&#xff0c;那就要在waf和nginx之间做一个解密前置应用处…