把一段裝置資源接到 CPU 的存取路徑

選擇步驟後,圖中對應的元件與下方解說會加上重點標示。完整圖與所有解說會持續顯示;也可用方向鍵切換步驟。

先看最內層 BAR 的需求,再向外檢查沿途視窗。這是配置及檢查順序;圖中的框表示位址範圍關係。

BAR
Base Address Register,基底位址暫存器
巢狀範圍表示沿途視窗涵蓋同一裝置資源,不代表各層另配置一份裝置記憶體。巢狀範圍表示沿途視窗涵蓋同一裝置資源,不代表各層另配置一份裝置記憶體。CPU 存取裝置資源依平台位址轉譯Root Port Window:涵蓋下游配置Switch 路徑各層 Window:涵蓋同一目標Endpoint Memory BAR已配置的基底、大小與對齊

作者的位址涵蓋示意。CPU 位址與 BAR 中的位址是否相同,需依平台的位址轉譯判定。

BAR
Base Address Register,基底位址暫存器

BAR(Base Address Register,基底位址暫存器)提供裝置資源的型別與配置入口。軟體先取得需求,再分配對齊的位址,讓沿途 Bridge Window 涵蓋它,最後開啟適用的解碼。

前情提要:Chapter 3 已找到這個 Function。現在處理它的資源,尚未開始驅動程式的工作流程。

規格路線:Figures 7-10–7-12/Table 7-9 → Figure 7-14 與 Bridge Window 條文 → Figure 7-5/Table 7-4 的 Command 控制。

  1. 先讀型別與需求

    本章的大小探查是受配置者控制的初始化情境;先停止相關解碼並保存原值,不對使用中的裝置任意寫全 1。

    讀 Memory/I/O 類型、32/64-bit 與 Prefetchable 屬性,再用適用方式取得大小。64-bit Memory BAR 會使用相鄰兩個欄位。

    Base 6.0 §7.5.1.2.1/Figures 7-10–7-12/Table 7-9,pp.928–930。

  2. 分配可容納且對齊的範圍

    保留 BAR 的屬性位元,確認位址寬度、對齊及平台轉譯;下方算例逐項驗算。

    依大小與型別選擇平台可提供的位址,再把基底寫入 BAR。大小遮罩與實際配置值分別用來回答需求及位置。

    Base 6.0 §7.5.1.2.1,pp.929–930;Firmware 3.3 §3.1.1,p.32。

  3. 讓沿途視窗涵蓋目標

    分別依視窗型別、粒度與上下界編碼處理;圖沒有把 Prefetchable 屬性當成 CPU 快取設定。

    沿 Endpoint 到根部檢查每層 Memory 或 Prefetchable Window;任一層沒有涵蓋目標範圍,都會影響轉送。

    Base 6.0 §7.5.1.3.8–§7.5.1.3.10,pp.940–941。

  4. 開啟本次路徑需要的解碼

    MSE 是 Memory Space Enable,控制 Memory Space 存取;BME 是 Bus Master Enable,關係到 Function 發起交易。兩者的用途分開判讀。

    完成資源配置後,依路徑設定 Memory Space Enable。裝置發起交易另看 Bus Master Enable;後續 DMA 準備由 Chapter 6 接續。

    DMA
    Direct Memory Access,裝置直接存取記憶體

    Base 6.0 §7.5.1.1.3/Figure 7-5/Table 7-4,pp.918–920。

圖中元件

Endpoint 的 BAR

本圖最內層是這個 Function 提供的裝置資源範圍。

基本責任

BAR 保存配置資訊,本身不是一塊可供 CPU 任意讀寫的資料緩衝區。

1. BAR 是一個資料緩衝區,還是一份資源描述?

BAR 是 Base Address Register,位於 Function 的 Configuration Header。它讓軟體辨認資源類型、查出需求大小,並寫入分配的基底位址。裝置的工作暫存器或資料區,則位於這個資源所映射的位置;讀 BAR 本身不等於讀到那些內容。

同一條路徑會同時用到三種不同的範圍
設定它描述什麼?不要拿它代替什麼?
Secondary/Subordinate Bus Number設定拓樸中的下游 Bus 範圍。不能代替 Memory Request 的位址路由範圍。
Endpoint 的 BAR這個 Function 自己要解碼的資源範圍。不能單獨保證沿途 Bridge 會轉送。
Bridge 的 Memory/Prefetchable WindowBridge 要轉送到下游的位址範圍。不是 Bridge 自己的 BAR,也不表示窗口內每個 byte 都有裝置回應。

