PCI devices expose 256 bytes (or 4 KB extended) of configuration registers per function. Access via I/O ports 0xCF8 (address) and 0xCFC (data) with enable bit set. For example, to read vendor/device ID of bus 0 dev 0 fn 0, write 0x80000000 to 0xCF8 and read 0xCFC.
Config cycle
nasm
Loading…
Bus/dev/fn/offset packed into the address port
BAR registers: Tell you MMIO and I/O ranges to map
Command register: Enable I/O and memory space decode
Enumerate functions 0-7 per device; read header type for multifunction bit
BAR decoding
After reading vendor/device IDs, read command register bit 1 and 2 to see if I/O and memory space are enabled. BAR0 low bits encode whether the region is I/O or memory and whether it is 32- or 64-bit. QEMU exposes host bridges on bus 0; plug-in devices appear on higher slot numbers. Config reads return 0xFFFFFFFF for nonexistent functions; mask with size probe writes to discover BAR lengths.
Why for this exercise
You will scan PCI buses and print vendor/device IDs using config port I/O. This exercise requires building the 0xCF8 address dword and interpreting the first config dword as vendor plus device identifiers.
Build and decode PCI CONFIG_ADDRESS dwords in C from stdin requests (type 1 access via ports 0xCF8/0xCFC).
Input format:
Line 1: N, the number of commands.
Then one command per line:
"ADDR <bus> <dev> <fn> <off>": read offset at bus/dev/fn
"DECODE <hex>": a 32-bit dword written to port 0xCF8
"IDS <hex>": a 32-bit config dword read back from port 0xCFC at offset 0x00
Requirements:
ADDR: cfg-addr = 0x80000000 | (bus & 0xFF) << 16 | (dev & 0x1F) << 11 | (fn & 0x07) << 8 | (off & 0xFC). The offset is dword-aligned, so its low two bits are cleared. Print "ADDR <bus> <dev> <fn> <off> -> cfg-addr=0x<xxxxxxxx>".
DECODE: extract en = bit 31, bus = bits 23:16, dev = bits 15:11, fn = bits 10:8, off = bits 7:2 << 2. Print "DECODE <hex> -> en=<e> bus=<b> dev=<d> fn=<f> off=0x<hh>".
IDS: vendor = low 16 bits, device = bits 31:16. Print "IDS <hex> -> vendor=0x<hhhh> device=0x<hhhh> <present|absent>", where a vendor of 0xFFFF means no device responds (config reads return 0xFFFFFFFF for absent functions).
Echoes: the ADDR offset, and the DECODE and IDS values, are printed back as lowercase hex without 0x (input 0x08 prints 8, 0x8000F83C prints 8000f83c).