BAR trong PCIe là gì?
Giải thích BAR trong PCIe: Base Address Register, MMIO/I/O BAR, 32-bit/64-bit BAR, prefetchable, sizing, resource allocation và debug MMIO fail.
Bạn thấy PCI device ở 02:00.0, Vendor ID đúng, Class Code đúng. Driver gọi PciIo->GetBarAttributes() cũng thấy BAR0 có base address. Nhưng khi đọc register trong BAR thì toàn 0xFFFFFFFF, hoặc access fault. Có khi BAR bằng 0, có khi 64-bit BAR bị driver parse nhầm thành hai BAR độc lập. Đây là nhóm bug rất phổ biến khi làm PCIe firmware.
Điểm cần hiểu là BAR.
Nói ngắn gọn: BAR, Base Address Register, là register trong PCI Configuration Space dùng để khai báo và chứa base address của vùng tài nguyên mà device cần, thường là MMIO hoặc I/O port. Firmware/OS probe BAR size, cấp address range, cấu hình bridge window và bật Command Register để driver có thể access device registers.
BAR nằm ở đâu?
BAR trong PCI Configuration Space
PCI Function Configuration Space
├─ 0x00: Vendor ID / Device ID
├─ 0x04: Command / Status
├─ 0x08: Revision / Class Code
├─ 0x0E: Header Type
├─ 0x10: BAR0
├─ 0x14: BAR1
├─ 0x18: BAR2
├─ 0x1C: BAR3
├─ 0x20: BAR4
├─ 0x24: BAR5
└─ Capability List... Endpoint Header Type 0 có tối đa 6 BAR. Bridge Header Type 1 có layout khác, nên không được parse như endpoint thường.
BAR trong enumeration flow
Read BAR original value
Firmware lưu BAR hiện tại trước khi sizing.
Write all 1s
Ghi 0xFFFFFFFF để device phản hồi size mask.
Read size mask
Tính size và type của BAR.
Allocate resource
Cấp MMIO/I/O range phù hợp từ root bridge aperture.
Program BAR base
Ghi base address vào BAR.
Program bridge windows
Bridge phía trên phải forward range đó.
Set Command Register
Bật Memory Space, I/O Space hoặc Bus Master khi cần.
Các loại BAR
| Loại BAR | Ý nghĩa | Debug khi lỗi |
|---|---|---|
| Memory BAR | MMIO register/resource | Driver map MMIO để access registers |
| I/O BAR | I/O port resource | Cần I/O Space Enable |
| 32-bit Memory BAR | Base address trong 32-bit address space | Below 4G resource |
| 64-bit Memory BAR | BAR dùng hai register liên tiếp | Parser sai làm mất BAR kế tiếp |
| Prefetchable BAR | Memory có thể prefetch/cache policy đặc biệt | Cần prefetchable bridge window |
| Non-prefetchable BAR | MMIO register thông thường | Không map như prefetchable bừa |
| Resizable BAR | BAR size có thể thay đổi qua capability | Resource allocation thay đổi theo policy |
| Unimplemented BAR | BAR không dùng | Read/probe ra 0 hoặc size 0 |
BAR bit layout cơ bản
BAR raw value có vài bit thấp dùng để mô tả type, không phải base address.
| Bit/field | Memory BAR | I/O BAR |
|---|---|---|
| Bit 0 | 0 nghĩa là Memory BAR | 1 nghĩa là I/O BAR |
| Bits 2:1 | Memory type, ví dụ 32-bit hoặc 64-bit | Reserved/khác theo I/O |
| Bit 3 | Prefetchable bit | Không dùng như memory prefetchable |
| Base address bits | Upper bits sau khi mask low bits | I/O base sau khi mask low bits |
| Alignment | Theo size BAR | Base phải aligned |
| 64-bit | Dùng BARn và BARn+1 | Không áp dụng kiểu memory 32-bit |
| Sizing mask | Read sau write all 1s | Dùng tính size |
| Assigned base | Firmware/OS ghi base vào BAR | Driver dùng base để map access |
64-bit BAR
64-bit BAR chiếm hai BAR register liên tiếp. Nếu BAR0 là 64-bit, thì BAR1 là phần high của cùng BAR, không phải resource độc lập.
64-bit BAR example
BAR0 low dword
├─ Bit 0 = 0: Memory BAR
├─ Bits 2:1 = 10b: 64-bit memory BAR
├─ Bit 3 = Prefetchable flag
└─ Base address low bits
BAR1 high dword
└─ Base address high bits
Next usable BAR
└─ BAR2, not BAR1 | Vấn đề | Biểu hiện | Cách kiểm tra |
|---|---|---|
| Parser coi BAR1 là BAR riêng | Resource list sai | Nếu BAR0 64-bit, skip BAR1 |
| High dword không ghi đúng | Base address sai trên above 4G | Read back BAR0/BAR1 |
| Above 4G disabled | Không cấp được large/64-bit BAR | Check setup/resource policy |
| Bridge window 32-bit | Endpoint BAR above 4G không forward | Check prefetchable 64-bit window |
| Driver truncate address | MMIO access sai | Use UINT64/EFI_PHYSICAL_ADDRESS |
| BAR size lớn | Resource allocation fail | Check root bridge aperture |
| Resizable BAR | Size không như expected | Check capability/policy |
| Alignment | Base phải aligned theo BAR size | Misaligned assignment invalid |
BAR sizing hoạt động thế nào?
Firmware/OS thường dùng quy trình probe size: ghi all 1s vào BAR, đọc lại mask, tính size, rồi restore/program base.
1. Save original BAR
2. Write 0xFFFFFFFF to BAR
3. Read back size mask
4. Mask type bits
5. Calculate size
6. Restore/program assigned base
| Bước | Cần đúng | Bug nếu sai |
|---|---|---|
| Save original | Lưu BAR trước khi probe | Mất base cũ |
| Disable decode nếu cần | Tránh decode trong lúc sizing | Transaction conflict |
| Write all 1s | Đúng width 32/64-bit | Size mask sai |
| Read mask | Mask type bits | Size tính sai |
| 64-bit handling | Probe low/high đúng | Truncate size/base |
| Restore/program | Ghi base address hợp lệ | BAR = 0 hoặc wrong base |
| Alignment | Base aligned theo size | Device không decode đúng |
| Bridge/root resource | Có window chứa resource | MMIO fail dù BAR set |
Prefetchable BAR
Prefetchable BAR cho biết vùng memory có thể được CPU/bridge prefetch theo rule nhất định. Nhưng không phải mọi MMIO register đều prefetchable.
| Khía cạnh | Prefetchable BAR | Non-prefetchable BAR |
|---|---|---|
| Ý nghĩa | Memory có thể prefetch nếu semantics cho phép | MMIO register cần strict ordering |
| Bridge window | Prefetchable memory window | Memory window thường |
| Cache policy | Có thể khác tùy OS/platform | Thường UC/device mapping |
| Thiết bị | Framebuffer/large memory window có thể prefetchable | Control registers thường non-prefetchable |
| Bug nếu sai | Ordering/data coherency issue | Performance thấp hoặc access issue |
| 64-bit window | Thường liên quan large BAR | Có thể below 4G |
| Debug | Check BAR bit 3 | Check bridge prefetch window |
| Security | Không map user-accessible bừa | Không map RWX hoặc cache sai |
BAR và Bridge Window
BAR của endpoint phía sau bridge phải nằm trong bridge window của tất cả bridges phía trên.
CPU accesses MMIO address
Driver đọc/ghi register trong BAR.
Root complex routes transaction
Address thuộc PCIe MMIO aperture.
Bridge window forwards
Bridge kiểm tra address nằm trong memory/prefetch window.
Endpoint BAR decodes
Device nhận transaction nếu BAR range match.
Register access
Device trả data hoặc thực hiện write.
| Điều kiện | Cần đúng | Nếu sai |
|---|---|---|
| Endpoint BAR base | Assigned address hợp lệ | BAR = 0 hoặc wrong base |
| BAR size | Size đủ và aligned | Overlap hoặc access ngoài range |
| Bridge memory window | Chứa non-prefetchable BAR | Transaction không forward |
| Bridge prefetch window | Chứa prefetchable BAR | Large/prefetch BAR fail |
| Root bridge aperture | Chứa toàn bộ resource | Allocator không cấp được |
| Command Memory Enable | Endpoint decode bật | Device không respond |
| Bridge command | Bridge forwarding bật | Downstream fail |
| Page table/cache | OS/firmware map đúng | CPU fault hoặc cache bug |
BAR và Command Register
BAR assign xong vẫn cần Command Register enable tương ứng.
| Bit | Liên quan BAR nào | Lỗi nếu chưa bật |
|---|---|---|
| Memory Space Enable | Memory/MMIO BAR | MMIO access không response |
| I/O Space Enable | I/O BAR | I/O port access không response |
| Bus Master Enable | DMA từ device | Device không DMA được |
| Interrupt Disable | INTx legacy | Interrupt behavior khác |
| SERR Enable | Error reporting | Error không propagate |
| Parity Error Response | Error handling | Debug bus error khó |
| Read-modify-write | Không phải bit, nhưng là cách ghi đúng | Ghi hardcode clear nhầm bit |
| Bridge command | Bridge cũng có command | Downstream forwarding issue |
BAR và EFI_PCI_IO_PROTOCOL
UEFI PCI driver thường không tự lấy BAR raw rồi map trực tiếp. Nó dùng EFI_PCI_IO_PROTOCOL để đọc BAR attributes, map MMIO và enable attributes.
| API/nhóm | Dùng để làm gì | Debug |
|---|---|---|
| GetBarAttributes | Lấy thông tin resource của BAR | BAR type/base/length |
| Attributes | Enable Memory/IO/BusMaster | Device decode/DMA |
| Mem.Read/Write | Access MMIO BAR | Register access debug |
| Io.Read/Write | Access I/O BAR | Legacy I/O |
| Pci.Read/Write | Đọc config space/BAR/Command | Config debug |
| Map/Unmap | DMA mapping | Bus master device |
| AllocateBuffer | DMA-safe buffer | DMA debug |
| GetLocation | BDF của controller | Log device đúng |
Debug Diary: BAR bằng 0
Triệu chứng:
Device tồn tại
BAR0 read = 0x00000000
Checklist BAR bằng 0
Debug Diary: MMIO đọc toàn 0xFFFFFFFF
Triệu chứng:
BAR có base
MMIO read register -> 0xFFFFFFFF
Checklist MMIO đọc toàn 0xFFFFFFFF
Debug Diary: 64-bit BAR parse sai
Triệu chứng:
BAR0 64-bit
Driver vẫn dùng BAR1 như BAR riêng
Hoặc base address bị truncate
Checklist 64-bit BAR parse sai
Debug Diary: Resource allocation fail vì BAR lớn
Triệu chứng:
Firmware báo out of resources
Large BAR / GPU / accelerator không được assign
Checklist BAR lớn allocation fail
Debug Diary: BAR access OK trong UEFI, fail trong OS
Triệu chứng:
UEFI driver đọc BAR register OK
OS driver đọc fail hoặc device mất
Checklist UEFI OK nhưng OS fail
Anti-pattern khi xử lý BAR
| Anti-pattern | Vì sao sai | Cách sửa |
|---|---|---|
| Dùng raw BAR làm base | Low bits chứa type flags | Mask đúng bit |
| Không handle 64-bit BAR | Base/size truncate | Ghép low/high và skip BAR tiếp theo |
| Không check Command Register | Device không decode | Enable Memory/I/O Space đúng |
| Chỉ nhìn endpoint BAR | Bridge window có thể sai | Check toàn path |
| Probe BAR khi OS sở hữu device | Có thể phá resource | Chỉ probe trong enumeration hoặc rất cẩn thận |
| Map MMIO WB bừa | Ordering/cache bug | Dùng UC/device attr nếu register MMIO |
| Không check BAR length | Access ngoài range | Validate offset |
| Ghi BAR hardcode | Resource conflict | Dùng allocator/firmware policy |
Instrumentation nên có
| Vị trí | Nên log | Mục tiêu |
|---|---|---|
| PCI enumeration | BDF + BAR raw values | Biết BAR hiện tại |
| BAR sizing | Type, size, prefetch, 64-bit | Debug resource request |
| Resource allocation | Assigned base/length | Debug allocation |
| Bridge windows | Memory/prefetch base-limit | Debug forwarding |
| Root bridge aperture | MMIO/I/O ranges | Debug out of resources |
| Command Register | Before/after bits | Debug decode/DMA |
| PciIo GetBarAttributes | BAR attributes | Verify firmware view |
| MMIO access | BAR index, offset, width, status | Debug register read/write |
| OS compare | UEFI vs OS resource dump | Debug handoff |
| Good/bad diff | BAR/resource diff | Regression |
BAR debug playbook
BAR debug playbook
Security checklist
Security checklist cho BAR/MMIO
Khi đọc BAR log nên tìm gì?
| Cần hiểu | Tìm trong log | Câu hỏi |
|---|---|---|
| BDF | Segment:Bus:Device.Function | Đúng device không? |
| Header Type | Type 0 hay Type 1 | Parse BAR đúng layout không? |
| BAR raw | Raw config value | Type bits là gì? |
| BAR type | MMIO/I/O, 32/64-bit | Driver xử lý đúng không? |
| Prefetchable | Bit prefetch | Window/cache policy đúng không? |
| Size | Sizing result | Resource cần bao nhiêu? |
| Base | Assigned address | Có non-zero và aligned không? |
| Bridge window | Memory/prefetch window | BAR có nằm trong window không? |
| Command | Memory/I/O/BusMaster bits | Decode/DMA enable chưa? |
| Access result | MMIO read/write status | Fail ở mapping hay device response? |
Câu hỏi tự kiểm tra
Tự kiểm tra sau khi đọc note này
Blog seeds
- BAR trong PCIe là gì?
- Base Address Register và MMIO giải thích dễ hiểu
- BAR có value nhưng MMIO đọc fail vì sao?
- 64-bit BAR trong PCIe debug
- Bridge window sai làm BAR access không hoạt động
Bài liên quan
- PCI/PCIe Architecture Overview
- BDF trong PCIe là gì?
- PCI Configuration Space là gì?
- MMIO là gì?
- PCI Resource Allocation là gì?
- Bridge Window trong PCIe là gì?
- PCI Root Bridge là gì?
- PCI Bus Driver là gì?
- PCI I/O Protocol là gì?
- EFI Out of Resources
Nguồn tham khảo public
- PCI-SIG Specifications
- UEFI Specification
- UEFI Platform Initialization Specification
- Tianocore EDK II
- EDK II Driver Writer’s Guide
Bài viết này hữu ích với bạn?
Bạn có thể chia sẻ cho người đang học firmware, BIOS/UEFI, embedded systems hoặc ủng hộ tác giả.
Nội dung liên quan
Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.
Bridge Window trong PCIe là gì?
Giải thích Bridge Window trong PCIe: memory window, prefetchable window, I/O window, bus number, BAR forwarding và debug endpoint sau bridge mất.
PCI Resource Allocation là gì?
Giải thích PCI Resource Allocation trong UEFI: BAR sizing, MMIO/I/O aperture, bridge windows, Above 4G, allocation fail và debug BAR bằng 0.
MMIO là gì?
Giải thích MMIO trong PCIe/firmware: memory-mapped I/O, BAR mapping, cache attribute, ordering, bridge window và debug register read fail.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.