2026. 6. 17. 22:23ㆍ기초지식
PCIe Enumeration 개요
PCIe Enumeration은 시스템 부팅 시 BIOS/UEFI 또는 OS가 PCIe 토폴로지를 탐색하고, 각 디바이스에 Bus 번호를 부여하며, 메모리/IO 리소스를 할당하는 과정이다. PCI Configuration Space를 통해 이루어진다.
- Depth-First Search(DFS) 방식으로 토폴로지 탐색
- Bus 0부터 시작해서 Bridge 발견 시 새로운 Bus 번호 할당
- BAR(Base Address Register)를 통해 디바이스 메모리 공간 매핑
- Capability Pointer를 통해 지원 기능 탐색
PCI Configuration Space 구조
PCIe는 전통적인 PCI의 256바이트 Configuration Space를 4096바이트(4KB)로 확장한다. 앞 256바이트는 PCI 호환 영역, 나머지 3840바이트는 PCIe Extended Configuration Space이다.
PCI-Compatible Configuration Space (0x000 - 0x0FF):
Offset 0x00: Vendor ID (16b) / Device ID (16b)
Offset 0x04: Command (16b) / Status (16b)
Offset 0x08: Revision ID (8b) / Class Code (24b)
Offset 0x0C: Cache Line Size / Latency Timer / Header Type / BIST
Offset 0x10 ~ 0x24: BAR 0~5 (Type 0) / BAR 0~1 + Bridge Registers (Type 1)
Offset 0x28: Cardbus CIS Pointer (Type 0) / Secondary Latency Timer (Type 1)
Offset 0x2C: Subsystem Vendor ID / Subsystem ID
Offset 0x30: Expansion ROM Base Address
Offset 0x34: Capabilities Pointer
Offset 0x3C: Interrupt Line / Interrupt Pin / Min_Gnt / Max_Lat
PCIe Extended Configuration Space (0x100 - 0xFFF):
0x100~: Extended Capabilities (AER, SR-IOV, LTR, etc.)
Header Type - Type 0 vs Type 1
Header Type 필드(offset 0x0E)로 디바이스 종류를 구분한다.
Type 0 Header - Endpoint Device
- Header Type[6:0] = 0x00
- BAR 0~5 최대 6개 사용 가능 (offset 0x10 ~ 0x24)
- Subsystem Vendor ID / Subsystem ID 존재
- 일반 디바이스(NIC, GPU, SSD 등)에 사용
Type 1 Header - Bridge Device
- Header Type[6:0] = 0x01
- BAR 0~1만 사용 (Bridge 자체 리소스)
- Primary Bus Number / Secondary Bus Number / Subordinate Bus Number 존재
- Memory Base / Memory Limit / Prefetchable Memory Base / Limit 존재
- PCIe Switch의 Upstream/Downstream Port, Root Port에 사용
Multi-Function Device
- Header Type[7] = 1이면 Multi-Function Device
- 하나의 물리 디바이스가 Function 0~7까지 최대 8개 Function 지원
- Function 0은 반드시 존재해야 함 (Enumeration 진입점)
- 각 Function은 독립적인 Configuration Space를 가짐
BAR (Base Address Register)
BAR는 디바이스가 필요로 하는 메모리 또는 IO 주소 공간의 크기와 타입을 선언하고, OS가 실제 주소를 할당해주는 매커니즘이다.
BAR 타입 구분
BAR[0]: Memory Space Indicator
0 = Memory Space BAR
1 = I/O Space BAR
Memory Space BAR[2:1]: Type
00 = 32-bit address space
10 = 64-bit address space (BAR 두 개를 pair로 사용)
01 = reserved
Memory Space BAR[3]: Prefetchable
0 = Non-Prefetchable (Side Effect 있을 수 있음)
1 = Prefetchable (캐싱, Burst Read 허용)
BAR 크기 탐색 방법
[BAR 크기 확인 절차]
1. 원래 BAR 값 저장 (saved_value = BAR)
2. BAR에 0xFFFFFFFF 쓰기
3. BAR 읽기 (size_mask = BAR)
4. 원래 BAR 값 복원
5. size_mask에서 타입 비트 마스킹 후 NOT 연산 + 1 = 크기
예: size_mask = 0xFFFF0000 (하위 16비트가 0)
-> 크기 = ~(0xFFFF0000 & 0xFFFFFFF0) + 1
= 0x0000FFFF + 1
= 0x10000 = 64KB
64-bit BAR의 경우:
- BAR[n]에 하위 32비트 기록
- BAR[n+1]에 상위 32비트 기록
- 두 BAR를 합쳐 64-bit 주소 공간 표현
BAR 주소 할당 규칙
- BAR 크기에 맞게 Alignment 필수 - 64KB BAR는 64KB 경계에 할당
- Prefetchable BAR는 가능한 Prefetchable Window에 배치
- 64-bit BAR는 MMIO High 영역(4GB 이상)에 배치 가능
- OS는 Resource Manager가 conflict 없이 할당 관리
Bus 번호 할당 - Depth-First Search
Enumeration은 DFS 방식으로 진행된다. Root Bus = 0부터 시작하여 Bridge를 발견할 때마다 새로운 Bus 번호를 부여한다.
[Enumeration 절차 예시]
초기 상태:
Bus 0: Root Complex (Host Bridge)
Step 1: Bus 0 스캔
- Device 0, Function 0: Root Port (Type 1 Header 발견)
-> Secondary Bus = 1, Subordinate Bus = 임시 최대값(0xFF) 할당
Step 2: Bus 1 스캔 (DFS로 진입)
- Device 0, Function 0: PCIe Switch Upstream Port (Type 1 Header 발견)
-> Secondary Bus = 2, Subordinate Bus = 0xFF
Step 3: Bus 2 스캔
- Device 2, Function 0: Switch Downstream Port A (Type 1 Header)
-> Secondary Bus = 3, Subordinate Bus = 0xFF
- Device 3, Function 0: Switch Downstream Port B (Type 1 Header)
-> Secondary Bus = (4, later), Subordinate Bus = 0xFF
Step 4: Bus 3 스캔
- Device 0: NVMe SSD (Type 0 Header = Endpoint)
-> Bus 3의 마지막 디바이스 확정
-> Downstream Port A의 Subordinate Bus = 3으로 갱신
Step 5: Bus 4 할당 후 스캔
- Device 0: GPU (Type 0 Header = Endpoint)
-> Downstream Port B의 Subordinate Bus = 4로 갱신
최종 결과:
Root Port: Primary=0, Secondary=1, Subordinate=4
SW Upstream: Primary=1, Secondary=2, Subordinate=4
SW Downstream A: Primary=2, Secondary=3, Subordinate=3
SW Downstream B: Primary=2, Secondary=4, Subordinate=4
Subordinate Bus Number의 역할
- Bridge가 Routing 결정 시 사용 - Secondary <= TLP 목적지 Bus <= Subordinate이면 해당 Bridge 아래로 전달
- Hot-plug 지원 시 미래 확장을 위해 Subordinate를 여유 있게 할당하기도 함
Capability Structure
PCIe 디바이스가 지원하는 선택적 기능을 Linked List 구조로 나열한 것이다. Capabilities Pointer(offset 0x34)에서 시작한다.
Capability 구조
각 Capability Entry:
Byte 0: Capability ID
Byte 1: Next Capability Pointer (0x00 = 마지막)
Byte 2~: Capability-specific Registers
주요 Capability ID:
0x01: Power Management Interface (PMI)
0x04: Slot Identification
0x05: MSI (Message Signaled Interrupt)
0x10: PCI Express Capability (필수)
0x11: MSI-X
0x12: SATA HBA
0x13: Advanced Features
PCI Express Capability (0x10) - 핵심 구조
Offset +0x00: Capability ID = 0x10
Offset +0x02: PCI Express Capabilities Register
[3:0] Capability Version
[7:4] Device/Port Type
0000 = PCIe Endpoint
0001 = Legacy PCIe Endpoint
0100 = Root Port
0101 = Upstream Port
0110 = Downstream Port
0111 = PCIe-to-PCI Bridge
1001 = Root Complex Integrated Endpoint
Offset +0x04: Device Capabilities Register
Offset +0x08: Device Control Register
Offset +0x0A: Device Status Register
Offset +0x0C: Link Capabilities Register
[3:0] Max Link Speed (1=2.5GT/s, 2=5GT/s, 3=8GT/s, 4=16GT/s, 5=32GT/s)
[9:4] Max Link Width (x1=1, x2=2, x4=4, x8=8, x16=16)
Offset +0x10: Link Control Register
[0] ASPM L0s Enable
[1] ASPM L1 Enable
[5:4] RCB (Read Completion Boundary)
[6] Link Disable
[7] Retrain Link
Offset +0x12: Link Status Register
[3:0] Current Link Speed
[9:4] Negotiated Link Width
[13] Link Training
[15] Link Bandwidth Management Status
Extended Capability Structure
PCIe 전용 확장 기능은 0x100 오프셋부터 시작하는 Extended Capability Space에 정의된다. 동일한 Linked List 구조이지만 포맷이 다르다.
각 Extended Capability Entry:
[15:0] Extended Capability ID
[19:16] Capability Version
[31:20] Next Extended Capability Offset (0x000 = 마지막)
주요 Extended Capability ID:
0x0001: Advanced Error Reporting (AER)
0x0002: Virtual Channel (VC)
0x0003: Device Serial Number
0x0004: Power Budgeting
0x000E: ARI (Alternative Routing-ID Interpretation)
0x0010: SR-IOV (Single Root I/O Virtualization)
0x0018: LTR (Latency Tolerance Reporting)
0x001E: L1 PM Substates
0x0023: Data Link Feature
0x0025: Physical Layer 16.0 GT/s
0x0026: Lane Margining at the Receiver
ARI (Alternative Routing-ID Interpretation)
- 기존 PCIe: Slot당 최대 8 Function (3-bit Function Number)
- ARI 활성화 시: Bus당 최대 256 Function (8-bit Function Number)
- SR-IOV의 Virtual Function 지원을 위해 필요
- Downstream Port와 Endpoint 모두 ARI 지원 시 활성화 가능
Command Register와 Status Register
Configuration Space offset 0x04의 Command/Status 레지스터는 디바이스의 기본 동작 제어에 사용된다.
Command Register (offset 0x04)
[0] I/O Space Enable - IO BAR 접근 허용
[1] Memory Space Enable - Memory BAR 접근 허용 (필수)
[2] Bus Master Enable - DMA 요청 허용 (PCIe에서 Posted/Non-Posted 생성 허용)
[6] Parity Error Response - Parity Error 시 Parity Error bit 세팅
[8] SERR# Enable - Fatal Error 시 SERR# 신호 발생
[10] Interrupt Disable - INTx 인터럽트 비활성화 (MSI 사용 시 설정)
Status Register (offset 0x06)
[3] Interrupt Status - INTx 인터럽트 펜딩 상태
[4] Capabilities List - 1이면 Capabilities Pointer 유효
[19] Signaled Target Abort - Completer에서 Abort 발생
[20] Received Target Abort - Requester 측에서 Abort 수신
[24] Master Data Parity Error
[27] Detected Parity Error
ECAM - Enhanced Configuration Access Mechanism
PCIe의 4KB Configuration Space에 접근하기 위한 메모리 매핑 방식이다. BIOS/UEFI가 MCFG(Memory Mapped Configuration) ACPI 테이블에 ECAM 기반 주소를 등록한다.
ECAM 주소 계산:
Base Address + (Bus << 20) | (Device << 15) | (Function << 12) | Offset
예: Base = 0xE0000000, Bus=1, Dev=2, Func=0, Offset=0x10
-> 0xE0000000 + (1 << 20) + (2 << 15) + (0 << 12) + 0x10
-> 0xE0000000 + 0x100000 + 0x10000 + 0x10
-> 0xE0110010
전통적인 CF8/CFC I/O Port 방식은 256바이트까지만 접근 가능
ECAM은 4096바이트 전체 접근 가능 (PCIe Extended Space 포함)
MSI / MSI-X
PCIe 디바이스의 인터럽트 메커니즘이다. 전통적인 INTx(레거시 인터럽트 핀 방식)를 대체한다.
MSI (Message Signaled Interrupt)
- Memory Write TLP를 통해 인터럽트 신호 전달 - 물리 핀 불필요
- 1~32개의 인터럽트 벡터 지원
- MSI Capability(0x05)의 Message Address/Data 레지스터에 OS가 값 설정
- 디바이스는 Message Address로 Memory Write TLP 전송 시 인터럽트 발생
MSI-X (MSI eXtended)
- 최대 2048개 벡터 지원 (MSI의 32개 대비 대폭 확장)
- MSI-X Table과 PBA(Pending Bit Array)를 BAR가 가리키는 메모리에 배치
- 벡터별로 독립적인 Address/Data 설정 가능 - NUMA/CPU Affinity 최적화
- 고성능 NVMe, 10GbE+ NIC 등에서 필수적으로 사용
SR-IOV (Single Root I/O Virtualization)
하나의 물리 PCIe 디바이스(Physical Function, PF)를 다수의 가상 Function(Virtual Function, VF)으로 분리하는 기술이다. 가상화 환경에서 디바이스를 VM에 직접 할당하는 데 사용한다.
- PF: 전체 디바이스 제어 담당 - SR-IOV Extended Capability 포함
- VF: 경량화된 Function - 데이터 경로(BAR)만 가짐, Configuration Space 최소화
- VF는 Enumeration 시 별도 BDF(Bus:Device:Function)로 노출됨
- ARI 활성화 필요 - VF 수가 많을 경우 256 Function 범위 필요
- IOMMU와 결합하여 각 VM의 DMA를 격리