天天看点

ACPI.sys,从Windows到Bios的桥梁(1.5):PCIe device 配置空间

    在继续<ACPI.sys,从Windows到Bios的桥梁>系列之前,先暂停补充一下PCIe device MMIO相关的知识。PCIe MMIO比较复杂,推荐以这两篇文章入门: 

<​​System Address Map Initialization in x86/x64 Architecture Part 1: PCI-Based Systems​​​> &<​​System Address Map Initialization in x86/x64 Architecture Part 2: PCI Express-Based Systems​​>。本文基于这两篇文章,总结如何在Intel平台上读取PCIe device配置空间。

0.收集主板信息:

不同平台,PCH上提供相同功能的PCIe device的Bus/Device/Function/Register Number可能会发生变化,为了赶上这种变化,需要先确定CPU和平台型号,如我的笔记本是WhiskyLake平台(见笑了):

ACPI.sys,从Windows到Bios的桥梁(1.5):PCIe device 配置空间

确定型号后,根据PCH EDS spec得到 Bus/Device/Function/Register Number(当然完全可以用RW放飞自我,不过PCH上有部分PCIe设备对RW等工具不可见)。

1.获取PCIEX_BASE_ADDRESS

根据CPU EDS Vol2,PCIEX_BASE_ADDRESS的值通过下列方式获得:

ACPI.sys,从Windows到Bios的桥梁(1.5):PCIe device 配置空间
ACPI.sys,从Windows到Bios的桥梁(1.5):PCIe device 配置空间

Bus:0 Device:0 Function:0 Register:0x60 bit[28:36]存放PCIEXBAR的地址,当然,这个可以用RW获取。如下图,对于WHL平台,PCIEXBAR地址为E0000000:

ACPI.sys,从Windows到Bios的桥梁(1.5):PCIe device 配置空间

2.访问PCIe设备配置空间: 

#define SB_PCIE_CFG_ADDRESS(bus, dev, func, reg) \

            ((UINTN)(PCIEX_BASE_ADDRESS + ((UINT8)(bus) << 20) + \

            ((UINT8)(dev) << 15) + ((UINT8)(func) << 12) + (reg)))

 

#define PCIEX_BASE_ADDRESS  0xe0000000      

根据这个宏定义可以访问多数PCIe设备(除了P2SB/PMC controller这种隐藏设备)的配置空间,比如VGA Controller:B:0 D:2 F:0,经过计算其配置空间起始地址:E0010000,对比从RW PCIe device获得的配置空间,两者内容相同:

ACPI.sys,从Windows到Bios的桥梁(1.5):PCIe device 配置空间

3.获得PCIe BAR1\BAR2...:

PCIe超过256B以外的配置空间以Mem方式访问,该配置空间起始地址存放于BAR1\BAR2,其Register offset分别为0x10\0x14,我们看下XHCI 配置空间为E00A0000/XHCI Bar Address为0x6001100000:

#define PCI_BUS_NUMBER_PCH_XHCI             0
#define PCI_DEVICE_NUMBER_PCH_XHCI          20
#define PCI_FUNCTION_NUMBER_PCH_XHCI        0
    
    XhciPciMmBase   = MmPciBase (
                      DEFAULT_PCI_BUS_NUMBER_PCH,
                      PCI_DEVICE_NUMBER_PCH_XHCI,
                      PCI_FUNCTION_NUMBER_PCH_XHCI
                      );
//获得XHci BAR Address
    UsbBase = MmioRead32 (XhciPciMmBase + PCI_BASE_ADDRESSREG_OFFSET + 4);
                UsbBase = (UsbBase << 32);
                UsbBase |= MmioRead32 (XhciPciMmBase + PCI_BASE_ADDRESSREG_OFFSET);
                UsbBase &= 0xFFFFFFFFFFFF0000;      
ACPI.sys,从Windows到Bios的桥梁(1.5):PCIe device 配置空间

 从RW Memory获得的XHCI Bar Address各Offset的具体内容需要与PCH EDS对比,当然这不是本文内容,不再讨论。

ACPI.sys,从Windows到Bios的桥梁(1.5):PCIe device 配置空间

 参考: