On PCI, a 256 bytes configuration address space, made of 64x32 bits registers, is used to configure PCI devices.
The PCI configuration space contains the function's vendor and device IDs, but also the memory mapped regions description (BAR) the function will be able to use.
This is the legacy method. Both PCI and PCI-e must support it.
On x86, the PCI configuration space is accessible through 2 IO ports: 0xcf8
and 0xcfc
.
The former is called the CONFIG_ADDRESS
register. A write to it allows for addressing one of the 64 registers from the configuration space, and it should have the following format:
0x80000000 | bus << 16 | device << 11 | function << 8 | register index
The latter is the CONFIG_DATA
register and is where the content of the addressed register is either read or written.
That method is defined by the PCI-x and PCI-e specifications and is called ECAM (Extended Configuration Access Mechanism).
Here the PCI configuration space is mapped in physical memory, and the address for each configuration space is specified by the ACPI MCFG
table [6].
Base Address Registers (BAR) describe the base address for a memory mapped device address space.
It allows the driver/CPU to access the device configuration and address space directly from the memory address space.
The PCI hole is the amount of the 32-bits memory address space that is taken by memory mapped PCI functions (described by BARs). That amount potentially make part of the physical memory unavailable as it's hidden to the CPU.
[1] https://wiki.osdev.org/PCI
[2] https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231
[3] https://en.wikipedia.org/wiki/PCI_configuration_space
[4] https://en.wikipedia.org/wiki/PCI_hole
[5] https://wiki.osdev.org/PCI_Express
[6] https://wiki.osdev.org/PCI_Express#Enhanced_Configuration_Mechanism