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