在驅動程式庫中對應裝置的記憶體

驅動程式會透過讀取及寫入裝置記憶體中的位元和位元組,與系統中的裝置通訊。在 Fuchsia 中,驅動程式庫會執行下列動作來設定裝置記憶體的存取權:

alt_text

圖 1. 程序會將虛擬記憶體物件 (VMO) 對應至專屬的虛擬記憶體位址區域 (VMAR),藉此存取 VMO 所代表的記憶體區域。

從驅動程式庫存取裝置記憶體

在 Fuchsia 中,驅動程式庫取得代表裝置記憶體區域的虛擬記憶體物件 (VMO),藉此在裝置記憶體中讀取及寫入資料。

與程序記憶體 (DRAM 通常支援) 不同,裝置的記憶體區域是由註冊系統支援。因此,裝置的 VMO 代表指向這些註冊器的記憶體對應的 I/O (MMIO) 區域。當驅動程式庫從該區域讀取或寫入時,效果與直接讀取或寫入裝置的暫存器相同。

根匯流排驅動程式 (例如平台、PCI 或 ACPI 匯流排驅動程式) 會知道所有連接到匯流排的裝置,並且具有為系統中的裝置建立 VMO 的特殊能力。建立完成後,即可將這些 VMO 傳遞給其他驅動程式。然後驅動程式會使用 VMO 存取目標裝置的記憶體對應的 I/O 區域。

以下為可讓驅動程式庫存取裝置記憶體的事件:

  1. 驅動程式管理員會找出裝置,並將驅動程式庫繫結至該裝置。
  2. 驅動程式會向裝置產生 VMO
  3. 根匯流排驅動程式會叫用 syscall 為裝置建立 VMO。
  4. Zircon 核心會建立 VMO,代表裝置的記憶體區域。
  5. 根匯流排驅動程式會接收 VMO 並傳遞至驅動程式庫。
  6. 驅動程式會將 VMO 對應驅動程式主機中的虛擬記憶體位址區域 (VMAR)。
  7. 驅動程式會在驅動程式庫程式主機的對應位址空間中讀取及寫入資料,以便與裝置通訊。

為裝置產生 VMO

Fuchsia 提供下列 (但不限於) 方法,可用於擷取代表裝置記憶體的 VMO:

  • PCI FIDL 通訊協定提供 GetBar(),以便從裝置擷取基本區域登錄 (BAR)。
  • ACPI FIDL 通訊協定提供 GetMmio(),用於擷取裝置的記憶體區域。
  • 平台裝置通訊協定 (以 Banjo 為基礎) 提供 GetMmio(),用於擷取裝置的記憶體區域。

驅動程式庫取得裝置的 VMO 後,驅動程式庫會將 VMO 對應至驅動程式代管程序中虛擬位址空間的區域。驅動程式庫必須進行這項設定,才能在裝置的記憶體中讀取及寫入資料 (請參閱將 VMO 對應至驅動程式中的 VMAR)。

雖然圖 1 似乎顯示每部裝置都有一個 VMO,但裝置在實體記憶體中可以有多個記憶體區域。在這種情況下,裝置可能需要產生多個 VMO 來分別代表這些記憶體區域。

裝置在實體記憶體中的 VMO

一般而言,VMO 代表虛擬記憶體的連續區域。但是,針對裝置,VMO 的建立方式與其他一般 VMO 不同。裝置的 VMO 由系統實體記憶體中的連續區域所支援的實體頁面。

如要建立這個 VMO,具有特殊能力的匯流排驅動程式,請叫用 zx_vmo_create_physical 系統呼叫,並為 Zircon 核心提供裝置記憶體區域的實際位址和大小。核心之後,核心會傳回由系統記憶體中連續實體頁面的叢集支援的 VMO。

分配裝置的位址空間

在 Fuchsia 系統中,裝置的位址空間可透過下列其中一種方式決定:

不過 USB 裝置並不會收到位址空間的區域。換句話說,當 USB 裝置熱插插入 Fuchsia 系統時,就不會為 USB 裝置產生 VMO。而是會保存所有 USB 裝置的記憶體對應資源。USB 裝置的驅動程式會使用 FIDL 通訊協定與 USB 控制器驅動程式庫進行通訊,而 USB 控制器驅動程式庫會將這些互動轉換為其專屬記憶體對應位址空間中的讀取和寫入作業。

如果 PCI 裝置也允許熱插拔,系統就會在系統中預先分配位址空間的特定區域,供所有可能使用熱接的 PCI 裝置進行預先分配。這個位址空間的子區段會發布給繫結到熱插式 PCI 裝置的驅動程式。此外,PCI 控制器驅動程式應負責為駕駛人提供這個位址空間的正確區域。

將 VMO 對應至驅動程式庫中的 VMAR

VMAR (虛擬記憶體位址區域) 代表程序中虛擬位址空間的連續區域。在 Fuchsia 中,程序通常會將 VMO (代表系統中虛擬記憶體的連續區域) 對應至 VMAR,以便讀取和寫入 VMO 所代表記憶體區域中的資料。

如果沒有對應至 VMAR,程序就只能使用一組系統呼叫 (例如 zx_vmo_readzx_vmo_write) 與 VMO 互動。這是因為所有記憶體都會對應至核心的位址空間,且只有系統呼叫可以切換至核心模式,以便直接讀取或寫入記憶體。

驅動程式不得使用這些系統呼叫與裝置記憶體 VMO 互動,並且必須將代表裝置記憶體區域的 VMO 對應至驅動程式主機 (也就是驅動程式庫所在的程序) 中的 VMAR。驅動程式不得使用系統呼叫與裝置記憶體互動,原因如下:

  • 註冊器的對應方式相關問題 (請參閱「快取和未快取的註冊」一節)。
  • 限制與登錄互動安全使用的操作說明類型限制。

如果單一驅動程式代管程序有多個驅動程式,同一個驅動程式代管程序中的所有驅動程式都會共用相同的根 VMAR

用於與裝置記憶體互動的輔助程式庫

Fuchsia 提供輔助程式庫 (請參閱 lib/mmio),可抽象化使用 VMO 和 VMAR 的詳細資料。這個輔助程式庫提供的抽象化機制可確保讀取和寫入裝置上的註冊資料安全無虞。舉例來說,由於並非所有與系統中記憶體互動的指令都視為安全,輔助程式庫也包含內嵌組譯指示,以確保在註冊器中讀取和寫入資料時正確無誤。

快取和未快取的註冊

在 Fuchsia 中,建議使用快取一致性註冊對應。在 x64 上,週邊記憶體一律為連續快取,因此可以對應為快取。不過,在 ARM 中,週邊記憶體不是共置快取,因此通常會對應為未快取。

Fuchsia 允許使用替代方法註冊對應,以及手動管理這些暫存器的快取一致性。不過,只有在使用未快取對應時遇到效能問題的進階開發人員,才應考慮採用這個方法。