前言

最近楼主比较苦逼啊,主管布置了一道访问pci的作业,这个作业使用io方式还可以非常浪地将所有的东西都给读取出来,虽然不能读取出pci-e设备的所有信息,但是还是可以将256位的其他东西给读出来的。

本文将先从io访问模式进行对pci访问的设置,在这里我所使用的包含了dos和linux,这样可以看到这2个的系统代码的不同。

pci简介

PCI总线是一种高性能32位或者64位的多路复用地址或者数据行的总线。相当于现实生活中的公路,是所谓的信号通道。可以在这上面传输数据、控制信号等等。

作用:高度集成外围控制其、外围插件和处理器/内存系统之间的互连机制。

如果要访问PCI 设备,首先要确定PCI设备在系统中的物理连接情况。描述这个连接情况的数据是“总线号”、“设备号”和“功能号”。一个系统可以有256个PCI总线,每个总线上可以有32个设备,每个设备可以具有8个功能(每个功能作为一个PCI设备)。当这三个数据确定的时候,就可以在系统中唯一确定一个PCI 设备。

8~10:功能位. 有时候,一个pci设备对应多个功能.将每个功能单元分离出来,对应一个独立的pci device

11~15位:设备号 对应该pci总线上的设备序号

16~23位:总线号 根总线的总线号为0.每遍历到下层总线,总线号+1

PCI拓扑结构图

在上图的总线结构中,ethernet设备和pci-pci bridge的同类型资源空间必须要是pci bus0的一个子集

例如,pci bus 0的I/O端口资源是0x00CC~0x01CC. Ethernet设备的I/O范围的是0x00CC~0x0xE0.那么pci-pci bridge的I/O端口范围就必须要在0x0xE0~0x01CC之间.

同样,SCSI和VIDEO同类型资源必须要是pci_bus1的子集.pci bus1上有一个pci桥,对应的资源也就是它所连桥上的资源.即pci_bus->self.也就是说,下层总线的资源是它上层总线资源的子集。上层总线资源是下层总线资源的父集。

其实,每个PCI设备的资源地始地址都是由操作系统设置的.在x86上,都由bios设置好了.

pci配置空间

PCI配置空间是一块容量为256字节并具有特定记录结构或模型的地址空间,通过配置空间,我们可以了解该PCI设备的一些配置情况,进而控制该设备,除主总线桥以外的所有PCI设备都必须事先配置空间.

配置空间的前64个字节叫头标区,头标区又分成两个部分,第一部分为前16个字节,在各种类型的设备中定义都是一样的,其他字节随各设备支持的功能不同而有所不同,位于偏移0EH的投标类型字段规定了是何种布局,目前有三种头标类型,头标类型1用于PCI-PCI桥,头标类型2用于PCI-CARDBUS桥,头标类型0用于其他PCI设备,下图为头标类型0的头标区布局。



头标区中有5个字段涉及设备的识别。

  • 供应商识别字段(Vendor ID)

偏移:00H。该字段用以标明设备的制造者。一个有效的供应商标识由PCI SIG来分配,以保证它的唯一性。0FFFFH是该字段的无效值。

  • 设备识别字段(Device ID)

偏移:02H。用以标明特定的设备,具体代码由供应商来分配。

  • 版本识别字段(Revision ID)

偏移:08H。用来指定一个设备特有的版本识别代码,其值由供应商提供,可以是0。

  • 头标类型字段(Header Type)

偏移:0EH。该字段有两个作用,一是用来表示配置空间头标区第二部分的布局类型;二是用以指定设备是否包含多功能。位7用来标识一个多功能设备,位7为0表明是单功能设备,位7为1表明是多功能设备。位0-位6表明头标区类型。

  • 分类代码字段(Class Code)

偏移:09H。标识设备的总体功能和特定的寄存器级编程接口。该字节分三部分,每部分占一个字节,第一部分是基本分类代码,位于偏移0BH,第二部分叫子分类代码,位于偏移0AH处,第三部分用于标识一个特定的寄存器级编程接口。

io口访问pci设备

在dos下申请相关的接口就可以得到io口,通过cf8和cfc的模式进行读取遍历pci设备。