先用 Figure 7-10 找 Type 0 Header 的 BAR 位置;遇到 Bridge,則用 Figure 7-14 分開看 BAR 與 Window。Type 0 Header 提供六個 DWORD 位置,從 0x10 到 0x24;Type 1 Header 只有兩個。64-bit BAR 會佔用連續兩個位置,所以「六個位置」不等於「六個獨立資源」。

規格位置

Base 6.0 §7.5.1.2.1,Figure 7-10,pp.928–930;§7.5.1.3,Figure 7-14,p.936;Memory/Prefetchable Window:§7.5.1.3.8–§7.5.1.3.10,pp.940–941。

2. 先讀哪幾個 bits,才知道後面怎麼算?

先看 BAR bit 0。為 0 時用 Memory BAR 格式,為 1 時用 I/O BAR 格式。兩者的位址遮罩不同,不能一律清掉低 4 bits。

Figure 7-11/7-12 的判讀入口
格式類型與屬性位址部分
Memory BARbit 0=0;bits 2:1 的 00b 表示 32-bit,10b 表示 64-bit;bit 3 是 Prefetchable。低 DWORD 的 bits 31:4;若為 64-bit,下一個 DWORD 接成 bits 63:32。
I/O BARbit 0=1,bit 1 保留;這個格式固定是 32-bit。bits 31:2。特定 16-bit I/O 相容配置另有大小計算規則。

Prefetchable 表示這段資源容許規格列出的讀取與合併行為,例如讀取沒有副作用,且可接受寫入合併。它不是「CPU 現在一定有快取」的狀態位,也不能拿來推論應用程式實際帶寬。

對本章的一般 PCI Express Endpoint,設為 Prefetchable 的 BAR 必須支援 64-bit addressing;非 Prefetchable BAR 可以是 32-bit。此類 Endpoint 也不得依賴 OS 配置 BAR 宣告的 I/O 資源,且不得發出 I/O Requests。本例因此只用 Memory BAR;I/O 格式保留在這裡,是為了讓讀者能辨認相容機制。

欄位與類型限制

Base 6.0 §7.5.1.2.1,Figures 7-11/7-12、Table 7-9,pp.929–930;一般 Endpoint 的限制見 §1.3.2.2,p.105。Memory Type 01b、11b 在本版為 Reserved;不要把舊版低於 1 MB 的編碼無聲套進本例。

3. 寫全 1 再讀回,為什麼能知道大小?

BAR 的位址欄位中,低位元有多少固定為 0,反映需要的自然對齊大小。規格提供的探測方法,是先停止對應位址解碼,保存原 BAR,寫全 1 再讀回;遮掉類型位元後,對指定寬度取反加 1。探測完要還原原值,才能回到原配置;若接著重新分配資源,也必須在重新啟用前完成一致的配置。

BAR 大小探測的假設讀回資料
位置探測前保存值寫入全 1 後的讀回值本例角色
BAR0,0x100x000000000xFFFFC00032-bit、非 Prefetchable Memory BAR。
BAR2,0x180x0000000C0xFFE0000C64-bit、Prefetchable BAR 的低 DWORD。
BAR3,0x1C0x000000000xFFFFFFFF上一列的高 DWORD,不能當成另一個 BAR 解碼。

本例另外假設 BAR1、BAR4、BAR5 未實作;未實作 BAR 固定回 0。探測前的 BAR0 也是 0,卻是有效、尚未分配基底的資源,所以不能只看初始值為 0,就宣告 BAR 不存在。

BAR0:先限定 32 bits,再取反

address_mask = 0xFFFFC000 & 0xFFFFFFF0 = 0xFFFFC000
size = ((~address_mask) & 0xFFFFFFFF) + 1
     = 0x00004000 = 16 KiB

這表示基底必須以 16 KiB 對齊。若用沒有固定位寬的運算工具,必須把取反限制在 32 bits;直接使用無限精度的負整數結果,會算錯大小。未實作 BAR 的全 0 探測結果也不能拿去套公式,然後宣布要分配 4 GiB。

BAR2/BAR3:兩個 DWORD 是一個 64-bit 問題

