前言

最近楼主比较苦逼啊,主管布置了一道访问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. hdu5016

    题意:给定一个n个点的图,这个图是一棵树,然后有些点建立了集市.并且没有集市的地方去集市一定是去最近的,如果距离相同,那么则去标号最小的..现在你还能在建一个集市,问建完这个集市最多有多少个点来这里. ...

  2. 16位CRC校验_Delphi

    unit Modbus_main; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, G ...

  3. Android-Kotlin简单计算器功能

    上一篇博客 Android-Kotlin-配置/入门 配置好了 AndroidStudio Kotlin 的环境: 选择包名,然后右键: 选择Class类型,会有class: 创建CounterCla ...

  4. cnn公式推导

    CNN公式推导 1 前言 在看此blog之前,请确保已经看懂我的前两篇blog[深度学习笔记1(卷积神经网络)]和[BP算法与公式推导].并且已经看过文献[1]的论文[Notes on Convolu ...

  5. 201621123018《java程序设计》第11周作业总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1. 源代码阅读:多线程程序BounceThread 1.1 BallR ...

  6. [Umbraco] DocumentType设计指南

    1. 命名规则 1.1. 文档类型(DocumentType)命名规则 图 1. Document Type命名示例 名称(Name)   采用帕斯卡命名法 如:TextPage 别名(Alias)  ...

  7. HTTP响应状态码 含义

    100 客户端可以继续 101 指示服务器正根据 Upgrade 头切换协议 200 请求正常成功 201 指示请求成功并在服务器上创建了一个新资源 202 指示已接受请求进行处理但处理尚未完成 20 ...

  8. 课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 1、10个测验题(Neural Network Basics)

    --------------------------------------------------中文翻译---------------------------------------------- ...

  9. Hadoop和Apache Spark的异同

    谈到大数据,相信大家对Hadoop和Apache Spark这两个名字并不陌生.但我们往往对它们的理解只是提留在字面上,并没有对它们进行深入的思考,下面不妨跟我一块看下它们究竟有什么异同. 1.解决问 ...

  10. Metasploit数据库问题汇总

    数据库在metaspoit中是相当重要的,当做一个大型渗透测试项目的时候,收集到的信息是相当大的,当和你的同伴一起协同作战的时候,你们可能 在不同的地方,所以数据共享很重要了!而且Metasploit ...