#include <stdio.h>
typedef unsigned long DWORD;
typedef unsigned int WORD;
#define MK_PDI(bus,dev,func) (WORD)((bus<<8)|(dev<<3)|(func))
#define MK_PCIaddr(bus,dev,func) (DWORD)(0xf8000000L|(DWORD)MK_PDI(bus,dev,func)<<8)
#define PCI_CONFIG_ADDRESS 0xCF8
#define PCI_CONFIG_DATA 0xCFC
DWORD inpd(int inport)
{
DWORD data;
asm mov dx,inport;
asm lea bx,data;
__emit__(
0x66,0x50,
0x66,0xED,
0x66,0x89,0x07,
0x66,0x58);
return data;
} void outpd(int outport,DWORD addr)
{
asm mov dx,outport;
asm lea bx,addr;
__emit__(
0x66,0x50,
0x66,0x8B,0x07,
0x66,0xEF,
0x66,0x58);
}
DWORD GetData(DWORD addr)
{
DWORD data;
outpd(PCI_CONFIG_ADDRESS,addr);
data = inpd(PCI_CONFIG_DATA);
return data;
}
int main()
{
int bus,dev,func;
DWORD addr,addr1,addr2,addr3;
DWORD data,data1,data2,data3;
printf("Bus#\tDev#\tFunc#");
printf("\n");
for (bus = 0; bus <= 0x63; ++bus)
{
for (dev = 0; dev <= 0x1F; ++dev)
{
for (func = 0; func <= 0x7; ++func)
{
addr = MK_PCIaddr(bus,dev,func);
data = GetData(addr);
if((WORD)data!=0xFFFF)
{
printf("%2.2x\t%2.2x\t%2.2x\t",bus,dev,func);
printf("\n");
}
}
}
}
return 0;
}

在linux系统下就很简单了,直接看代码吧!

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/io.h>
#define PCI_MAX_BUS 255
#define PCI_MAX_DEV 31
#define PCI_MAX_FUN 7
#define PCI_BASE_ADDR 0x80000000L
#define CONFIG_ADDR 0xcf8
#define CONFIG_DATA 0xcfc typedef unsigned long DWORD;
typedef unsigned int WORD;
typedef unsigned long DWORD; int main()
{
WORD bus,dev,fun;
DWORD addr,data;
int ret;
printf("bus#\tdev#\tfun#\t");
printf("\n");
ret = iopl(3);
if(ret < 0)
{
perror("iopl set error");
return -1;
}
for(bus = 0; bus <= PCI_MAX_BUS; bus++)
for(dev = 0; dev <= PCI_MAX_DEV; dev++)
for(fun = 0; fun <= PCI_MAX_FUN; fun++)
{
addr = PCI_BASE_ADDR|(bus << 16)|(dev << 11)|(fun << 8);
outl(addr,CONFIG_ADDR);
data = inl(CONFIG_DATA);
if((data != 0xffffffff)&&(data != 0))
{
printf("%2x\t%2x\t%2x",bus,dev,fun);
printf("\n");
}
}
ret = iopl(0);
if(ret < 0){
perror("iopl set error");
return -1;
}
return 0; }

后记

今天暂时到这里,下一章将介绍什么是mmio,如何实现的!欢迎关注!

