RFC-0270:Zircon 虛擬中斷信號

RFC-0270:Zircon 虛擬中斷信號
狀態已接受
區域
  • 核心
說明

為虛擬中斷物件提出新的信號。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2025-04-02
審查日期 (年-月-日)2025-04-16

問題陳述

我們需要更佳的方式來解調共用中斷,並管理虛擬中斷的已確認/未確認狀態。詳情請參閱下方的「擴充問題陳述」一節。

摘要

這份 RFC 建議在虛擬中斷物件中新增 Zircon 信號,當虛擬中斷物件處於「未觸發」狀態時,這些信號會持續提出。

背景

實體和虛擬中斷

Zircon 中斷物件有兩種型別:實體中斷和虛擬中斷。

實體中斷物件在邏輯上代表透過系統中斷控制器傳送的中斷信號,有時會透過 PCIe 匯流排傳送,有時則會透過平台或 SoC 專屬路由直接傳送至控制器。相反地,虛擬中斷物件不會直接代表來自非 CPU 硬體的信號。相反地,虛擬中斷是由程式建立,以便看起來像是實體中斷,但只有在軟體對物件呼叫 zx_interrupt_trigger 時,才能發出信號。

自訂等候介面

中斷物件目前不會使用標準 Zircon 訊號系統,以便通知用戶端已收到中斷。雖然這些事件可以繫結至通訊埠,並在收到 IRQ 時傳送通訊埠封包,且可用於在收到 IRQ 前封鎖執行緒,但不會使用標準 zx_object_wait_one/zx_object_wait_manyzx_object_wait_async 系統呼叫來達成這項行為。相反地,如果使用者想接收 port 封包,就必須使用 zx_interrupt_bind 將中斷物件繫結至 port 物件,如果想封鎖執行緒,則必須使用 zx_interrupt_wait。一次只能在中斷物件上等候一個邏輯等待作業,系統不支援任意數量的等待作業。一旦執行緒解除封鎖或傳送了埠封包,就必須「確認」中斷,才能再次傳送信號。

當使用者透過 zx_interrupt_wait 等待中斷時,如果使用者的執行緒下次再次呼叫 zx_interrupt_wait 時阻斷中斷,中斷就會變成已確認。當使用者透過 zx_interrupt_bind 將中斷事件繫結至通訊埠時,他們可以在中斷事件物件上呼叫 zx_interrupt_ack,藉此確認中斷事件,並允許傳送新的通訊埠封包。

雖然這個非標準的訊號介面並非最理想的解決方案,但我們希望設計出可與標準 Zircon 訊號機制相容的新介面 (除瞭解決其他問題點)。完整重新設計 Zircon 中斷 API 並轉換至新系統是一項複雜的任務,可能需要大量時間和精力,且超出這項提案的範圍。

虛擬中斷的目的

虛擬中斷在 Fuchsia 中主要有兩個用途,兩者都源自相同的動機。這些是測試和解調。

由於驅動程式需要使用中斷物件使用的特殊等待介面,因此很難輕鬆將不同的核心物件 (可能是事件) 替換為中斷物件,並讓驅動程式庫程式碼「正常運作」。在撰寫驅動程式庫測試時,如果測試環境想要模擬硬體,就會發生這個問題。沒有任何可提供給驅動程式庫的物理中斷,即使有,在任何特定測試中控制這類中斷也可能很困難,且非常依賴目標。

相反地,測試可以使用虛擬中斷物件。從驅動程式庫程式使用者的角度來看,這些驅動程式使用相同的 API,且基本上無法區分,因此無需任何特殊情況程式碼即可測試程式碼,這類程式碼可辨別測試環境和實際環境之間的差異。

當需要解調個別中斷時,也會發生類似的情況。請考慮外部晶片的驅動程式庫,該驅動程式需要發出中斷。我們希望外部晶片有單一驅動程式庫,不受特定產品中用於外部晶片的特定 SoC 影響。晶片可能會有與 SoC 連線的 IRQ 訊號。在某些 SoC 設計中,這個 IRQ 訊號可能會直接路由至 SoC 的中斷控制器,這表示可以在初始化期間例項化專屬的實體中斷,並將其傳遞至驅動程式庫。如果管理中斷只需要與系統的中斷控制器互動,核心可以直接透過物理中斷物件管理 IRQ。

