应用程序中pci配置空间读写

~~~~~~~~~~~~~~~~~~~~~~~

1. 概述

主要讲述在linux操作系统中应用程序如何读写pci配置空间。

2. 基本原理

对于pci设备,由cpu通过一个统一的入口地址向pci总桥发出命令,再由相应的pci桥间接地完成具体的读写操作。对于X86结构,pci总线的设计者在I/O地址空间保留了8个字节用于这个操作:0xcf8

-

0xcff。这8个字节分成两个32位的寄存器,0xcf8是地址寄存器,0xcfc是数据寄存器。cpu先往地址寄存器中写入目标地址,然后通过数据寄存器读写数据,写入地址寄存器中的目标地址是一种包括总线号、设备号、功能号以及配置寄存器地址的综合地址。具体如下:

bit31 1

bit30-bit24 保留

bit23-bit16 总线号

bit15-bit11 设备号

bit10-bit8 功能号

bit7-bit0 寄存器地址,最低两位为0

设备的这些信息都可以通过lspci命令获取。

3. ioport读写权限

由于要通过操作ioport,所以先要获取ioport的读写权限。

能获取读写权限的函数有两个ioperm()和iopl()。

由于pci的口地址比较高,要用iopl(3)获取权限。

4. 读程序

#define

PCI_CFG_DATA 0xcfc

#define

PCI_CFG_CTRL 0xcf8

void pci_read_config_byte(unsigned char bus,

unsigned char dev, unsigned char offset, unsigned char *val)

{

unsigned

char fun = 0;

outl((0x80000000 | ((bus)<<16)

|((dev)<<11) |

((fun)<<8) | (offset

& ~0x3)), PCI_CFG_CTRL);

*val =

inl(PCI_CFG_DATA) >> ((offset

& 3) * 8);

}

void pci_read_config_word(unsigned char bus,

unsigned char dev, unsigned char offset, unsigned short *val)

{

unsigned

char fun = 0;

outl((0x80000000 | ((bus)<<16)

|((dev)<<11) |

((fun)<<8) | (offset

& ~0x3)), PCI_CFG_CTRL);

*val =

inl(PCI_CFG_DATA) >> ((offset

& 3) * 8);

}

void pci_read_config_dword(unsigned char bus,

unsigned char dev, unsigned char offset, unsigned int *val)

{

unsigned

char fun = 0;

outl((0x80000000 | ((bus)<<16)

|((dev)<<11) |

((fun)<<8) | (offset)),

PCI_CFG_CTRL);

*val =

inl(PCI_CFG_DATA);

}

很明显就是先向控制寄存器写入综合地址,格式前面已经提到,对比一下是完全一样的。然后从数据寄存器读数据即可,由于数据寄存器是32位的,如果不是读取双字,需要做移位操作。

另外一定需要注意大小端问题,如需要就要进行大小端转换,下面写程序也一样。

5. 写程序

void pci_write_config_dword(unsigned char bus,

unsigned char dev, unsigned char offset, unsigned int val)

{

unsigned

char fun = 0;

outl((0x80000000 | ((bus)<<16)

|((dev)<<11) |

((fun)<<8) | (offset)),

PCI_CFG_CTRL);

outl(val,

PCI_CFG_DATA);

}

void pci_write_config_word(unsigned char bus,

unsigned char dev, unsigned char offset, unsigned short val)

{

unsigned

long tmp;

unsigned

char fun = 0;

outl((0x80000000 | ((bus)<<16)

|((dev)<<11) |

((fun)<<8) | (offset

& ~0x3)), PCI_CFG_CTRL);

tmp =

inl(PCI_CFG_DATA);

tmp

&= ~(0xffff <<

((offset & 0x3) * 8));

tmp |= (val

<< ((offset & 0x3) *

8));

outl(tmp,

PCI_CFG_DATA);

}

void pci_write_config_byte(unsigned char bus,

unsigned char dev, unsigned char offset, unsigned short val)

{

unsigned

long tmp;

unsigned

char fun = 0;

outl((0x80000000 | ((bus)<<16)

|((dev)<<11)

|((fun)<<8) | (offset

& ~0x3)), PCI_CFG_CTRL);

tmp =

inl(PCI_CFG_DATA);

tmp

&= ~(0xff << ((offset

& 0x3) * 8));

tmp |= (val

<< ((offset & 0x3) *

8));

outl(tmp,

PCI_CFG_DATA);

}

