The 64-byte PCI-compatible header used by every PCIe endpoint — Vendor and Device ID, Command and Status registers, Class Code, the six Base Address Registers, Subsystem IDs, Expansion ROM, Capabilities Pointer, and the Interrupt registers. How BARs are sized, what each bit in Command/Status does, and the full 4 KB config space layout.
Configuration space is a standardised address space separate from memory and IO space. Every PCIe function — whether an endpoint, a switch port, or a root port — has its own configuration space. Software uses configuration space to discover devices, learn their capabilities, assign memory and IO addresses, and control device behaviour.
Configuration space was inherited from PCI and is preserved in PCIe for complete software backward compatibility. A PCIe device driver written for Windows in 2005 accesses configuration registers the same way as one written in 2025. The register layout, offsets, and access rules are identical.
Legacy PCI mechanism (CF8/CFC): writes to the Configuration Address Port at IO address 0CF8h (encoding bus/device/function/register) then reads/writes the Configuration Data Port at 0CFCh. Limited to the first 256 bytes (64 DWs) per function. All x86 systems support this.
Enhanced Configuration Access Mechanism (ECAM): the entire 4 KB per function is mapped into memory address space as a flat MMIO region. The base address of this region is advertised in ACPI (MCFG table). Address = ECAM_BASE + (Bus × 1MB) + (Device × 32 KB) + (Function × 4 KB) + Register_Offset. This is the only way to access Extended Configuration Space (offset 100h and above).
The Header Type register at offset 0Eh bits [6:0] determines which header layout a function uses. Only two layouts are defined:
| Header Type | Used by | BARs | What replaces BARs 2–5 in Type 1 |
|---|---|---|---|
| Type 0 (value 0) | Endpoints, Root Complex internal functions, multi-function device functions | Six 32-bit BARs (BAR0–BAR5) at offsets 10h–24h | — (Type 0 has all six) |
| Type 1 (value 1) | Bridges — every switch port, root port, PCIe-to-PCI bridge | Two 32-bit BARs (BAR0–BAR1) at offsets 10h–14h | Bus Number registers + Memory/IO Base/Limit windows (offsets 18h–2Ch) |
Bit 7 of the Header Type register is the Multi-Function Device bit. If set to 1, the device implements more than one function and software should probe functions 0–7. If bit 7 = 0, only function 0 exists. Software uses this to avoid unnecessary configuration reads on a single-function device.
This post covers Type 0 headers — the layout used by every PCIe endpoint including NVMe drives, GPUs, NICs, and USB controllers. Type 1 headers are covered in PCIe-19.
These two 16-bit read-only registers at offset 00h are the first thing software reads during enumeration. Together they uniquely identify the hardware.
| Register | Offset | Width | Access | Purpose and notes |
|---|---|---|---|---|
| Vendor ID | 00h bits [15:0] | 16 bits | RO | Assigned by the PCI-SIG to device manufacturers. Must be unique per company. Intel = 8086h, NVIDIA = 10DEh, AMD = 1022h, Broadcom = 14E4h. Value FFFFh means no device present — the bus returns 0xFFFF when nothing is attached. Software checks for FFFFh to detect empty slots during enumeration. |
| Device ID | 00h bits [31:16] | 16 bits | RO | Assigned by the vendor to identify a specific product. Combined with Vendor ID forms a globally unique device identifier. The same chip used in multiple products may have the same Device ID; variants are distinguished by Subsystem IDs. |
The Command register at offset 04h bits [15:0] is the primary control register for the device. Most bits default to 0 after reset — the device is largely inactive until software configures it. Writing a 1 to a bit enables the corresponding capability.
| Bit | Name | Reset | Meaning when set to 1 |
|---|---|---|---|
| 0 | I/O Space Enable | 0 | Device responds to IO address cycles targeting its IO BARs. Legacy only — PCIe discourages IO space use. |
| 1 | Memory Space Enable | 0 | Device responds to memory address cycles targeting its memory BARs. Must be set before any driver MMIO access to BAR space. Set to 0 during BAR programming to prevent incorrect claims. |
| 2 | Bus Master Enable | 0 | Device is allowed to initiate TLPs as a Requester (DMA reads and writes). Without this, the device is a target only — it responds to requests but cannot generate them. IOMMU must be configured before this is set. |
| 3 | Special Cycle Enable | 0 | Legacy PCI feature — device responds to PCI Special Cycle commands. Not used in native PCIe. |
| 4 | Memory Write and Invalidate Enable | 0 | Legacy PCI feature — enables MWI transactions. Not used in native PCIe. |
| 5 | VGA Palette Snoop | 0 | Legacy VGA feature. Ignore for non-VGA PCIe devices. |
| 6 | Parity Error Response Enable | 0 | Device must take action when a parity error is detected. If 0, device ignores parity errors (except setting Detected Parity Error in Status). |
| 7 | Reserved (IDSEL Stepping) | 0 | Legacy PCI only. Must be 0 in PCIe. |
| 8 | SERR# Enable | 0 | Device sends ERR_FATAL or ERR_NONFATAL messages upstream when a system error occurs. Must be set for AER (Advanced Error Reporting) to be useful. |
| 9 | Fast Back-to-Back Enable | 0 | Legacy PCI only. Has no effect in PCIe — always reads as 0 on PCIe-native devices. |
| 10 | Interrupt Disable | 0 | When set, disables the device from asserting INTx legacy interrupt pin signals. Should be set by the driver when switching to MSI or MSI-X interrupt mode. |
| [15:11] | Reserved | 0 | Must return 0 when read. Writes ignored. |
The Status register at offset 04h bits [31:16] reports conditions that have occurred. Most bits are sticky — they latch when the condition occurs and stay set until software explicitly clears them by writing a 1 to the bit (write-1-to-clear). Writing a 0 has no effect.
| Bit | Name | Access | Meaning |
|---|---|---|---|
| [18:16] | Reserved | RO | Return 0. |
| 19 | Interrupt Status | RO | When 1: device is asserting a legacy INTx interrupt. Read-only snapshot — cannot be cleared by writing. Only valid when Interrupt Disable (Command bit 10) is 0. |
| 20 | Capabilities List | RO | When 1: device implements a Capabilities linked list starting at the Capabilities Pointer (offset 34h). All PCIe devices must have this set to 1 because a PCIe Capability structure is mandatory. |
| 21 | 66 MHz Capable | RO | Legacy PCI only. Always 0 on PCIe-native devices. |
| 22 | Reserved | RO | Returns 0. |
| 23 | Fast Back-to-Back Capable | RO | Legacy PCI only. Always 0 on PCIe-native devices. |
| 24 | Master Data Parity Error | RW1C | Device acting as Bus Master detected a parity error. Set when a poisoned TLP is received and Parity Error Response Enable (Command bit 6) is set. Latches — cleared by writing 1. |
| [26:25] | DEVSEL Timing | RO | Legacy PCI only. Returns 01b (Medium timing) for PCIe-native devices for compatibility. |
| 27 | Signaled Target Abort | RW1C | Device sent a Completion with CA (Completer Abort) status — it aborted the transaction. Latches — cleared by writing 1. |
| 28 | Received Target Abort | RW1C | Device received a Completion with CA status while it was a Requester. Latches — cleared by writing 1. |
| 29 | Received Master Abort | RW1C | Device received a Completion with UR (Unsupported Request) status while it was a Requester. Latches — cleared by writing 1. |
| 30 | Signaled System Error | RW1C | Device sent an ERR_FATAL message. Only set if SERR# Enable (Command bit 8) was set. Latches — cleared by writing 1. |
| 31 | Detected Parity Error | RW1C | Device received a TLP with the EP (Error Poison) bit set, regardless of the Parity Error Response Enable bit. Always latches. Cleared by writing 1. |
| Register | Offset | Width | Purpose |
|---|---|---|---|
| Revision ID | 08h [7:0] | 8 bits RO | Vendor-specific hardware revision. Combined with Device ID, lets software distinguish between chip steppings. Value 00h is valid (first silicon). No standard meaning — purely vendor-defined. |
| Class Code | 08h [31:8] | 24 bits RO | Three sub-fields: Base Class [31:24] (broad category — storage, display, network, bridge), Sub-Class [23:16] (more specific type), Programming Interface [15:8] (optional detail, 00h if not applicable). Lets the OS load a generic driver when no specific driver is found. Examples below. |
| Base Class | Sub-Class | Prog IF | Device type |
|---|---|---|---|
| 01h (Storage) | 08h (NVM) | 02h | NVMe controller — OS loads NVMe driver automatically |
| 03h (Display) | 00h (VGA) | 00h | VGA controller — OS loads generic display driver |
| 02h (Network) | 00h (Ethernet) | 00h | Ethernet controller |
| 04h (Multimedia) | 03h (HD Audio) | 00h | High-Definition Audio controller |
| 0Ch (Serial Bus) | 03h (USB) | 30h | USB XHCI (USB 3.x) controller |
| 06h (Bridge) | 04h (P2P) | 00h | PCI-to-PCI bridge (Type 1 header devices) |
| FFh (Unclassified) | — | — | Device does not fit any standard class |
| Register | Offset | Access | Purpose |
|---|---|---|---|
| Cache Line Size | 0Ch [7:0] | RW | Legacy PCI concept. Specifies the system cache line size in units of 32-bit DWs. Example: 10h (16 DWs = 64 bytes) for typical x86 systems. Used by legacy PCI MWI (Memory Write and Invalidate) transactions. Has no operational effect in native PCIe — ignored by most PCIe devices, but BIOS typically programs it anyway for PCI backward compatibility. |
| Latency Timer | 0Ch [15:8] | RW | Legacy PCI bus master latency timer. Specifies the minimum number of PCI clock cycles a bus master can hold the bus. Not relevant in PCIe (point-to-point, no shared bus). Returns 0 or is ignored on native PCIe devices. |
| Header Type | 0Ch [22:16] | RO | Bits [6:0] = 0 for Type 0 (endpoint), 1 for Type 1 (bridge). Bit 7 = Multi-Function Device bit. If bit 7 = 1, probe all 8 functions (0–7). If bit 7 = 0, only function 0 exists. |
| BIST | 0Ch [31:24] | RW / RO | Built-In Self Test. Bit 7: BIST Capable (RO) — device supports self-test. Bit 6: Start BIST (RW) — software writes 1 to trigger the test. Device clears this bit when done. Bits [3:0]: Completion Code — 0 = test passed, non-zero = specific failure code. Bits [5:4] reserved. If bit 7 = 0, BIST not supported and writing bit 6 has no effect. |
The six BARs (offsets 10h–24h) are the mechanism by which a device requests memory and IO address space from the system. The device designer hard-codes the lower bits to specify the type and size of space needed. Software reads these bits to discover the request, then programs the upper bits with the base address of the allocated region.
A Type 0 header has six 32-bit BARs. A 64-bit memory BAR uses two consecutive 32-bit slots (e.g. BAR0+BAR1 form one 64-bit BAR). Unimplemented BARs are hardwired to all zeros and read back as 0 — software recognises this as “not implemented” and skips allocation.
The device designer hardcodes the lower N bits of each BAR to specific values that encode the size of the requested region. Software cannot know the size just by reading the uninitialized BAR. Instead, it uses a three-step procedure:
config_write(offset, 0xFFFFFFFF). The lower hardcoded bits are unaffected. Only the writable upper bits flip to 1.After programming all BARs, software re-enables Memory Space Enable and/or I/O Space Enable in the Command register. From this point, any TLP with an address that falls within a programmed BAR range is claimed and processed by the device.
The lower bits of each BAR are hardcoded by the device designer and reveal the type of address space requested:
| BAR type | Bit 0 | Bits [2:1] | Bit 3 | BAR slots used | Typical use |
|---|---|---|---|---|---|
| 32-bit non-prefetchable memory | 0 | 00 | 0 | 1 (single 32-bit) | Control/status registers |
| 32-bit prefetchable memory | 0 | 00 | 1 | 1 (single 32-bit) | Read-only data regions (rare in 32-bit) |
| 64-bit non-prefetchable memory | 0 | 10 | 0 | 2 (pair of 32-bit) | Large control register spaces above 4 GB |
| 64-bit prefetchable memory | 0 | 10 | 1 | 2 (pair of 32-bit) | GPU framebuffer, NVMe queues, large DMA windows |
| IO space | 1 | n/a | n/a | 1 (single 32-bit) | Legacy COM/LPT port compatibility only |
| Not implemented | — | — | — | Reads all 0s | Unused BAR slots; software skips allocation |
Offset 28h (DW 10). This register is a legacy pointer to the CardBus Card Information Structure — a format used by CardBus (the 32-bit successor to PC Card) to describe the card to the host. In a PCIe device this field has no function and must return 0. Software and drivers ignore it. It exists only because the PCIe Type 0 header is layout-compatible with the original PCI Type 0 header which included this field.
Offset 2Ch. These two 16-bit read-only registers are assigned by the board/card manufacturer, not by the chip manufacturer. They allow identification of the specific product SKU or reference design in cases where many products share the same chip (same Vendor ID + Device ID) but differ in configuration, memory size, cooling, or firmware.
| Example | Vendor ID | Device ID | Subsystem Vendor ID | Subsystem Device ID |
|---|---|---|---|---|
| NVIDIA GA102 chip (RTX 3080) | 10DEh | 2206h | 10DEh (NVIDIA FE) | 1459h |
| Same chip, ASUS variant | 10DEh | 2206h | 1043h (ASUS) | 8777h |
| Same chip, EVGA variant | 10DEh | 2206h | 3842h (EVGA) | 2477h |
Operating systems and drivers use Subsystem IDs to load card-specific firmware, VBIOS, fan profiles, or OC settings. The OS device driver database (INF files on Windows, modalias on Linux) can match on Vendor+Device+Subsystem combinations to load the exact right configuration.
Offset 30h. The Expansion ROM BAR holds the base address of the device’s option ROM — a block of firmware code that runs at POST time to initialise the hardware before the OS loads. Network boot (PXE), GPU BIOS, and RAID controller initialisation are classic uses.
The register format is similar to a memory BAR but with bit 0 as an Enable bit rather than a type indicator. Bits [10:1] are hardcoded to 0 (making the ROM addressable at minimum on 2 KB boundaries; in practice typically 4 KB or larger). The upper bits hold the base address once software programs it.
If a device has no ROM, this register reads back as all zeros regardless of what is written to it. Software checks this by writing all-1s and reading back — if bits [31:11] are all 0, no Expansion ROM is present.
Offset 34h bits [7:0]. This byte is the offset (within configuration space) of the first entry in the PCI Capabilities linked list. Capabilities are optional feature structures that extend the base header. They live in the 192-byte device-specific region (offsets 40h–FFh) of the PCI-compatible space.
| Capability ID | Structure name | Required in PCIe? |
|---|---|---|
| 01h | Power Management Capability | Mandatory for all PCIe devices |
| 05h | MSI (Message Signalled Interrupts) | Mandatory for endpoints |
| 10h | PCIe Capability (Link Control, Link Status, Device Control, Device Status) | Mandatory for all PCIe devices |
| 11h | MSI-X (Extended MSI with table in BAR space) | Optional but common in high-performance devices |
| 03h | Vital Product Data (VPD) | Optional |
| 09h | Vendor-Specific Capability | Optional |
| Register | Offset | Access | Purpose |
|---|---|---|---|
| Interrupt Line | 3Ch [7:0] | RW | System interrupt vector number (0–254) as assigned by the OS/BIOS. Maps the device’s INTx legacy interrupt to a specific IRQ line in the interrupt controller. Value 255 (FFh) means “not connected.” This field has no operational effect on hardware — it is purely a software-managed annotation field. Drivers read this to know which IRQ to attach a handler to for legacy INTx interrupts. |
| Interrupt Pin | 3Ch [15:8] | RO | Indicates which legacy PCI interrupt pin this function uses: 0 = no interrupt, 1 = INTA#, 2 = INTB#, 3 = INTC#, 4 = INTD#. This is hardcoded by the device designer. Most single-function PCIe endpoint devices use INTA# (value 1). When MSI or MSI-X is used, this field is ignored at runtime but remains as a fixed declaration of legacy intent. |
| Min_Gnt | 3Ch [23:16] | RO | Legacy PCI only. Minimum grant time the device needs when it has the bus. Has no effect in PCIe (no shared bus). Typically 0 in native PCIe devices. |
| Max_Lat | 3Ch [31:24] | RO | Legacy PCI only. Maximum latency tolerance before device suffers data loss. Has no effect in PCIe. Typically 0 in native PCIe devices. |
PCIe extends the original 256-byte PCI configuration space to 4 KB per function. The region from offset 100h to FFFh (3840 bytes = 960 DWs) is the PCIe Extended Configuration Space, accessible only via ECAM (MMCFG). Legacy CF8/CFC IO-indirect access cannot reach this region.
Extended capabilities use a different linked list format than PCI capabilities. Each PCIe Extended Capability structure starts with a 32-bit header:
| Extended Cap ID | Structure | Key function |
|---|---|---|
| 0001h | Advanced Error Reporting (AER) | Detailed error logging, correctable/uncorrectable error status, header log, TLP prefix log |
| 0002h | Virtual Channel (VC) | Configures VC TC mapping, VC arbitration |
| 0003h | Device Serial Number (DSN) | 64-bit globally unique serial number |
| 0004h | Power Budgeting | Slot power allocation for hot-plug controllers |
| 000Bh | Vendor-Specific Extended Capability (VSEC) | Vendor-defined extended registers |
| 000Dh | Access Control Services (ACS) | Controls peer-to-peer DMA, AT=10 validation |
| 000Fh | ATS (Address Translation Services) | IOMMU translation caching negotiation |
| 0018h | LTR (Latency Tolerance Reporting) | Device advertises its memory and snoop latency tolerance |
| 0019h | L1 PM Substates | ASPM L1.1 / L1.2 sub-states for deeper power savings |
| 0026h | Physical Layer 16.0 GT/s (Gen 4) | Equalization status, lane margining, retimer support |
| 002Ah | Physical Layer 32.0 GT/s (Gen 5) | Gen 5 equalization and signal integrity |
| 002Bh | Alternate Protocol | CXL and other PCIe-based protocols negotiate here |
The Type 0 header layout, all register definitions, all bit positions, the Capabilities Pointer, the Extended Configuration Space structure — everything described in this post — is completely unchanged in Gen 6. Configuration space is a software-visible abstraction above the Physical Layer. Gen 6 changes only the Physical Layer.
What Gen 6 adds to configuration space is a few new Extended Capability structures:
| Register | Offset | Access | Key rule or value |
|---|---|---|---|
| Vendor ID | 00h [15:0] | RO | PCI-SIG assigned. FFFFh = no device. First thing software reads during enumeration. |
| Device ID | 00h [31:16] | RO | Vendor-assigned product identifier. Unique within a vendor. |
| Command | 04h [15:0] | RW | Bit 0: IO Enable · Bit 1: Memory Enable · Bit 2: Bus Master Enable · Bit 8: SERR Enable · Bit 10: INTx Disable. All default 0 after reset. |
| Status | 04h [31:16] | mixed | Bit 20: Capabilities List present (must be 1 for PCIe). Bits [31:24]: error flags — RW1C (write 1 to clear). |
| Revision ID | 08h [7:0] | RO | Vendor-specific chip revision. 00h = first silicon. No standard meaning. |
| Class Code | 08h [31:8] | RO | Base Class [31:24] · Sub-Class [23:16] · Prog IF [15:8]. Used by OS for driver matching. |
| Cache Line Size | 0Ch [7:0] | RW | System cache line in DWs. BIOS programs to 10h (64 bytes). No effect on native PCIe operations. |
| Header Type | 0Ch [22:16] | RO | Bits [6:0] = 0 for Type 0. Bit 7 = Multi-Function Device (probe functions 0–7 if set). |
| BIST | 0Ch [31:24] | mixed | Bit 7 RO: BIST capable. Bit 6 RW: Start BIST. Bits [3:0] RO: result (0 = pass). |
| BAR0–BAR5 | 10h–24h | mixed | Six 32-bit slots. 64-bit BAR uses two slots. Bit 0=0 → memory, bit 0=1 → IO. Bits [2:1]: 00=32-bit, 10=64-bit. Bit 3: prefetchable. Write all-1s then read to size. |
| CardBus CIS | 28h | RO | Always 0 in PCIe. Legacy CardBus field, not used. |
| Subsystem Vendor ID | 2Ch [15:0] | RO | Card/board manufacturer’s PCI-SIG ID. Distinguishes OEM variants of same chip. |
| Subsystem Device ID | 2Ch [31:16] | RO | Card/board manufacturer’s product ID. Used by driver database for SKU-specific firmware. |
| Expansion ROM | 30h | mixed | Bit 0: Enable. Bits [10:1]: hardwired 0. Bits [31:11]: base address (RW). Size via write-all-1s procedure. |
| Capabilities Pointer | 34h [7:0] | RO | Offset to first PCI Capability structure. Must be DWORD aligned. Mask bits [1:0] before use. 00h if no capabilities (but PCIe requires capabilities, so never 00h). |
| Interrupt Line | 3Ch [7:0] | RW | OS/BIOS writes the system IRQ number here. Software annotation only — no hardware effect. |
| Interrupt Pin | 3Ch [15:8] | RO | 1=INTA# · 2=INTB# · 3=INTC# · 4=INTD# · 0=none. Hardcoded by device designer. |
| Extended Config Space | 100h–FFFh | varies | Only via ECAM (MMCFG). PCIe Extended Capabilities linked list with 32-bit headers (16-bit Cap ID + version + next offset). AER, ATS, VC, DSN, LTR, L1SS, Gen 4/5/6 PHY caps. |