這是本文件的舊版!
項目 | Mechanism #1(I/O Port Based) | Mechanism #2(MMIO / ECAM Based) |
---|---|---|
📜 標準名稱 | PCI Spec | PCIe Base Spec(ECAM) |
👨💻 存取方式 | 透過 I/O Port 0xCF8/0xCFC | 透過 MMIO 直接對應 Config 空間 |
🧱 硬體需求 | 不需要 MMCONFIG | 需提供 MMCONFIG base 地址 |
📍 典型使用平台 | Legacy BIOS, x86(PCI) | UEFI, modern x86-64(PCIe) |
🗂 Address 空間 | 利用 32-bit I/O Port 做定址 | 每個 Function 對應 4KB MMIO 區 |
⚙️ 實體地址組成 | CF8 / CFC | PCIEX_BASE_ADDRESS + Calculation |
🔄 支援 Config 空間大小 | 256 Bytes(PCI) | 4KB(PCIe) |
🔍 可見性 | 無法被一般 Memory View 工具看到 | 可透過 memtool / debugger 查看 |
🔒 安全性 | 較低,容易誤操作 | 較安全,區段獨立清楚 |
🚫 限制 | 無法存取多段 Bus 空間、無法支援完整 PCIe 擴展功能 | 需 BIOS/ACPI 支援並正確配置 MMCONFIG |
#define PCI_ADDR(bus, dev, func, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xFC)) IoWrite32(0xCF8, PCI_ADDR(0, 31, 0, 0x10)); UINT32 val = IoRead32(0xCFC); // 讀 BAR0
0xCF8 Address 格式(32-bit)
Bit | 範圍 | 名稱 | 寬度 | 說明 |
---|---|---|---|---|
31 | Enable Bit | 1 | 必須設為 1 才能啟用 | |
30–24 | Reserved | 7 | 必須為 0 | |
23–16 | Bus | 8 | Bus number | |
15–11 | Device | 5 | Device number | |
10–8 | Function | 3 | Function number | |
7–2 | Register | 6 | Config register number (dword aligned) | |
1–0 | Always 0 | 2 | 必須為 0(因為只能對齊讀取) |
如何透過 Mechanism 1 存取 bus 0 device 31 function 0 offset 0 Bus = 0x00 → bit 27–20 = 0000_0000 Device = 0x1F (31) → bit 19–15 = 11111 Function = 0x03 → bit 14–12 = 011 Offset = 0x10 → bit 11–0 = 0000_0001_0000 Enable Bit = 0x80000000 + Bus = 0x00000000 + Devicec = 0x000F8000 + Function = 0x00000000 + Offset = 0x00000000 ------------------------------- 最終地址 = 0x800F8000
#define PCIEX_BASE_ADDRESS 0xC0000000 UINT32* bar0 = (UINT32*)(PCIE_ECAM_BASE + (0 << 20) + (31 << 15) + (0 << 12) + 0x10); val = *bar0; // 直接透過 Memory Read 存取 BAR0
如何透過 Mechanism 2 存取 bus 0 device 31 function 0 offset 0 Bus << 20 = 0 << 20 = 0x00000000 Device << 15 = 31 << 15 = 0x000F8000 Function << 12 = 0 << 12 = 0x00000000 Offset = 0x00000000 ------------------------------- 總和 = 0x000F8000 PCIEX_BASE_ADDRESS = 0xC0000000 + Offset Sum = 0x000F8000 ------------------------------- 最終地址 = 0xC00F8000 使用 Utility -> RW -> Memory 讀取 0xC00F8000