【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,则返回NULLif (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资源也不是内存资源,返回NULLreturn 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 0struct 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.mzph.cn/news/775481.shtml

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

相关文章

JDK8的下载安装与环境变量配置教程

前言 官网下载&#xff1a;Java Archive Downloads - Java SE 8u211 and later 现在应该没人用32位的系统了吧&#xff0c;直接下载Windows x64 Installer jdk-8u391-windows-x64.exe 一、安装JDK 1. 打开jdk-8u391-windows-x64.exe 2. 直接下一步 3. 这个地方不要动他&…

servlet开发详解

一、什么是servlet&#xff0c;干什么用的&#xff1f;&#xff1f;&#xff1f; tomcat作为一个web服务器&#xff0c;也称作servlet容器。servlet只有放在web服务器中才能运行&#xff0c;不能独立运行。tomcat这个容器要做三件事&#xff1a;接收请求、处理请求和响应请求。…

从根本上优雅地解决 VSCode 中的 Python 模块导入问题

整体概述&#xff1a; 在我尝试运行 test_deal_file.py 时&#xff0c;我遇到了一个 ModuleNotFoundError 错误&#xff0c;Python告诉我找不到名为 controllers 的模块。这意味着我无法从 deal_file.py 中导入 read_excel 函数。 为了解决这个问题&#xff0c;我尝试了几种方法…

【ML】类神经网络训练不起来怎么办 5

【ML】类神经网络训练不起来怎么办 5 1. Saddle Point V.S. Local Minima(局部最小值 与 鞍点)2. Tips for training: Batch and Momentum(批次与 动量)2.1 Tips for training: Batch and Momentum2.2 参考文献:2.3 Gradient Descent2.4 Concluding Remarks(前面三讲)3.…

【QT】:基本框架

基本框架 一.创建程序二.初识函数1.main2.Widget.h3.Wight.cpp4.Wight.ui5.文件名.pro 三.生成的中间文件 本系列的Qt均使用Qt Creator进行程序编写。 一.创建程序 二.初识函数 1.main 2.Widget.h 3.Wight.cpp 4.Wight.ui 此时再点击编辑&#xff0c;就看到了ui文件的本体了。…

数仓建设实践——58用户画像数仓建设

目录 一、数据仓库&用户画像简介 1.1 数据仓库简介 1.2 数据仓库的价值 1.3 用户画像简介 1.4 用户画像—标签体系 二、用户画像数仓建设过程 2.1 画像数仓—背景&现状 2.2 画像数仓—整体架构 2.3 画像数仓—研发流程 2.4 画像数仓—指标定义 2.5 画像数仓…

【数据库管理操作】Mysql 创建学生数据库及对数据表进行修改

MySQL 创建学生成绩数据库 1.创建数据库 create database studentscore;创建完成之后&#xff0c;如果需要使用该数据&#xff0c;使用use命令 use studentscore;创建表前查看当前数据库中包含的表 show tables; 2.创建bclass表 create table bclass( class_id char(8) …

Sublime 彻底解决中文乱码

1. 按ctrl&#xff0c;打开Console&#xff0c;输入如下代码&#xff1a; import urllib.request,os; pf Package Control.sublime-package; ipp sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHand…

ubuntu之搭建samba文件服务器

1. 在服务器端安装samba程序 sudo apt-get install samba sudo apt-get install smbclient 2.配置samba服务 sudo gedit /etc/samba/smb.conf 在文件末尾追加入以下配置 [develop_share] valid users ancy path /home/ancy public yes writable y…

国内ip切换app,让切换ip变得简单

在数字化快速发展的今天&#xff0c;互联网已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着网络应用的深入&#xff0c;用户对于网络环境的需求也日益多样化。其中&#xff0c;IP地址作为网络中的关键标识&#xff0c;其切换与管理显得尤为重要。为了满足用户对于IP…

每日一题 --- 链表相交[力扣][Go]

链表相交 题目&#xff1a;面试题 02.07. 链表相交 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交**&#xff1a;** 题目数据 保证 整个链式结…

【C语言】Infiniband驱动init_dev_assign函数

一、注释 一个内核模块的初始化函数&#xff0c;用于分配和初始化某些资源。以下是对代码块的逐行中文注释&#xff1a; // 定义一个初始化设备分配的函数 static void init_dev_assign(void) {int i 1;spin_lock_init(&dev_num_str_lock); // 初始化自旋锁if (mlx4_fil…

R: 网状Meta分析进行模型构建及图形绘制

网状meta分析的制作步骤主要包括&#xff1a; 1. 绘制网状证据图 2. 普通Meta分析&#xff08;两两之间的直接比较&#xff09; 3. 网状Meta分析&#xff08;整合直接比较和间接比较的结果&#xff0c;绘制相关图形&#xff09; 4. 绘制累积概率排序图 5. 三个假设的检验…

江协STM32:点亮第一个LED灯和流水灯

很多单片机都是高电平弱驱动&#xff0c;低电平强驱动&#xff0c;所以这里是低电平有效 点亮一个LED灯 操作STM32的GPIO需要三个操作&#xff1a; 第一个使用RCC开启GPIO的时钟 第二步使用GPIO_Init函数初始化GPIO 第三步使用输出或输入函数控制GPIO 1.使用RCC开启GPIO的时…

游戏开发笔记:游戏海外版本时区问题(解释时区问题,分解为js写法和lua写法来分析记录,整理出对应语言的相关函数方法。)

对于海外游戏而言,与时间相关的功能,都不能忽略时区的计算。根据 ‘ 服务端资源是有限的,客户端资源是无穷无尽的 ’的定义来说,基本上时区包括时间的计算都是由客户端来进行计算,今天内容也是围绕客户端来展开。 时区算法常见的时间描述时区需要计算的点在lua语言中的写…

Docker数据卷挂载

一、容器与数据耦合的问题: 数据卷是虚拟的&#xff0c;不真实存在的&#xff0c;它指向文件中的文件夹 &#xff0c;属主机文件系统通过数据卷和容器数据进行联系&#xff0c;你改变我也改变。 解决办法&#xff1a; 对宿主机文件系统内的文件进行修改&#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;执行…

Day23:事务管理、显示评论、添加评论

事务管理 事务的定义 什么是事务 事务是由N步数据库操作序列组成的逻辑执行单元&#xff0c;这系列操作要么全执行&#xff0c;要么全放弃执行。 事务的特性(ACID) 原子性(Atomicity):事务是应用中不可再分的最小执行体&#xff08;事务中部分执行失败就会回滚 。一致性(C…

Windows入侵排查

目录 0x00 前言 0x01 入侵排查思路 1.1 检查系统账号安全 1.2 检查异常端口、进程 1.3 检查启动项、计划任务、服务 0x00 前言 当企业发生黑客入侵、系统崩溃或其它影响业务正常运行的安全事件时&#xff0c;急需第一时间进行处理&#xff0c;使企业的网络信息系统在最短时…

6_相机坐标系_相机4个坐标系详述

相机系列文章是用来记录使用opencv3来完成单目相机和6轴机械臂手眼标定。本人吃饭的主职是linux下6轴机械臂相关应用开发。但对于机械臂运动学、相机应用等都非常感兴趣&#xff0c;所以对一些线性代数基础薄弱又想深入了解机械臂内部运算的同志比较有体会。由于是探索性学习&a…