address_mask = (0xFFFFFFFF << 32) | (0xFFE0000C & 0xFFFFFFF0)
             = 0xFFFFFFFFFFE00000
size = ((~address_mask) & 0xFFFFFFFFFFFFFFFF) + 1
     = 0x00200000 = 2 MiB

低 DWORD 的 0xC 解成 Memory Type=10b、Prefetchable=1。軟體探測時必須處理兩個 DWORD,保存與還原也要包含兩者;走訪 BAR 清單時,下次應前進到 BAR4,不能把 BAR3 的全 1 再當成 I/O BAR。

探測流程與算式依據

Base 6.0 §7.5.1.2.1,pp.929–930,尤其 p.930 的「Sizing a 32-bit Base Address Register Example」與其後 64-bit 說明。自然對齊、2 的冪次大小、未實作 BAR 回 0 均見同頁。本例沒有 Resizable BAR;若有該能力,還要確認目前選用的大小與相關規則,不能直接沿用本例固定需求。

4. 知道大小後,可以挑任意空位填進去嗎?

還要同時滿足平台允許的資源範圍、BAR 位址寬度、大小對齊,以及與其他分配不重疊。以下基底是作者從假設的可用資源中選出的結果;它們不是規格推薦的固定位址。

本例的資源配置
資源分配的 PCI 位址範圍(含首尾)配置後的 BAR 值
BAR0:16 KiB0x80004000–0x80007FFF0x10:0x80004000
BAR2/3:2 MiB0x0000000120000000–0x00000001201FFFFF0x18:0x2000000C;0x1C:0x00000001

案例推演:BAR0 的尾端是 0x80004000 + 0x4000 - 1 = 0x80007FFF;BAR2/3 的尾端是 0x120000000 + 0x200000 - 1 = 0x1201FFFFF。兩個基底各自是所需大小的整數倍。64-bit BAR 的高 DWORD 為 1,讓這段資源位於 4 GiB 以上;這不代表裝置真的有 4 GiB RAM,也不表示一次交易要搬 64 bits 的資料。

接著假設裝置介面規格定義 BAR0 內的 +0x120 是可讀 Register,則它在 PCI 位址空間的位置為 0x80004120。本例另假設 Host Bridge 對這段 MMIO 使用相同的 CPU/PCI 位址,因此 CPU 也使用 0x80004120。這個相同映射是教學前提;Firmware 3.3 §3.1.1 明確容許兩種視角不同,不能把所有平台都當成如此。

MMIO
Memory-Mapped I/O,記憶體映射輸入輸出
來源與作者假設

Base 6.0 §7.5.1.2.1,pp.928–930。PCI Firmware 3.3 §3.1.1,p.32 說明 non-identity MMIO mapping。兩個可用範圍、相同映射,以及裝置內 +0x120 Register 都是本例假設;PCIe Base 並未定義這個裝置專屬 Register 的功能。

5. Endpoint 的 BAR 已經填好,為什麼還可能收不到?

位址要求還得穿過沿途的 Bridge。沿 Chapter 1 的拓樸,到目標要經過 Root Port 00:01.0、Switch Upstream Port 01:00.0,以及 Downstream A 02:01.0。三者的相關 Window 都必須涵蓋目標資源;只改最靠近 Endpoint 的那一個,無法補上上游缺少的範圍。

Memory Window 與 Endpoint BAR 的包含關係本例沿途三個Bridge都配置80000000到800FFFFF的Memory Window,內含Endpoint的BAR0範圍80004000到80007FFF。CPU讀取80004120落在BAR0內,但Window其他位置不因此保證有有效Register。每層 Bridge Window:0x80000000–0x800FFFFFEndpoint BAR0:0x80004000–0x80007FFF本例 Register:0x80004120(BAR0 + 0x120)範圍包含示意,不按容量比例;沿途三層都需核對。
自製圖。Bridge Window 可以比 BAR 大;較大的窗口不保證空隙中有可用 Register。
本例三個 Bridge 都採用的 Window 設定
Type 1 Header 欄位offset/寬度假設配置值
Memory Base/Memory Limit0x20/0x22,各 16 bits0x8000/0x8000
Prefetchable Memory Base/Limit0x24/0x26,各 16 bits0x2001/0x2011
Prefetchable Base Upper/Limit Upper0x28/0x2C,各 32 bits0x00000001/0x00000001