c语言-遍历pci设备(1)io访问的更多相关文章

  1. c语言-遍历pci设备(2)mmio访问

    前言 今天其实我在公司也没有做什么,但是昨天就把pcie遍历的mmio形式做了出来,赞扬公司的台湾服务器,至少我可以使用google来去搜索我想要的资料和答案,有一位大神在台湾的论坛上发布了一片博文, ...

  2. 【DPDK】谈谈DPDK如何实现bypass内核的原理 其一 PCI设备与UIO驱动

    [前言] 随着网络的高速发展,对网络的性能要求也越来越高,DPDK框架是目前的一种加速网络IO的解决方案之一,也是最为流行的一套方案.DPDK通过bypass内核协议栈与内核驱动,将驱动的工作从内核态 ...

  3. 3.1 PCI设备BAR空间的初始化

    在PCI Agent设备进行数据传送之前,系统软件需要初始化PCI Agent设备的BAR0~5寄存器和PCI桥的Base.Limit寄存器.系统软件使用DFS算法对PCI总线进行遍历时,完成这些寄存 ...

  4. 008 PCI设备BAR空间的初始化

    一.PCI设备BAR空间的初始化 在PCI Agent设备进行数据传送之前,系统软件需要初始化PCI Agent设备的BAR0~5寄存器和PCI桥的Base.Limit寄存器.系统软件使用DFS算法对 ...

  5. Linux驱动设计——内存与IO访问

    名词解释 内存空间与IO空间 内存空间是计算机系统里面非系统内存区域的地址空间,现在的通用X86体系提供32位地址,寻址4G字节的内存空间,但一般的计算机只安装256M字节或者更少的内存,剩下的高位内 ...

  6. PCI 设备详解二

    上篇文章主要从硬件的角度分析了PCI设备的特性以及各种寄存器,那么本节就结合LInux源代码分析下内核中PCI设备的各种数据结构以及相互之间的联系和工作机制 2016-10-09 注:一下代码参考LI ...

  7. PCI 设备详解一

    2016-10-09 其实之前是简单学习过PCI设备的相关知识,但是总感觉 自己的理解很函数,很多东西说不清楚,正好今天接着写这篇文章自己重新梳理一下,文章想要分为三部分,首先介绍PCI设备硬件相关的 ...

  8. 系统虚拟化学习笔记——PCI设备

    内容摘自<系统虚拟化:原理与实现> PCI 总线架构 PCI总线是典型的树结构.把北桥中host-PCI桥看做根,总线中其他PCI-PCI桥,PCI-ISA桥(ISA总线转PCI总线桥)等 ...

  9. linux PCI设备初始化过程

    linux PCI设备初始化过程 start_kernel->rest_init 这个函数会启动一个核心线程0, 核心线程然后调用init -> do_basic_setup. 然后我们开 ...

随机推荐

  1. CSS 基础 例子 图片拼合技术

    利用background-position xpos ypos 就是以图片的左上角顶点为原点,往下和右都为正,反之为负,移动图片 如: background-position: 15px 20px;( ...

  2. Opencv打开摄像头,读不到图像,一般来说先读取第一帧,舍弃,然后就正常了

    舍弃第一帧的程序: cap >> img; cv::waitKey(100);  if (cvWaitKey(5) == 27) break; cap >> img;

  3. Nginx 实现端口转发

    https://www.cnblogs.com/zhaoyingjie/p/7248678.html Nginx 实现端口转发 什么是端口转发 当我们在服务器上搭建一个图书以及一个电影的应用,其中图书 ...

  4. IIS日志存入数据库之一:ODBC

    园内@Fish Li的文章<IIS日志-网站运维的好帮手>中介绍将IIS的文本格式的文件导入数据库的方法.在实践中,我们发现导数据的速度很慢,一个200M的日志文件居然要近100分钟.我们 ...

  5. neo4j图数据库安装以及基本操作命令

    neo4j图数据安装以及基本操作命令 neo4j安装配置使用, 安装环境:Ubuntu系统 jdk1.8 (neo4j 只支持jdk1.8以上版本) 下载 neo4j neo4j的下载window可以 ...

  6. 在WPF中将图片转换成3D图像并可以旋转

    时光偷走的,永远都是我们眼皮底下看不见的珍贵. https://pan.baidu.com/s/14dk-OU2SR0nxXj2bL4bVpQ 源码网站https://www.codeproject. ...

  7. 前台获取枚举的key值

    如: Enum ShowPosition { 首页 = 0,一级分类页 = 1,二级分类页 = 2 } 想获得汉字对应的数字,可用GetHashCode() html展示如下:循环枚举 @foreac ...

  8. AngularJS指令封装高德地图组件

    1 概述 公司移动门户原来是基于AngularJS指令封装的百度地图组件,用于签到.签退.定位等功能,在使用过程中发现百度地图频繁的弹出广告,所以打算重新引用其它地图组件,最后决定基于AngularJ ...

  9. mac下查看jdk安装版本及安装目录

    使用IntelliJ idea新建工程时需要查看jdk安装目录,记录下来为以后备用. mac自带jdk,查看jdk版本: IcarusdeMacBook-Pro:~ icarus$ java -ver ...

  10. Mongodb--基础(连接,增删改查,数据类型)

    mongodb 日常启动命令 mongod --dbpath D:\data\db 一.启动,连接 mongodb是一个非关系型数据库 1. 启动MongoDB服务: 安装时我并没有将mongodb服 ...