另一方面,其他設計可能會將這個中斷連結至 GPIO,做為中斷區塊的一部分 (通常為 16 或 32 個區塊)。當區塊中設為中斷的任何 GPIO 收到信號時,GPIO 硬體的實體中斷會觸發。接著,GPIO 驅動程式庫可以喚醒並找出哪個 GPIO 中斷已觸發,並遮罩中斷,直到可以處理為止。不過,它仍需要向中斷的驅動程式庫發出信號。我們不希望 IRQ 使用者驅動程式庫程式需要瞭解這些情況的差異,也不希望不同的外部晶片需要在同一個程序中使用多個驅動程式,只因主機板設計將多個中斷事件路由至同一個 GPIO 區塊。因此,在這種情況下,GPIO 驅動程式庫可為每個 GPIO 建立虛擬中斷物件,並將其設為共用硬體中的中斷,有效地將共用相同實體中斷的多個中斷進行多工處理,且不需要驅動程式庫具備用來以不同方式處理這兩種情況的程式碼。

問題陳述內容

不過,這種做法目前有實際問題。請考慮 GPIO 解調情境。有多個 GPIO 中斷共用相同的硬體區塊,且驅動程式庫已為每個區塊建立及發布一個虛擬中斷。當其中一個中斷觸發時,GPIO 會透過區塊的共用實體中斷發出訊號。GPIO 驅動程式庫接著可以使用 SoC 專屬 GPIO 硬體遮罩特定位元,並zx_interrupt_trigger相關聯的虛擬中斷。由於所有待處理的 GPIO 中斷都已發出信號,因此可以確認自身的物理中斷,並返回等待新的中斷。

在驅動程式庫/使用者端,中斷處理常式會喚醒,中斷會受到服務,最後會收到確認。此時,GPIO 驅動程式庫需要採取行動。具體來說,它需要喚醒,並在 GPIO 區塊中解除遮罩/重新啟用特定位元,才能發出任何新中斷信號。

不過,目前沒有任何好方法可以做到這點。從用戶端驅動程式庫到 GPIO 驅動程式庫,不會透過中斷物件傳送任何信號,但如果沒有這種信號,GPIO 驅動程式庫就無法得知何時可以安全地取消遮罩並重新啟用中斷。

您可以引入其他物件或建立通訊協定,以提供這類信號,但這會要求中斷事件的使用者知道這是虛擬中斷事件,而非實體中斷事件,這會破壞讓這兩種情況有效區分的目標。

相關人員

講師:cpu@google.com

審查者: + 'maniscalco@google.com' + 'bradenkell@google.com' + 'rudymathu@google.com' + 'cpu@google.com'

諮詢:

Zircon 驅動程式庫架構團隊。

社會化:

我們已將這份提案 (以 Google 文件形式) 與 Zircon 團隊分享。

需求條件

使用中斷物件的「下游」驅動程式必須不理會該物件是否為虛擬物件。

設計

中斷物件和標準 Zircon 信號

如前所述,Zircon 中斷物件目前不會使用標準 Zircon 訊號系統,以便從硬體發出中斷要求訊號。這並不表示他們完全不參與標準訊號系統。使用者可以自由發布異步等待作業來中斷物件,或使用 zx_object_wait_one/zx_object_wait_many 封鎖這些物件的執行緒。不過,只有在等待幾乎所有 Zircon 物件上存在的 8 個「使用者信號」其中之一,且軟體聲明該信號時,這些等待作業才會滿足。目前未定義任何「系統信號」,可用於中斷物件,讓核心發出信號。

ZX_VIRTUAL_INTERRUPT_UNTRIGGERED

