设备虚拟化基础 - PCI

文章详细介绍了PCI设备的配置空间概念,包括其作用、结构和预定义空间的解析。接着,讲述了如何通过配置空间发现和访问PCI设备,重点解析了Linux内核中的接口`pci_read_config_*`。此外,文章讨论了Virtio设备的自定义空间和CapabilitiesList,以及Linux内核如何读取这些信息。最后,展示了`virtio_pci_modern_probe`函数的代码,解释了如何遍历和解析CapabilitiesList。

目录

1. 配置空间概念和作用

2. 通过配置空间发现设备

3. Linux读取PCI配置空间接口

4. 内核中具体读取配置空间实例

5. Virtion设备自定义空间

6. Linux读取Capabilities List代码解析


1. 配置空间概念和作用

详细的定义可以参考PCI Spec的第六章《Configuration Space》中的描述,这里仅摘抄关键点

  • 所有的PCI设备必须实现配置空间,配置空间的本质是一堆寄存器
  • 配置空间可以用来发现设备
  • pci local bus spec规定的配置空间最大256字节,前64字节是spec中定义好的,称预定义空间,其中前16字节对所有类型的pci设备都相同(是指格式,而不其中具体的值),之后的空间格式因类型而不同,对前16字节空间,我称它为通用配置空间。

 上面是摘自PCI3.0规范的配置空间,一共64字节,即预定义空间,其中前16字节对应通用配置空间。

预定义空间解析

vendor id:厂商ID,用来标识pci设备出自哪个厂商,这里是0x1af4,来自Red Hat。
device id:厂商下的产品ID,传统virtio-blk设备,这里是0x1001
revision id:厂商决定是否使用,设备版本ID,这里未使用
header type:pci设备类型,0x00(普通设备),0x01(pci bridge),0x02(CardBus bridge)。virtio是普通设备,这里是0x00

status: 描述pci设备状态的寄存器

 其中有一位是Capabilities List,它是pci规范定义的附加空间标志位,Capabilities List的意义是允许在pci设备配置空间之后加上额外的寄存器,这些寄存器由Capability List组织起来,用来实现特定的功能,附加空间在64字节配置空间之后,最大不能超过256字节。以virtio-blk为例,它标记了这个位,因此在virtio-blk设备配置空间之后,还有一段空间用来实现virtio-blk的一些特有功能。1表示capabilities pointer字段(0x34)存放了附加寄存器组的起始地址。这里的地址表示附加空间在pci设备空间内的偏移。具体Capability List怎么理解本文后面分析。

2. 通过配置空间发现设备

发下设备需要确定两个事情:PCI设备地址,以及确定地址之后具体怎么通过该地址访问。

PCI设备地址 : 参考PCI规范3.2.2.3.2章节

设备地址可以通过Bus号,Device号,功能号和寄存器号唯一确定:

 

 Linux内核中确定该地址可以通过宏:

/*
 * Functions for accessing PCI base (first 256 bytes) and extended
 * (4096 bytes per PCI function) configuration space with type 1
 * accesses.
 */

#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
	(0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
	| (devfn << 8) | (reg & 0xFC))

访问配置空间

  • 配置空间寄存器偏移

PCI_CONF1_ADDRES宏确定了配置空间的基地址(Base Address),还要结合配置空间偏移具体访问具体的功能,比如访问配置空间的Command对应的offset:04h,Capabilities pointer偏移:0x34h。

  • 端口访问

配置空间地址无法直接访问,需要通过特定的端口来访问:

CONFIG_ADDRESS(CF8h) : 将需要访问的配置空间地址设置到该端口

CONFIG_DATA(CFCh):从该端口读取配置空间的值。

3. Linux读取PCI配置空间接口
//参数dev : pci 设备
//where : 配置空间寄存器对应的偏移offset
int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val);
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val);
int pci_read_config_dword(const struct pci_dev *dev, int where, u32 *val);
int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val);
int pci_write_config_word(const struct pci_dev *dev, int where, u16 val
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值