先看 Figure 7-14 定位,再讀 §7.5.1.3.8–§7.5.1.3.10。Memory Base/Limit 的高 12 bits 對應 Address[31:20];Base 省略的低 20 bits 補 0,Limit 則補 1。因此 Limit 不是排除式邊界,不能再少算或多算一個 byte。

Memory Base  = (0x8000 & 0xFFF0) << 16 = 0x80000000
Memory Limit = ((0x8000 & 0xFFF0) << 16) | 0xFFFFF = 0x800FFFFF

Prefetchable Base  = (1 << 32) | ((0x2001 & 0xFFF0) << 16)
                  = 0x120000000
Prefetchable Limit = (1 << 32) | ((0x2011 & 0xFFF0) << 16) | 0xFFFFF
                  = 0x1201FFFFF

本例三個 Bridge 都實作 64-bit Prefetchable Window,所以 Base/Limit 的低 nibble 為 1,並使用 Upper 32 Bits。非 Prefetchable Memory Window 則是 1 MiB 粒度,足以涵蓋 BAR0 的 16 KiB;Prefetchable Window 剛好涵蓋另一個 2 MiB BAR。其餘分支不使用這兩段資源,平台也已保留這些範圍供本例使用。

窗口編碼的來源

Base 6.0 Figure 7-14,p.936;§7.5.1.3.8,p.940;§7.5.1.3.9–§7.5.1.3.10,pp.940–941。未使用的窗口要依該節規則處理,不能把未配置的零值直接當成「關閉」。本章的窗口大小、同值配置於三個 Bridge,以及資源分支配置皆為作者假設。

6. MSE 與 BME,哪一個才是「啟用裝置」?

沒有一個位元能代替所有準備工作。Command Register 在 offset 0x04、寬度 16 bits;讀 Figure 7-5/Table 7-4 時,應把以下三個控制分開。

Command bits 0–2 各自控制的方向
位元對本例 Endpoint 的作用沿途 Port 還要注意什麼?
bit 0:I/O Space Enable控制是否解碼並處理收到的 I/O 存取;本例不用 I/O BAR。Type 1 的控制涉及 Primary Side 收到的 I/O 存取。
bit 1:Memory Space Enable(MSE)控制是否解碼並處理收到的 Memory 存取。各 Bridge 的相關解碼與窗口也須有效。
bit 2:Bus Master Enable(BME)允許 Function 發起 Memory/I/O Requests;一般 PCIe Endpoint 另受不得發 I/O Requests 的限制。Type 1 Port 的 BME 也控制向上游發起/轉送 Memory、I/O Requests;不阻擋 Completion 轉送。

案例推演:所有 BAR、Window 與平台映射已正確配置,且裝置介面已可接受本例讀取時,Endpoint 與路徑上各 Bridge 的 Command 若為 0x0002,表示 MSE=1、BME=0。CPU 可依已建立的路徑讀取本例 MMIO Register;Endpoint 仍不能自行發起 DMA 的 Memory Request。它回覆這筆讀取所需的 Completion,不是被 BME 禁止的 Memory Request。

MMIO
Memory-Mapped I/O,記憶體映射輸入輸出
DMA
Direct Memory Access,裝置直接存取記憶體

之後若要讓 Endpoint 主動搬移資料,不能只把自己的 Command 改成 0x0006 就宣告成功。還要確認上游 Port 的 BME、裝置工作設定、有效緩衝區,以及平台位址與存取權限。BME 為 1 是允許相關要求的必要控制,不是 DMA 已準備好的證據。MSI/MSI-X 也屬於帶內 Memory Write,因此 BME=0 同樣會禁止這類通知。

MSI
Message Signaled Interrupt,訊息中斷
MSI-X
Message Signaled Interrupts Extension,表格式訊息中斷

修改 Command 時應使用對應欄位寬度並保存其他控制;相鄰的 Status 在 0x06,含有 RW1C 位元。不要把 Command 與 Status 一起讀成 32 bits,再原樣回寫整個 DWORD,以免意外清除狀態。RW1C 的語義見 Chapter 2。

啟用條件的依據

Base 6.0 §7.5.1.1.3,Figure 7-5/Table 7-4,pp.917–920,尤其 MSE p.918、BME 與 MSI/MSI-X/Completion p.919。Command 與 Status 的相鄰布局見 Figure 7-4,p.916;Status 的 RW1C 範例見 Table 7-5,pp.922–923。配置 BAR 前後的解碼處理見 p.930。

