驅動程式會讀取及寫入裝置記憶體中的位元和位元組,與系統中的裝置通訊。在 Fuchsia 中,驅動程式庫會執行下列動作,設定裝置記憶體的存取權:
圖表 1。程序會將虛擬記憶體物件 (VMO) 對應至本身的虛擬記憶體位址區域 (VMAR),藉此存取 VMO 代表的記憶體區域。
從驅動程式庫存取裝置的記憶體
在 Fuchsia 中,驅動程式庫會取得代表系統中裝置記憶體區域的虛擬記憶體物件 (VMO),藉此取得讀取及寫入裝置記憶體中資料的能力。
與一般由 DRAM 支援的程序記憶體不同,裝置的記憶體區域是由暫存器支援。因此,裝置的 VMO 代表指向這些暫存器的記憶體對應 I/O (MMIO) 區域。當驅動程式庫從這個區域讀取或寫入資料時,效果與直接從裝置的暫存器讀取或寫入資料相同。
根匯流排驅動程式 (例如平台、PCI 或 ACPI 匯流排驅動程式) 可感知連線至匯流排的所有裝置,並具備為系統中的裝置建立 VMO 的特殊能力。建立後,這些 VMO 即可傳遞至其他驅動程式。然後,驅動程式會使用 VMO 存取目標裝置的記憶體對應 I/O 區域。
以下序列逐步說明可讓驅動程式庫存取裝置記憶體的事件:
- 驅動程式管理器會探索裝置,並將驅動程式庫繫結至該裝置。
- 驅動程式會要求為裝置產生 VMO。
- 根匯流排驅動程式會叫用 syscall,為裝置建立 VMO。
- Zircon 核心會建立 VMO,代表裝置的記憶體區域。
- 根匯流排驅動程式會接收 VMO,並將其傳遞至驅動程式庫。
- 驅動程式會將 VMO 對應至驅動程式代管程序中的虛擬記憶體位址區域 (VMAR)。
- 驅動程式會在驅動程式庫主機的對應位址空間中讀取及寫入資料,與裝置通訊。
為裝置產生 VMO
Fuchsia 提供下列 (但不限於) 方法,可擷取代表裝置記憶體的 VMO:
- PCI FIDL 通訊協定提供
GetBar(),可從裝置擷取基本區域暫存器 (BAR)。 - ACPI FIDL 通訊協定提供
GetMmio(),用於擷取裝置的記憶體區域。 - 平台裝置 FIDL 通訊協定提供
GetMmio(),可擷取裝置的記憶體區域。
驅動程式庫取得裝置的 VMO 後,會將 VMO 對應至驅動程式代管程序中虛擬位址空間的某個區域。驅動程式庫必須完成這項設定,才能在裝置的記憶體中讀取及寫入資料 (請參閱「在驅動程式中將 VMO 對應至 VMAR」)。
雖然圖 1 似乎顯示每個裝置都有一個 VMO,但裝置的實體記憶體中可能有多個記憶體區域。在這種情況下,裝置可能需要產生多個 VMO,分別代表這些記憶體區域。
實體記憶體中的裝置 VMO
一般來說,VMO 代表虛擬記憶體的連續區域。但如果是裝置,VMO 的建立方式與其他一般 VMO 不同。裝置的 VMO 由實體頁面支援,這些頁面涵蓋系統實體記憶體中的連續區域。
如要建立這類 VMO,匯流排驅動程式必須具備特殊能力,並叫用 zx_vmo_create_physical syscall,向 Zircon 核心提供裝置記憶體區域的實體位址和大小。核心接著會傳回 VMO,該 VMO 由系統記憶體中連續實體頁面的叢集支援。
裝置的位址空間配置
在 Fuchsia 系統中,裝置的位址空間區域會透過下列其中一種方式決定:
但 USB 裝置永遠不會收到位址空間區域。換句話說,USB 裝置熱插拔至 Fuchsia 系統時,系統一律不會為這些裝置產生 VMO。而是由 USB 控制器驅動程式庫取得所有 USB 裝置的記憶體對應資源。USB 裝置的驅動程式會使用 FIDL 協定與 USB 控制器驅動程式庫通訊,而 USB 控制器驅動程式庫隨後會將這些互動轉換為自身記憶體對應位址空間中的讀取和寫入作業。
對於也允許熱插拔的 PCI 裝置,系統會預先為所有可能熱插拔的 PCI 裝置分配特定位址空間區域。這個位址空間的子區段會分配給繫結至熱插拔 PCI 裝置的驅動程式。PCI 控制器驅動程式有責任為驅動程式提供這個位址空間的正確區域。
在驅動程式庫中將 VMO 對應至 VMAR
VMAR (虛擬記憶體位址區域) 代表程序中虛擬位址空間的連續區域。在 Fuchsia 中,程序通常會將 VMO (代表系統中連續的虛擬記憶體區域) 對應至 VMAR,方便在 VMO 代表的記憶體區域中讀取及寫入資料。
如果沒有對應至 VMAR,程序只能使用一組系統呼叫 (例如 zx_vmo_read 和 zx_vmo_write) 與 VMO 互動。這是因為所有記憶體都會對應至核心的位址空間,而且只有系統呼叫可以切換至核心模式,直接從記憶體讀取或寫入資料。
驅動程式不得使用這些系統呼叫與裝置記憶體 VMO 互動,且必須將代表裝置記憶體區域的 VMO 對應至驅動程式代管程序 (驅動程式庫所在的程序) 中的 VMAR。由於下列原因,驅動程式不得使用系統呼叫與裝置的記憶體互動:
- 暫存器對應方式相關問題 (請參閱「已快取和未快取的暫存器」)。
- 可安全用於與暫存器互動的指令類型限制。
如果單一驅動程式代管程序有多個驅動程式,則同一驅動程式代管程序中的所有驅動程式會共用相同的根 VMAR。
用於與裝置記憶體互動的輔助程式庫
Fuchsia 提供輔助程式庫 (請參閱 lib/mmio),可抽象化處理 VMO 和 VMAR 的詳細資料。這個輔助程式庫提供的抽象化功能,可確保裝置上的暫存器讀取和寫入作業安全無虞。舉例來說,由於系統中與記憶體互動的每項指令都不安全,因此輔助程式庫含有內嵌組語指令,可確保在暫存器中讀取和寫入資料時的正確性。
已快取和未快取的暫存器
在 Fuchsia 中,最好以快取一致的方式對應暫存器。在 x64 上,周邊記憶體一律為快取一致性,因此可對應為快取。不過,在 ARM 上,周邊記憶體並非快取一致,因此通常會對應為未快取。
Fuchsia 允許使用替代方式對應暫存器,以及手動管理這些暫存器的快取一致性。不過,只有在使用未快取對應時遇到效能問題的進階開發人員,才應考慮採用這種做法。