因此,我們來引入一個新的信號 (稱為 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED),並只用於虛擬中斷。以下是信號的基本屬性:

  1. 虛擬中斷物件在建立後不會立即觸發,因此系統會在任何新建立的虛擬中斷物件上斷言此信號。
  2. 當使用者在虛擬中斷物件上呼叫 zx_interrupt_trigger 時,物件會進入觸發狀態,且信號會取消斷言。
  3. 當使用者確認已觸發虛擬中斷物件時,物件會進入未觸發狀態,並確認信號。

實際使用範例

請考慮使用物理中斷 I 的 GPIO 驅動程式庫,並在同一個 GPIO 區塊中公開三個虛擬中斷 ABC

  1. 在啟動時,驅動程式庫會建立並分發 ABC,然後將 I 繫結至通訊埠 P
  2. 它也會建立專屬的 IRQ 執行緒 (T)、設定適當的設定檔,然後在 P 中封鎖 T,等待封包。
  3. I 會觸發將封包傳送至 P 的動作,並在過程中解除 T 的封鎖。
  4. T 會檢查 GPIO 狀態,並發現與 AC 相關聯的 GPIO 已提出。
  5. T 會在 AC 上呼叫 zx_interrupt_trigger
  6. AC 進入觸發狀態,並在過程中清除 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED
  7. T 會在 AC 上呼叫 zx_object_async_wait,將它們與其連接埠建立關聯,並等待 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 在虛擬中斷物件上變成斷言。
  8. T 會遮蔽與 AC 相關聯的 GPIO。
  9. T 會在 I 上呼叫 zx_interrupt_ack,然後再次阻斷通訊埠,等待新的封包。
  10. 在某個時間點,使用 C 的驅動程式庫會喚醒,處理中斷,然後在其句柄上呼叫 zx_interrupt_ackC,宣稱 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 為副作用。
  11. 等待 C 未觸發信號的非同步等待作業已滿足,因此系統會產生並傳送至 P 的 port 封包,並解除封鎖 T
  12. T 喚醒後,發現 C 已「未觸發」,因此會使用硬體專屬的暫存器,解除遮罩並重新啟用與 C 相關聯的 GPIO 中斷。
  13. T 只會返回等待其連接埠。當 I 再次變為有效,或是 AZX_VIRTUAL_INTERRUPT_UNTRIGGERED 信號變為有效時,我們就會收到端口封包。目前您無須採取進一步行動。

確認待處理的中斷

對於某些中斷物件,系統可能會觸發中斷,並在確認時有第二個 IRQ 待處理。雖然這類情況最常發生在 MSI 中斷時,但只要在用戶端管理中斷服務之前,連續兩次呼叫觸發事件,就能使用虛擬中斷物件產生這種情況。

當使用者確認有其他 IRQ 待處理的中斷時,中斷物件會立即有效觸發。透過 zx_interrupt_wait 回應的執行緒會立即解除封鎖。透過 zx_interrupt_ack 回報的執行緒會立即產生新的連接埠封包。

UNTRIGGERED 信號會發生什麼事?由於中斷在邏輯上未觸發,然後立即重新觸發,因此信號的行為應為閃爍行為。也就是說,目前等待 UNTRIGGERED 信號的任何執行緒都應解除封鎖,而目前發布的任何非同步等待作業都應滿足條件並產生 port 封包。不過,在確認作業後立即發出的訊號狀態會解除。

實作

實作這個做法應該會很簡單,且風險較低。目前,核心程式碼有兩個中斷物件調度器,分別是 InterruptDispatcherVirtualInterruptDispatcher,其中第二個是第一個的子類別。雖然這兩者共用許多程式碼,但成為信號的路徑是不同的。InterruptDispatcher 會透過 InterruptHandler 方法在硬體 IRQ 時間點發出信號,而虛擬中斷會透過 Trigger 方法在 zx_interrupt_triggered 時間點發出信號。在 InterruptDispatcher 上呼叫 Trigger 是違法的,這麼做會導致 BAD_STATE 錯誤。因此,觸發是只在虛擬中斷物件上執行的作業,且一律是在系統呼叫內容中執行,因為在該內容中,您可以合法取得用於操控物件信號狀態所需的鎖定。