設定空間可讀,為什麼 Memory Read 還會失敗?

設定存取用 BDF 與 Register offset 選擇 Function 和欄位;Memory Read 則使用記憶體位址選擇目標。沿用本章案例,先把 0x80004120 放回 BAR0 與每一層 Window,再檢查接收方向上的 Memory Space Enable(MSE,記憶體空間解碼控制)。

BDF
Bus/Device/Function,匯流排、裝置與功能識別

查閱時先由 Figure 7-10/Figure 7-14 定位 BAR 與 Bridge 欄位,使用 §7.5.1.3.8 解碼 Memory Base/Limit,接著讀 Figure 7-5/Table 7-4 的 MSE,注意 Type 1 Header 的 Primary Side 條件。最後用 §2.3.1 的 Request Handling 規則確認需要 Completion 的 UR 如何回覆。(Base 6.0,文件頁/PDF 頁 208、916–918、928、936、940。)

只要位址落在 BAR 內,每個 byte 都可以讀嗎?

BAR 的大小定義資源位址範圍;實際有哪些可用的裝置 Register,要查裝置介面文件。本例只假設 +0x120 是可讀 Register,並未定義 +0x3000 的用途,雖然它也在 BAR0 範圍內。Base 6.0 §7.5.1.2.1(p.930)允許 Function 對程式模型從不存取的未使用位置回 UR。要判定某次存取的結果,還需要該裝置介面及實際交易證據。

7. OS 怎麼知道韌體交給它的 BAR 有效?

Firmware 3.3 §3.5 說明,OS 以 Command 的 I/O/Memory Enable,以及 Expansion ROM 的 Enable,判斷相應資源是否已由韌體配置;不使用 BME 判定 BAR 是否有效。所以交接時看到 MSE=1、BME=0,不代表 BAR 無效;資源既然已啟用,韌體就必須正確配置。

ROM
Read-Only Memory,唯讀記憶體

這項交接契約也不表示只要讀到 MSE=1,就能忽略平台映射或任意操作裝置。本章的配置表解決了位址與轉送問題;驅動程式仍要依裝置介面規格初始化工作流程。

交接規則來源

PCI Firmware Specification Revision 3.3 §3.5,pp.34–35;本段採用該版本的資源有效性判斷,沒有把 BME 當成 BAR 配置的替代證據。

8. 把型別、對齊與視窗接起來

把 16 KiB 的 BAR0 放在 0x80005000,其他條件都不變,可以嗎?

不行。0x80005000 & 0x3FFF = 0x1000,不是 16 KiB 對齊。大小正確但基底未自然對齊,仍不是合法的分配。(§7.5.1.2.1,p.930。)

BAR2 的低 DWORD 讀到 0xFFE0000C,能只用這 32 bits 判定 64-bit 資源大小嗎?

不能。先用 bits 2:1 確定它是 64-bit BAR,再把 BAR3 作為高 DWORD 一起探測與計算。低 DWORD 只是完整遮罩的一部分。(Figures 7-11、Table 7-9,p.929;64-bit 探測,p.930。)

三個 Bridge 的 Memory Window 都正確,Endpoint 的 MSE 卻為 0,CPU 讀 BAR0 還會成功嗎?

不能據此期待成功。Endpoint 的 MSE=0 時,收到的 Memory Space 存取依 UR 處理;沿途可轉送不等於終點已啟用。(Table 7-4,p.918。)

Command 從 0x0002 改成 0x0006,就證明 DMA 緩衝區位址正確了嗎?

沒有。兩者差在 BME;它不驗證裝置工作描述項、緩衝區生命週期或平台轉譯。還要建立並核對那些資料,才能讓裝置開始工作。

9. 接下來追蹤一筆真正的交易

到這裡,系統已能選定 Function、找到能力、建立 Bus 路徑並配置資源。Chapter 5 接著追蹤 CPU 的一次讀取如何形成 Request,以及 Completion 如何回到要求者。完整安排見 課程閱讀路線。

版本與來源

PCI Express Base Specification Revision 6.0 與 PCI Firmware Specification Revision 3.3。所有來源位置就近標示;大小、位址、裝置內 Register 與平台映射均為教學假設。Firmware 3.3 並非 Base 6.0 的同版配套,兩者分別用於欄位規則與交接背景。查核日期:2026-10-28。