PCI配置空间访问

x86(32位)处理器 有三种地址空间:

1、Memory Address Space,CPU直接访问的内存空间0~4G(32位);

2、I/O Address Space ,io端口,0~0xFFFF(64K),通过in、out 指令直接访问,

3、PCI Configuration Address Space(PCI配置空间) 0~0xFFFFFF (16M)。

 PCI配置空间访问有4种方式:pci_bios、pci_conf1、pci_conf2、pci_mmcfg

PCIconf1 PCI conf2  其实也是用in、out指令,该方式只能访问256B。

在reactos0.17中有完整的代码

当0xCF8-CFB作为单独的Byte使用时,往0xCFB的bit0写1意味着使用PCIconf1,写0使用PCI conf2,conf2已经废弃不用    WritePortByte(0xCFB, 0x01);
然后往0xCF8-CFB写入地址0x80000000,如果读回来的还是0x80000000说明系统中有PCI总线,

pci_mmcfg应该是MMIO方式,

1)通过主桥(Host Bridge)中的 IO 映射地址端口(Address Port )和资料端口(Data Port)进行索引来间接访问 PCI 配置空间。地址端口(Address Port )位于 IO 地址 CF8h-CFBh,是一个大小为32 bits的暂存器,

2)Direct Memory Access (DMA)

PCIe则引入了一种新的Configuration Address Space访问方式:将其直接映射到了Memory Address Space当中。

简化代码,做一些基本功能测试

typedef struct _PCI_TYPE_HEADER {
	USHORT vendorID, deviceID;
	USHORT command, status;    //
	UCHAR revID,ProgrammingInterface,SubClassCode,BaseClassCode; //	//	其中 BaseClassCode 将 PCI 设备分类为显卡、网卡、PCI 桥等设备;
	//SubClassCode 对这些设备进一步细分;
	//而 Interface 定义编程接口。
	UCHAR CacheLineSize, LatencyTimer, HeaderType, bist;
	ULONG BaseAdder0, BaseAdder1;
	union {
		struct {
			ULONG BaseAdder2;
			ULONG BaseAdder3;
			ULONG BaseAdder4;
			ULONG BaseAdder5;
			ULONG CardBusClsBponiter;
			USHORT SubsysVendorID,SubSysID;
			ULONG ExpRomBaseAddress0;
			ULONG CapabilityPointer0;//(CapPointer0+Reserved)
			ULONG Reserved;
			UCHAR interLine0, interPin0, MinGnt, MaxLat;
		}TYPE_0_HEADER;
		struct {
			UCHAR PrimaryBus, secondaryBus, subBus, SecLatTimer;
			UCHAR ioBase, ioLimit;
			USHORT SecondaryStatus;
			USHORT memBase,memLimit;
			USHORT prefMemBase,PreMemLimit;
			ULONG PrefBase32,PrefLimit32;
			USHORT iobase16,ioLimit16;
			ULONG CapPointer1;//(CapPointer0+Reserved)
			ULONG ExpRomBaseAddress1;
			UCHAR interLine1, interPin1;
			USHORT bridgeControl;
		}TYPE_1_HEADER;
		char CardBusCls[192];
	};

} PCI_TYPE_HEADER, *PPCI_TYPE_HEADER;
#define PCI_CONF1_ADDRESS(bus, dev, fn) \
(0x80000000 | (bus  << 16) | (dev << 11) | (fn << 8))
#define PCI_CONFIG  0xCF8
#define PCI_DATA    0xCFC
DWORD read_pci_ulong(DWORD baseaddr, DWORD reg) {
	WritePortDword(PCI_CONFIG, baseaddr | ((reg & 0x3F) << 2));
	return ReadPortDword(PCI_DATA);
}
void pci_scan() {
	//domain(总线域)、bus(总线号)、dev(设备) func函数号、reg(寄存器号)
	int bus, dev, func, reg;
	DWORD dwAddr;
	PCI_TYPE_HEADER pth;
	// pci 配置空间的具体到代码中的访问有4种方式:pci_bios、pci_conf1、pci_conf2、pci_mmcfg。最优的方式是 mmcfg
	// I/O 访问的方式只可以访问配置空间的前256字节,而使用 mmcfg 的方式则可以完全支持 PCIE 的扩展寄存器即4K字节的配置
	//前64位是header 后192位是CapabilityPointer,这是个偏移值
//	WritePortByte((PUCHAR) 0xCFB, 0x01);
	for (bus = 0; bus < 256; ++bus) {
		for (dev = 0; dev < 32; ++dev) {
			for (func = 0; func < 8; ++func) {
				dwAddr = PCI_CONF1_ADDRESS(bus, dev, func);
				*((PULONG) &pth) = read_pci_ulong(dwAddr, 0);
				if ((pth.deviceID != 0xFFFF) && (pth.vendorID != 0)) {
					//ID前面已经读取,前16为header
					for (reg = 1; reg < 16; reg++) {
						*(PULONG) (((ULONG) &pth) + reg * 4) = read_pci_ulong(
								dwAddr, reg);
					}

					DbgPrint("b=%x, d=%x,f=%x;", bus, dev, func);
					DbgPrint("did=%x,vid=%x,bcc=%x,scc=%x;", pth.deviceID,
							pth.vendorID, pth.BaseClassCode, pth.SubClassCode);
					DbgPrint("ht=%x ba=%x\n", pth.HeaderType, pth.BaseAdder0);
				}
				//printf("-\t-\t-\t-\n");

			}
		}
	}

	return;
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麻雀123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值