系統會在下次呼叫 zx_interrupt_wait (針對非連結埠中斷) 或呼叫 zx_interrupt_ack (針對連結埠中斷) 時,確認中斷。同樣地,與 zx_interrupt_trigger 一樣,呼叫會在允許信號操控的系統呼叫情境中進行。

最後,中斷會在最後一個句柄關閉或執行緒呼叫 zx_interrupt_destroy 時遭到刪除。同樣地,所有這些都會在可取得核心互斥鎖並斷言使用者信號的情況下發生,因此在明確銷毀物件時,您可以輕鬆斷言未觸發的信號 (解除封鎖任何等待者)。

因此,實作這項功能時,只要在觸發、回應、等待和銷毀這四個作業期間,將 VirtualInterruptDispatcher 的行為超載即可。超載版本可能會在執行作業前取得調度器鎖定,並在作業結束時視需要更新信號狀態。

就這樣。UpdateState 和現有的標準 Zircon 信號機制已負責處理所有複雜的繁重工作,包括解除封鎖執行緒和傳送埠封包。實體中斷物件不會公開信號,也不會使用任何虛擬調度器程式碼,因此無須將任何信號狀態與在硬體 IRQ 時間執行的作業同步。

人體工學

這項功能的人體工學設計應簡單易用,您不必對現有的中斷事件使用者進行任何變更,因為 ack 信號行為完全自動化。虛擬中斷產生器只需使用現有的完善信號處理模式,即可使用信號。

安全性考量

新增這項功能後,系統便可有效地在中斷事件消費者和中斷事件產生者之間建立新的通訊管道,讓產生者知道消費者何時已確認虛擬中斷事件。這是多重中斷系統運作所需的部分條件,不會被視為獨立或不受歡迎的側邊管道,因此不構成安全性風險。

隱私權注意事項

這項功能不會處理任何使用者資料或其他可能的機密資訊,因此沒有需要處理的隱私權考量。

測試

測試應是現有單元測試的簡單延伸。我們基本上需要新增測試,確保:

  1. 建立虛擬中斷物件時,系統會一開始就提出 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 信號。
  2. 系統會在回應對 zx_interrupt_trigger 的呼叫時清除信號。
  3. 系統會在回應對 zx_interrupt_ack 的呼叫時設定信號。
  4. 在存在其他待處理 IRQ 的情況下,信號會在收到確認時正確實作「strobe」行為。

說明文件

虛擬中斷物件的說明文件將更新,以說明新信號、指出該信號僅用於虛擬中斷物件,並概述上述行為規則 (最初斷言、觸發時清除、在 ack 時設定、在待處理 ack 時閃爍)。

缺點、替代方案和未知事項

這種做法沒有已知的重大缺點。符合使用者需求。實作和測試應簡單且風險低。

Zircon 驅動程式庫程式團隊討論了許多替代方案,但都存在相同的缺點。虛擬中斷的驅動程式取用者必須明確知道自己正在使用虛擬中斷,然後明確參與某些使用者層級定義的通訊協定,向中斷產生者傳送確認信號。

雖然所有這些方法都可行,但似乎都不理想。這會為驅動程式庫程式作者帶來重大額外負擔,因為他們必須參與使用虛擬中斷時所定義的任何通訊協定,並在使用實體中斷時採取不同的行為。此外,現有的驅動程式群組也需要更新,才能使用新通訊協定,如果核心以透明方式處理 ACK 信號,則可完全略過這項作業。

無論實作哪種通訊協定,都會完全在使用者模式中實作,因此必須仔細考量可能來自惡意人士的信任問題。讓 Zircon 核心調解信號機制,有助於簡化這項分析。

最後,Zircon 中斷的使用者已經必須確認中斷 (隱含或明確)。很難想像,任何額外的非頻道 ACK 通訊協定,在執行現有 ACK 時,是否能像操控核心物件信號位元一樣有效率。