写程序同读程序一样,先向控制寄存器写入综合地址,然后向数据寄存器写入数据。

6. 问题

上面的程序都是参考linux内核对pci空间的读写程序写的。但是在应用程序中读写pci空间和在内核中读写pci空间是完全不同的。在linux源代码中可以看到,在进行pci空间的读写操作都是在关闭中断的情况下进行的,而在用户程序空间就没有这个手段了。所以,读写可能会出错。

经过本人试验,读基本上没有出错过,而写有一定出错的概率,慎用!

有兴趣的,可以随便写个应用程序试试看。

7. 源代码

附上一份源代码,可以直接编译运行。

#include

#include

#include

static unsigned int read_pci_config_32(unsigned

char bus, unsigned char slot, unsigned char func, unsigned char

offset)

{

unsigned int v;

outl(0x80000000 |

(bus<<16) |

(slot<<11) |

(func<<8) | offset, 0xcf8);

v = inl(0xcfc);

return v;

}

unsigned char read_pci_config_8(unsigned char bus,

unsigned char slot, unsigned char func, unsigned char offset)

{

unsigned char v;

outl(0x80000000 |

(bus<<16) |

(slot<<11) |

(func<<8) | offset, 0xcf8);

v = inb(0xcfc +

(offset&3));

return v;

}

unsigned short read_pci_config_16(unsigned char

bus, unsigned char slot, unsigned char func, unsigned char

offset)

{

unsigned short v;

outl(0x80000000 |

(bus<<16) |

(slot<<11) |

(func<<8) | offset, 0xcf8);

v = inw(0xcfc +

(offset&2));

return v;

}

void write_pci_config_32(unsigned char bus,

unsigned char slot, unsigned char func, unsigned char offset,

unsigned int val)

{

outl(0x80000000 |

(bus<<16) |

(slot<<11) |

(func<<8) | offset, 0xcf8);

outl(val, 0xcfc);

}

void write_pci_config_8(unsigned char bus,unsigned

char slot, unsigned char func, unsigned char offset, unsigned char

val)

{

outl(0x80000000 |

(bus<<16) |

(slot<<11) |

(func<<8) | offset, 0xcf8);

outb(val, 0xcfc +

(offset&3));

}

void write_pci_config_16(unsigned char bus,unsigned

char slot, unsigned char func, unsigned char offset, unsigned char

val)

{

outl(0x80000000 |

(bus<<16) |

(slot<<11) |

(func<<8) | offset, 0xcf8);

outw(val, 0xcfc +

(offset&2));

}

int main(void)

{

iopl(3);

printf("0 0 0 0 = %xn", read_pci_config_16(0, 0

, 0, 0));

printf("0 0 0 2 = %xn", read_pci_config_16(0, 0

, 0, 2));

printf("0 1 0 0 = %xn",

read_pci_config_16(0, 1 , 0, 0));

printf("0 1 0 2 = %xn", read_pci_config_16(0, 1

, 0, 2));

printf("0 7 1 0 = %xn",

read_pci_config_16(0, 7 , 1, 0));

printf("0 7 1 2 = %xn", read_pci_config_16(0, 7

, 1, 2));

return 0;

}

