先選清單,再把序號讀出來
選擇步驟後,圖中對應的元件與下方解說會加上重點標示。完整圖與所有解說會持續顯示;也可用方向鍵切換步驟。
先讀兩種入口的差別,再沿右側完成 DSN 查詢。左側是對照,並非必須先走完它才能開始右側。
- MSI-X
- Message Signaled Interrupts Extension,表格式訊息中斷
- AER
- Advanced Error Reporting,進階錯誤回報
沿用前章已找到的裝置功能,本章要讀出它提供的裝置序號。查詢先從設定空間選對清單,再沿指標找到能力結構,最後讀取資料欄位並解釋位元組順序。這條路徑也能用來理解其他能力的查詢。
選定 Function 與正確入口
普通 Type 0 Endpoint;平台能存取完整設定空間,讀取成功且快照穩定。
先用 Segment 與 BDF 選定設定對象,再以 byte offset 選擇其中的位置。傳統清單與 Extended Capability(延伸能力)清單各有入口。
- BDF
- Bus/Device/Function,匯流排、裝置與功能識別
Base 6.0 §7.2/Figure 7-3、§7.6.1/Figure 7-42,文件頁/PDF 頁 905–906、1009。
用傳統清單看懂 Next 的用途
此處作為清單格式的對照;本次序號查詢使用右側的延伸清單。
傳統清單的 Null Capability 是沒有功能資料的節點。其 ID=0 仍須依 Next Pointer(下一項位置)繼續到 0x70;這一路沒有接到延伸清單。
Base 6.0 §7.9.27/Figure 7-384/Table 7-336,文件頁/PDF 頁 1315。
從延伸清單找到序號結構
AER 是進階錯誤回報結構;本例不支援 Flit Mode,因此使用其 Version 2。
- AER
- Advanced Error Reporting,進階錯誤回報
在 0x100 讀 Header,分出 ID、Version 與 Next。沿 Next=0x180 到下一項,確認 DSN(Device Serial Number,裝置序號)ID=0003h、Version=1。
Base 6.0 Figures 7-43/7-154/7-242、Tables 7-39/7-134/7-221,文件頁/PDF 頁 1010、1112、1206。
以目前結構起點取得資料
DWORD 是四個 bytes。這組序號數值只示範重組,不宣稱已配發,也不用來認證硬體。
DSN 是提供裝置序號的能力。由目前起點 0x180 加 0x04、0x08,讀取低、高 DWORD,再依 Table 7-222 的位元組對映重組序號。
Base 6.0 Figures 7-241–7-243/Tables 7-221–7-222,文件頁/PDF 頁 1205–1207。
圖中元件
Function:本次的設定對象
本次固定查詢 0000:03:00.0 的設定空間。
基本責任
每個 Function 各有設定空間;byte offset 只在選定的 Function 內定位。
DSN:裝置序號能力
在 0x180 確認結構後,才讀它的兩個資料 DWORD。
基本責任
DSN 為可選能力;一般多功能 Device 中有實作的各 Function 必須回報相同序號。
先回想兩個步驟:Segment 與 BDF 選定要查的功能,Header Layout 與 Device/Port Type 說明它採用的結構與角色。這裡從相同對象繼續往設定空間內部找。
- BDF
- Bus/Device/Function,匯流排、裝置與功能識別
1. 同一個 offset,先問它從哪裡算起
選定 Function 之後,它的 PCIe Configuration Space(設定空間)提供 4096 bytes 的位置。前 256 bytes 保留 PCI 相容布局,其後是 Extended Configuration Space(延伸設定空間)。本章的 byte offset 都只描述這份設定空間內的位置;CPU 實際執行存取所需的平台位址另由存取機制提供。
例如,0x34 是從 Function 設定空間起點計算的 Capabilities Pointer;某個結構標示的 Offset 04h,則可能是從該結構起點計算。先確認原圖畫的是整份設定空間,還是其中一個結構,再做加法。
設定空間透過記憶體映射存取,就等於裝置的 Memory BAR 嗎?
- BAR
- Base Address Register,基底位址暫存器
不等於。ECAM(Enhanced Configuration Access Mechanism)把 CPU 對指定記憶體範圍的存取轉成 Configuration Request;BAR 則描述裝置所需的資源。兩者都可能從 CPU 的記憶體位址發起,目的與轉換方式卻不同。
- BAR
- Base Address Register,基底位址暫存器
查詢介面還必須能存取所需範圍。PCI 相容存取機制只涵蓋前 256 bytes;不能用它沒有提供的能力,推論 0x100 之後的功能不存在。ECAM(將 CPU 記憶體存取轉成設定要求的機制) 的平台基址與可用 Bus 範圍要由平台提供,本章不自行猜一個實體位址。
規格依據與存取限制
Base 6.0 §7.2–§7.2.2.2,pp.905–909;Table 7-1(pp.907–908)列出 ECAM 位址中的 Bus、Device、Function 與 Register 部分。跨 DWORD 邊界或使用鎖定語意的 CPU 存取,不保證能由 Root Complex 轉成 Configuration Request(pp.907、909)。本章使用自然對齊、大小明確的設定讀取。
同一個 offset,為什麼兩個 Function 的欄位不同?
先讀所選 Function 在 0x0E 的 Header Type Register(標頭類型暫存器),以 bits 6:0 的 Header Layout 選圖。Type 0 的配置看 Figure 7-10;代表 Root Port 或 Switch Port 的 Type 1 配置看 Figure 7-14。兩張圖的橫向位置是 bit,最右側是從 Configuration Space 起點算的 byte offset。
| offset | Type 0 | Type 1(Root/Switch Port) |
|---|---|---|
| 0x10–0x14 | Base Address Registers(BAR,資源基底暫存器)的一部分 | 此 Port 的 BAR 0、BAR 1 |
| 0x18 | BAR 區域的一部分 | Primary、Secondary、Subordinate Bus Number 等欄位 |
| 0x20 | BAR 區域的一部分 | Memory Base 與 Memory Limit |
例如,看到 0x18 的 32-bit 讀值後,先取得同一 Function 的 Header Layout;選到 Type 1 才把其中對應的 bytes 解作 Bus Number。Type 0 的同一位置則屬於 BAR 區域。再查具體 BAR 的型態與欄位定義,才能解讀其用途。Type 1 的 Bus Number 用於安排下游搜尋範圍,Memory Base/Limit 描述資源視窗;完整配置與路由分別接到 Chapter 3 和 Chapter 4。
Header Type 的 bit 7 與 bits 6:0 要分開讀。以本章假設值 0x80 為例,Layout 為 Type 0,bit 7 表示 Device 可能有多個 Function,還需進一步查詢。VF 有不同適用規則,本例不納入。Header Layout 與 Configuration Request 的 Type 0/Type 1 封包分類也各有定義。
- VF
- Virtual Function,虛擬功能
閱讀位置:Base 6.0 §7.5.1.1.9、Figure 7-8/Table 7-7(文件頁/PDF 頁 924–925);Figure 7-10(p.928);Figure 7-14 及其適用說明(p.936)。先從 Header Type 選圖,再讀該圖的 offset 與對應欄位說明。
2. 想查某項功能,要先走哪一份清單?
先在指定版本的規格中找到目標功能的正式結構。本章要找 Device Serial Number,它屬於 Extended Capability;先前用過的 PCI Express Capability 則屬於前 256 bytes 的傳統清單。確認分類後,才使用相應入口與 Header 格式。
| 比較項目 | 傳統 Capability | Extended Capability |
|---|---|---|
| 設定空間內的入口 | 先看 Status.Capabilities List,再讀 Header 的 Capabilities Pointer;本章 Type 0/1 在 0x34。 | 從 0x100 的 32-bit Header 開始,不接在傳統清單尾端。 |
| 識別與下一項 | 一般開頭的低 byte 是 8-bit ID,高 byte 是 8-bit Next Pointer。 | bits 15:0 為 ID,19:16 為 Version,31:20 為 Next Offset。 |
| 下一項的基準 | Function 設定空間起點;不是目前結構起點。 | 同樣從 Function 設定空間起點計算。取出後要遮掉低 2 bits。 |
| 清單結束 | Next Pointer 為 0。ID 為 0 的 Null Capability 仍可能有下一項。 | Next Offset 為 0。若完全沒有 Extended Capability,0x100 的 Header 依規格回報 ID、Version、Next 全為 0。 |
這張表的來源與例外
Base 6.0 §7.5.1.1.4,Figure 7-6/Table 7-5(pp.921–922);§7.5.1.1.11(p.926);傳統 Header 例見 Figure 7-22/Table 7-18(p.953)。Extended 格式見 §7.6–§7.6.3、Figures 7-42/7-43、Table 7-39(pp.1008–1010)。Null Capability 見 §7.9.27、Figure 7-384/Table 7-336(p.1315)。RCRB 的起點與空清單規則不同,本章沒有把它納入。
3. 清單中出現 ID = 0,就可以停止了嗎?
| Function 內 byte offset | 讀取寬度 | 讀值 | 這次查詢的用途 |
|---|---|---|---|
| 0x0E | 8 bits | 0x80 | Header Layout 為 Type 0;bit 7 表示 Device 可能有多個 Function。 |
| 0x06 | 16 bits | 0x0010 | Status bit 4 為 1,有 Capability 清單。 |
| 0x34 | 8 bits | 0x40 | 第一項位於 0x40。 |
| 0x40 | 16 bits | 0x5001 | ID 01h:Power Management;下一項 0x50。 |
| 0x50 | 16 bits | 0x7000 | ID 00h:Null Capability;下一項 0x70。 |
| 0x70 | 16 bits | 0xD010 | ID 10h:PCI Express Capability;下一項 0xD0。 |
| 0xD0 | 16 bits | 0x0011 | ID 11h:MSI-X;Next 為 0,清單結束。 |
- MSI-X
- Message Signaled Interrupts Extension,表格式訊息中斷
案例推演:入口為 0x40 & 0xFC = 0x40。每次讀取 16 bits 後,以 value & 0xFF 取 ID,以高 8 bits 對應的 (value >> 8) & 0xFC 取得下一項的位置。
0x40 → PM → 0x50 → Null → 0x70 → PCIe → 0xD0 → MSI-X → 結束
在 0x50:ID = 0x7000 & 0xFF = 0
Next = (0x7000 >> 8) & 0xFC = 0x70
在 0x50,Null Capability 的 ID 表示這個節點沒有功能資料,Next 卻仍指向 0x70,所以繼續走到 PCIe 與 MSI-X。完成這條傳統清單後,序號查詢仍應回到延伸清單的獨立入口;兩份清單各自描述所屬能力。
本例的 MSI-X 結構存在,也不代表中斷已啟用。能力的存在、控制位設定及目前是否能使用,仍是不同問題;MSI-X 的設定流程留到中斷章。
本例 ID 與指標的核對位置
PM:§7.5.2.1,Figure 7-18/Table 7-14,p.945。Null:§7.9.27,p.1315。PCIe:§7.5.3.1,Figure 7-22/Table 7-18,p.953。MSI-X:§7.7.2.1,Figure 7-59/Table 7-48,pp.1021–1022;啟用位另見 Table 7-49,p.1022。起始指標低 2 bits 的遮罩規則見 p.926;配置資料採小端序,見 §7.5.1.1,p.916。
4. 要找 Device Serial Number,依序翻哪幾張圖?
- 確認入口
Figure 7-42/§7.6.1:Extended 清單由設定空間 0x100 開始。 - 解開清單 Header
Figure 7-43/Table 7-39:讀 32 bits,分出 ID、Version 與 Next。 - 確認目標與資料位置
Figure 7-242/Table 7-221:DSN 的 ID 為 0003h;Figure 7-241:序號位於結構起點 +0x04、+0x08。
DSN 是 Device Serial Number 的縮寫。這是可選的 Extended Capability,不是每個 Function 都必須提供,也不是每個 Function 各自擁有不同序號。
| Function 內 byte offset | 讀取寬度 | 讀值 | 解讀 |
|---|---|---|---|
| 0x100 | 32 bits | 0x18020001 | AER:ID 0001h、Version 2;下一項 0x180。 |
| 0x180 | 32 bits | 0x00010003 | DSN:ID 0003h、Version 1;Next 為 0。 |
| 0x184 | 32 bits | 0x33221100 | Serial Number Register 的 Lower DW。 |
| 0x188 | 32 bits | 0x77665544 | Serial Number Register 的 Upper DW。 |
- DW
- Double Word,4 bytes的資料單位
header = 0x18020001
ID = header & 0xFFFF = 0x0001
Version = (header >> 16) & 0xF = 2
Next = (header >> 20) & 0xFFC = 0x180
案例推演:從 Header 取出的 Next 已經是 Function 內的 byte offset,因此下一筆直接讀 0x180。DWORD 對齊表示低 2 bits 為 0,無須再乘 4。確認 ID 0003h、Version 1 後,才由目前 DSN 起點加上資料位移,得到 0x180 + 0x04 = 0x184 與 0x180 + 0x08 = 0x188。
兩個 DWORD 拼起來,就是平常書寫的 EUI-64 順序嗎?
先分清楚「Register 整數」與「識別碼的位元組順序」。本例組成的 Register 整數是 (0x77665544 << 32) | 0x33221100 = 0x7766554433221100。Table 7-222 另外規定,Register bits 7:0 對應 EUI bits 63:56,接著依 byte 對映;因此本例按 EUI 的高位元組到低位元組書寫時,是 00-11-22-33-44-55-66-77。
這組數字只示範資料重組,不主張是已配發或可以拿去使用的產品序號。真實 DSN 必須符合 Table 7-222 的 IEEE 公司識別碼與製造商延伸識別碼規則。序號也不能單獨當成身分認證證據。
DSN 的範圍還要讀 §7.9.3:一般多功能 Device 若實作這項能力,Function 0 必須實作;其他有實作的 Function 必須回報相同值。因此,找到相同 DSN 不能用來區分同一個 Device 的 Function 0 與 Function 1;目前的設定對象仍由 Segment 與 BDF(Bus、Device、Function 識別號) 選定。
原文定位與版本條件
清單:§7.6–§7.6.3,Figures 7-42/7-43、Table 7-39,pp.1008–1010。AER Header:§7.8.4.1、Figure 7-154/Table 7-134,p.1112;支援 Flit Mode 時須用 Version 3,本例已排除該情況。DSN:§7.9.3–§7.9.3.2,Figures 7-241–7-243、Tables 7-221/7-222,pp.1205–1207。RCiEP、PF/VF 有另外規則,本例不適用。Table 7-39 允許向前相容的更高 Capability Version,不能把「只接受等於 1」寫成所有版本的通用搜尋規則。
5. 讀到一個欄位,就能把原值寫回去嗎?
讀取欄位定義時,也要看表格的 Attributes(存取屬性)。這一欄說明軟體寫入會觸發什麼行為。能力查詢只需要讀取;若另有修改需求,先按屬性與當前條件組成寫值,避免把查詢所得的狀態直接回寫。
| 屬性 | 讀值與寫入的意義 | 常見誤判 |
|---|---|---|
| RO | 軟體不能改寫;若欄位明確反映硬體狀態,值仍可能隨執行狀態改變。 | 唯讀不等於永遠不變。 |
| RW | 軟體可設定或清除,仍須遵守該欄位的額外條件。 | 可寫不代表任何時刻、任何值都合法。 |
| RW1C | 讀取狀態;寫 1 清除對應狀態,寫 0 沒有效果。 | 把讀值原樣寫回,可能清掉原本想保留的事件。 |
| RsvdP | 保留且保存。此版本讀為 0,寫入時軟體必須保存讀到的值。 | 不能自行借來存資料。 |
| RsvdZ | 保留且寫零。此版本讀為 0,寫入時軟體必須使用 0。 | 不能對所有 Reserved 都套相同的讀改寫方式。 |
規格依據
Base 6.0 §7.4,Table 7-2,pp.913–915;本表取 RO、RW、RW1C(寫入一才清除對應狀態)、RsvdP(寫入時須保存讀值的保留欄位)、RsvdZ(寫入時須為零的保留欄位) 的語義。HwInit 與 Sticky 類型另有初始化和 Reset 條件,留到相關章節使用,不把未列在此表的類型視為等同 RW。
6. 找不到時,怎麼分清「不存在」與「還不知道」?
| 實際取得的證據 | 可以怎麼記錄? | 仍不能推論什麼? |
|---|---|---|
| 在正確清單中找到目標 ID,且已核對版本與類型。 | 此 Function 暴露該 Capability;可繼續讀其定義欄位。 | 不能直接宣告功能已啟用、工作已完成。 |
| 成功走完適用的清單,Next 為 0,沒有找到可選的目標。 | 這份有效清單沒有暴露目標 Capability。 | 不能因此宣告整張卡、其他 Function 都不支援。 |
| 有效讀取 0x100 得 0x00000000。 | 依 §7.6.1,這個 Function 沒有 Extended Capability。 | 不能把同樣規則套到傳統清單的 Null ID。 |
| 存取介面不支援延伸區,或這次讀取失敗。 | 尚未取得可用的查詢結果。 | 不能拿失敗後的 buffer 當成「支援位元全為 0」。 |
| 指標循環、超出範圍,或資料與必要結構矛盾。 | 清單無法可靠解析,保留異常位置與讀值。 | 不能假裝正常走到結尾。 |
最後一列整理教材採用的解析檢查:記下走過的 offset,檢查位置範圍與對齊,並辨認是否重訪同一節點。清單位置可以往前或往後;重訪才是循環檢查的依據。遇到無法可靠解析的資料時,保留異常位置與讀值,再釐清原因。
同樣地,成功讀到 0 不保證那裡是一個有意義的欄位。Base 6.0 §7.3.3(p.913)規定,在沒有其他需回報錯誤的情況下,對未實作 Register 的設定讀取成功回傳 0。位置與格式必須先由標頭、Capability 或明確的 Register 定義建立,不能靠讀值看起來合理來猜。
7. 串接一次完整的序號查詢
回到完整序號查詢:先選定 0000:03:00.0,從 0x100 進入延伸清單,沿 Next 找到 0x180 的 DSN,再讀 0x184 與 0x188。最後按序號定義重組位元組,並保留它在多功能 Device 中的共用範圍。以下延伸說明分別改動指標、資料位置與屬性。
讀到 0x50 的值是 0x7000,下一步是停止、讀 0x70,還是讀 0xC0?
讀 0x70。ID 0 是傳統 Null Capability,Next 0x70 從設定空間起點計算。0xC0 是把目前位置錯加上 Next 的結果。(Figure 7-384/Table 7-336,p.1315;各 Next Pointer 的定義見清單來源。)
Extended Header 改成 0x24010003,DSN 資料要到 0x244 讀嗎?
先問這個 Header 是在哪裡讀到的。若仍在 0x180,ID 0003h 代表目前這一項就是 DSN,資料仍在 0x184 與 0x188;0x240 是下一項的位置。只有目前結構真的位於 0x240,Lower DW 才在 0x244。(Figures 7-241/7-243,pp.1205–1206;Table 7-39,p.1010。)
同一個 Device 的兩個 Function 回報相同 DSN,是規格違反嗎?
不是。本章的一般多功能 Device,其他有實作 DSN 的 Function 必須回報與 Function 0 相同的值。DSN 不能拿來代替 BDF 的 Function 部分。(§7.9.3,p.1205。)
某個狀態是 RO,兩次讀值不同,就代表裝置壞了嗎?
不能這樣判定。先查欄位是否明確反映會變動的硬體狀態。RO 限制的是軟體改寫,並不禁止硬體依定義更新狀態。(Table 7-2,p.914。)
8. 查詢入口本身是怎麼找到的?
本章從一個已知存在的 Function 開始。接著的 Chapter 3 會往前追問:系統還不知道有哪些 Bus 和 Function 時,如何安排搜尋路徑?原本尚未配置的 Bridge,又如何逐步成為可查詢的下游入口?
版本與來源
本章以使用者提供的 PCI Express Base Specification Revision 6.0(6.0-1.0-PUB)為依據。各節附精確圖表與頁碼;所有讀值、拓樸位置與解析檢查均已區分為教學假設或作者的檢查方法。查核日期:2026-10-28。原始 PDF 不隨教材散布。