iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0
自我挑戰組

Linux Kernel 網路巡禮系列 第 25

MMIO 與 PMIO 的建立與管理

  • 分享至 

  • xImage
  •  

今天是介紹 PCI(e) 部分的最後一篇,我們將深入探討 MMIO(Memory-Mapped I/O)和 PMIO(Port-Mapped I/O)的建立與管理過程。

Base Address Registers (BARs)

昨天我們談到,PCI(e) 設備的 Configuration Space Header 保存了該設備的基本資訊和設置。而其中的 Base Address Registers (BARs),就是今天要討論的重點。

https://ithelp.ithome.com.tw/upload/images/20241009/20152703562GbX0Z4W.png

BARs 是一系列 32 bits 的暫存器,用來管理 PCI 設備的記憶體映射。不論是透過 MMIO 或是 PMIO,都是將 PCI 設備的記憶體區塊映射到物理記憶體空間(Physical Address Space)或 I/O 空間(I/O Space)。

設定 BAR 的過程

https://ithelp.ithome.com.tw/upload/images/20241009/201527039F3vf33iuD.png

在系統初始化時,作業系統會向 Base Address Register 寫入 0xFFFFFFFF,然後讀取該暫存器,這時 PCI 設備會返回所需的映射空間大小,並告知是使用 I/O Space 還是 Memory Space。

BAR 的 bit 0 會指示該設備是使用 I/O Space 或 Memory Space。如果是使用 Memory Space,因為該空間較大,可以允許映射到 64 位元的定址範圍,因此 bit 2:1 會指示該 BAR 是 32 位元還是 64 位元的暫存器。

接下來,從 BAR 的欄位可以計算出該設備所需的記憶體大小。以下是計算過程:

  1. 將 bit 3:0(如果是 I/O 則是 bit 1:0)歸零。
  2. 將整個 32 位元(如果是 64 位元模式則計算 64 位元暫存器)進行邏輯反運算(Logical Not)。
  3. 加 1。
    就可得到需要的地址。

經過上述計算,就能得到設備所需的地址大小。例如,某個設備需要 1MB 的 MMIO 記憶體,BAR 讀取出來的數值會是 0xFFF00000。因為使用的是 MMIO,所以 bit 3:0 歸零後不變。邏輯反運算後,~0xFFF00000 = 0x000FFFFF,加 1 得到 0x00100000,也就是 1MB。

使用 lspci 查看 BAR 設定

透過 lspci 指令,我們可以檢視 PCI 設備的映射區域資訊:

> lspci -s 07:00.0 -vvv
07:00.0 Ethernet controller: Intel Corporation Ethernet Controller I225-V (rev 03)
        Subsystem: ASUSTeK Computer Inc. Ethernet Controller I225-V
        Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 19
        IOMMU group: 20
        Region 0: Memory at 86500000 (32-bit, non-prefetchable) [size=1M]
        Region 3: Memory at 86600000 (32-bit, non-prefetchable) [size=16K]
        Capabilities: [40] Power Management version 3

在這裡,我們可以看到該設備有兩個 MMIO 映射區,分別大小為 1MB 和 16KB,並且映射地址分別為 0x865000000x86600000

讀取 Configuration Space Header

透過額外的參數,我們可以直接讀取 Configuration Space Header 的數據:

lspci -s 07:00.0 -Qkxxxxnnv
07:00.0 Ethernet controller [0200]: Intel Corporation Ethernet Controller I225-V [8086:15f3] (rev 03)
        Subsystem: ASUSTeK Computer Inc. Device [1043:87d2]
        Flags: bus master, fast devsel, latency 0, IRQ 19, IOMMU group 20
        Memory at 86500000 (32-bit, non-prefetchable) [size=1M]
        Memory at 86600000 (32-bit, non-prefetchable) [size=16K]
        ...
00: 86 80 f3 15 06 04 10 00 03 00 00 02 10 00 00 00
10: 00 00 50 86 00 00 00 00 00 00 00 00 00 00 60 86
....

對照 Configuration Space Header 的欄位,我們可以看到 Bar 0 的數值是 00 00 50 86,正好對應 Region 0 的映射地址 0x86500000。同樣地,Bar 300 00 60 86,剛好對應 Region 3 的映射地址`0x86600000。

今天我們了解了如何建透過 BARs 管理 PCIe 設備的映射,接著我們將會回到驅動層來探索。


上一篇
PCI Configuration Space
下一篇
Network Device 與 Socket Buffer
系列文
Linux Kernel 網路巡禮30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言