linux 写pci配置空间,[转载]应用程序中pci配置空间读写相关推荐

  1. linux 写一个包含test的脚本程序,linux的test命令及相关shell脚本详解

    test 命令最短的定义可能是评估一个表达式:如果条件为真,则返回一个 0 值.如果表达式不为真,则返回一个大于 0 的值 - 也可以将其称为假值.检查最后所执行命令的状态的最简便方法是使用 $? 值 ...

  2. db2 参数标识符使用无效_在Python应用程序中使用配置的最佳实践

    大多数计算机应用程序都可以使用配置来指定行为,无论是通过命令行标志.环境变量还是配置文件.作为一名软件开发人员,处理配置时会遇到一些挑战,例如解析不合法的输入.验证它以及在程序的任意位置访问它.以Py ...

  3. linux java 调用c_Linux上从Java程序中调用C函数

    原则上来说,"100%纯Java"的解决方法是最好的,但有些情况下必须使用本地方法.特别是在以下三种情况: 需要访问Java平台无法访问的系统特性和设备: 通过基准测试,发现Jav ...

  4. matlab变量相加,如何在空间计量matlab程序中加入更多的变量?

    各位大神: 我用matalab软件运行了空间计量包"javp7"中的演示文件"demopanelcompare"当我用两个变量替换掉例子中的变量后,程序运行结果 ...

  5. Linux jsp php集成环境,ImageMagick在程序中调用(linux环境,jsp,php)

    最近发现图片格式为cmyk时,图片上传浏览器不能正常显示,图片缩放会变成黑屏, 后来通过google发现imagemagick的功能很强大,安装可以采用两种方法,1)直接与php编译安装,在程序中调用 ...

  6. linux的_msize()函数,定位并行应用程序中的可伸缩性问题(最透彻一篇)

    原创 梁金荣.戴君毅等 Linux阅码场 4月6日 作者简介 本文由西邮陈莉君教授研一学生梁金荣.戴君毅.马明慧翻译,宋宝华老师指导和审核.译者梁金荣.戴君毅.马明慧同学热爱开源,践行开放.自由和分享 ...

  7. log4net 在asp.net WEB应用程序中的配置

    我是一个三层架构的应用程序,将日志记录放在了业务层,并写入了数据库,整个使用操作步骤为以下步骤. 第一步 编写配置文件 文件名称为 log4net.config 内容如下 <?xml versi ...

  8. 在微信小程序中如何配置腾讯位置服务并调用

    因为很多服务都已经被封装好了,所以我们只需要调用引入配置就行了. 下面进入正题,我们要先 一.进入到腾讯位置服务腾讯位置服务 - 立足生态,连接未来 先注册一个账号,然后点击控制台,进去以后找到左侧的 ...

  9. 应用程序添加到服务器,在同一应用程序中的配置服务器和eureka服务器:尝试连接到localhost:8761...

    我有一个spring-boot应用程序,可用于在开发和测试环境中设置a spring cloud config server和a eureka server.奇怪的是localhost:8761,即使 ...

最新文章

  1. Caffe训练ImageNet
  2. runfile python_python文件执行路径问题
  3. 阻塞、非阻塞、超时(同步与异步)
  4. ABAP的数据字典DDIC和Hybris Commerce的类型系统Type system
  5. 搜索训练1 [8数码问题]
  6. 产品经验谈:一文讲清楚商业模式梳理怎么做?
  7. 科研|诺奖得主本庶佑: 不要相信论文里写的东西,《自然》《科学》这些杂志上的观点有九成是不正确的...
  8. HighCharts使用更多图表HighChartsMore
  9. android中openMax的实现
  10. JSON字符串,JSON对象的相互转换
  11. pert图java_项目管理之甘特图和工程网络图(PERT图)(一)
  12. c语言编程输出一到十,c语言编程输出1?
  13. 关于Olly Dbg的使用报告
  14. 计算机方向的综述投稿哪个期刊,人工智能方向论文投稿期刊
  15. html缩放惯性,js带滚动惯性的视觉差特效插件
  16. 阿里巴巴Java开发手册github地址
  17. Win10 Linux 子系统(WSL)监听端口报错Error `IN6_IS_ADDR_V4MAPPED (sin6-sin6_addr.s6_addr32)` Failed的处理
  18. 《嫌疑人X的献身》读后感
  19. PHP curl 中文gbk转utf8
  20. 小兵大乱斗服务器维修吗,这个游戏有点意思《小兵大乱斗》最新评测来袭

热门文章

  1. 用MyQR 制作动态二维码
  2. LMV324IPWR四路低电压轨至轨输出运算放大器TI
  3. ubuntu16.04下使用Modbus RTU协议控制Robotiq
  4. 超表面透镜相位matlab,可调超表面的抛物线梯度相位修正方法及变/定焦距透镜的制作方法...
  5. PHP设计模式 二 (单例 工厂 注册)
  6. android qq音乐布局,仿QQ音乐底部栏
  7. 2019年中国公有云厂商收入利润排名
  8. matlab的探查功能
  9. 实习第三周小记-----生活在于经历
  10. 中国目前最具竞争力的二线城市有哪些?