中斷

名稱

中斷 - 使用者模式 I/O 中斷提交

SYNOPSIS

中斷物件可讓使用者空間建立、發出信號,以及等待硬體中斷。

說明

中斷物件是驅動程式通常用來接收待處理中斷要求 (IRQ) 通知的物件,這些通知通常是由硬體單元產生。中斷有兩種主要類型:實體和虛擬,且與其他 Zircon 核心物件略有不同,因為它們會透過一組特殊的核心系統呼叫,而非依賴標準信號機制,向待處理的 IRQ 發出信號。

物理中斷

中斷物件通常是在裝置枚舉期間,由具有高度特權的驅動程式庫程式程序 (通常是平台匯流排驅動程式或 PCIe 匯流排驅動程式) 建立,然後透過委派提供給適當的驅動程式。代表物理邊緣和位元值觸發中斷的物件會使用 zx_interrupt_create() 建立,並且需要傳遞各種平台專屬的設定選項 (例如中斷是邊緣觸發還是位元值觸發,或是高電平活動還是低電平活動),才能正確設定系統的中斷控制器。

訊息信號中斷 (MSI,由 PCIe 裝置使用) 略有不同,必須透過對 zx_msi_allocate()zx_msi_create() 的呼叫來分配及建構。

如需更多資訊,請參閱這些系統呼叫的參考說明文件。

虛擬中斷

您也可以使用 zx_interrupt_create() 並傳遞 ZX_INTERRUPT_VIRTUAL 選項來建立虛擬中斷。虛擬中斷物件是純軟體結構,不會由硬體中斷要求發出信號。而是使用 zx_interrupt_trigger() 系統呼叫,為物件觸發虛擬 IRQ。

虛擬中斷通常用於下列任一情況:

第一個是測試。虛擬中斷會使用相同的特殊系統呼叫組合,用於等待並確認實際中斷的使用情形,但會將 IRQ 的觸發置於軟體控制之下。也就是說,測試程式碼可以建立虛擬中斷,並將其傳遞給測試中的驅動程式庫,而驅動程式庫可以直接使用中斷物件,無需修改程式碼。差異在於,現在測試架構可控制物件的中斷要求狀態,讓它在測試期間模擬各種硬體行為。

第二個是解調,通常用於 GPIO (通用輸入輸出) 中斷。許多晶片都允許將通用用途的引腳設為中斷來源,以便連接至需要將 IRQ 傳送至系統的外部裝置。通常,除了用於中斷的引腳 (無論是否用於中斷) 之外,用於控制引腳的共用暫存器 (代表引腳的資料庫) 也必須使用。通常,16 或 32 個引腳組會共用一組登錄器,以及與系統中斷控制器相關聯的單一實體中斷。

在這種系統中,可能會有一個驅動程式庫負責設定 GPIO 硬體,並處理常見的 GPIO 物理中斷,而其他驅動程式則負責外部硬體,這些硬體可能會使用共用常見 GPIO 群組的不同引腳連線至主系統。舉例來說,假設系統有一個外部晶片可處理藍牙,以及另一個用於加速計的晶片。每個驅動程式庫都與 GPIO 驅動程式庫和其他驅動程式分開,且應進行隔離。不過,即使 BT 和加速計驅動程式實際上在 GPIO 驅動程式庫的控制下共用單一實體中斷,但仍需要各自有中斷物件等待。

在這種情況下,中斷必須由 GPIO 驅動程式庫「解多工」,並使用虛擬中斷將中斷個別委派給適當的驅動程式。對於每個設為中斷的引腳,GPIO 驅動程式庫可以建立虛擬中斷,並將其傳遞至適當的特定工作驅動程式庫。當常見的物理 GPIO 中斷觸發時,GPIO 驅動程式庫可以識別代表任何新斷言 IRQ 的虛擬中斷,並使用 zx_interrupt_trigger() 觸發這些中斷。虛擬中斷的驅動程式庫使用者處理硬體並確認中斷後,GPIO 驅動程式庫就能在適當的 GPIO 登錄庫中重新啟用中斷,並透過共用的實體中斷等待新的 IRQ。

等待並確認中斷

使用者可以透過中斷物件等待中斷要求,方法是同步地在中斷物件上封鎖執行緒,或非同步地將中斷事件繫結至 Zircon 連接埠物件,在該物件中,IRQ 會使用連接埠封包傳送,而該封包可與傳送至連接埠的其他封包一併讀取。

只能使用一種方法。中斷物件無法同時繫結至埠,並讓執行緒在該埠上阻斷。此外,以同步方式使用時,一次只能在中斷物件上阻斷一個執行緒。嘗試封鎖第二個執行緒會導致錯誤。同樣地,在以非同步方式使用時,中斷物件一次只能繫結至一個連接埠,不得超過一個。

同步等待和確認

建立中斷物件後,使用者可以呼叫 zx_interrupt_wait(),藉此阻斷執行緒並等待 IRQ。如果中斷物件已觸發 (可能是由硬體 IRQ 觸發物理中斷,或是對虛擬中斷呼叫 zx_interrupt_trigger()),則呼叫會立即傳回。否則,執行緒會持續處於封鎖狀態,直到 IRQ 遭到斷言,或是中斷物件透過對 zx_interrupt_destroy() 的呼叫而遭到摧毀為止。

中斷物件觸發時,會釋放等待該物件的目前執行緒,或等待該物件的下一個執行緒。不過,即使該執行緒已解除封鎖,中斷仍會在邏輯上觸發,且在收到確認訊息前,中斷不會重新武裝及重新啟用。中斷物件的同步使用者會再次等待中斷物件,藉此確認 IRQ。中斷物件會在中斷控制器層級重新武裝,並在下一個 IRQ 斷言時解除封鎖執行緒。

非同步等待和確認

使用者也可以將中斷事件繫結至 Zircon 連接埠物件,以非同步方式等待 IRQ。為此,使用者會呼叫 zx_interrupt_bind(),將控制代碼傳遞至中斷物件,以及傳遞至已使用 ZX_PORT_BIND_TO_INTERRUPT 選項建立的端口的控制代碼。中斷事件已繫結至連接埠後:

1) 將中斷埠封包排入已繫結的連接埠,即可發出 IRQ 信號。2) 與標準 Zircon 訊號不同,在中斷事件繫結至通訊埠後,就不需要呼叫 zx_object_wait_async()。只要 IRQ 被提出,系統就會自動將通訊埠封包傳送至已繫結的通訊埠。2) 後續對 zx_interrupt_bind() 的呼叫會失敗。中斷物件一次只能繫結至單一連接埠。3) 對 zx_interrupt_wait() 的呼叫會失敗。中斷物件可同步或非同步使用,但不能同時使用。4) 您可以使用 zx_interrupt_unbind() 將中斷物件與其繫結的通訊埠解除連結,之後可以將其重新繫結至其他通訊埠,或透過 zx_interrupt_wait() 同步使用。

觸發已繫結的中斷並傳送通訊埠封包後,系統會等到中斷已收到確認才會傳送新封包。與同步模式不同,在同步模式中,中斷會透過下一次對 zx_interrupt_wait() 的呼叫來確認,但中斷物件的非同步使用者必須透過對 zx_interrupt_ack() 的呼叫,明確確認中斷。確認中斷後,系統會在下次 IRQ 被提出時,或在有其他 IRQ 待處理時,傳送新的埠封包。

使用者信號

雖然中斷物件不會使用標準 Zircon 信號通知使用者 IRQ,但仍屬於 Zircon 核心物件。因此,它們仍擁有八個標準的「使用者信號」集合,可透過對 zx_object_signal() 的呼叫進行設定和清除,並使用 zx_object_wait_one()zx_object_wait_many()zx_object_wait_async() 進行等待,前提是呼叫端必須具備具有足夠權限的句柄。

虛擬中斷和 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED

除了使用者信號之外,虛擬中斷物件還定義另一個名為 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 的標準锆石信號。

與實體中斷不同,在特定條件下,硬體會自動觸發中斷要求,但虛擬中斷物件必須由軟體明確觸發。虛擬中斷觸發後,負責觸發的軟體必須知道 IRQ 接收器何時已處理並確認 IRQ,以便日後在適當的時間點重新確認。

為了提供這項資訊,我們引入 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 信號。

當您使用虛擬中斷進行測試時,可以使用這個信號將測試推進下一個階段。當這個信號用於解調中斷時,多重中斷集合的擁有者可以使用這個信號,解除共用實體中斷的遮罩並重新啟用中斷,然後返回等待共用實體中斷。

ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 信號相關的規則如下:

  • 虛擬中斷物件在建立後立即處於「未觸發」狀態,並會斷言 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 信號。
  • 呼叫 zx_interrupt_trigger() 會導致中斷物件進入觸發狀態,並取消斷言 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 信號。
  • 信號會一直處於未確認狀態,直到消費者透過下一次對 zx_interrupt_wait() 的呼叫 (同步使用) 或對 zx_interrupt_ack() 的呼叫 (非同步使用) 確認為止。
  • 信號的觀察器會使用標準 zx_object_wait_one()zx_object_wait_many()zx_object_wait_async() 系統呼叫。

請注意,當中斷物件與通訊埠一起使用時,虛擬中斷可能處於已觸發的狀態,而另一個中斷則處於待處理狀態。初始對 zx_interrupt_trigger() 的呼叫會立即將通訊埠封包傳送至已繫結的通訊埠,而後續的呼叫會等待另一個中斷,但不會立即觸發通訊埠封包。

在這種情況下,當使用者透過對 zx_interrupt_ack() 的呼叫確認第一個 port 封包時,物件會從觸發狀態有效地移至未觸發狀態,但隨後會立即再次觸發,並傳送第二個 port 封包,從未觸發狀態轉回觸發狀態。

在這個過程中,ZX_VIRTUAL_INTERRUPT_UNTRIGGERED 信號基本上會處於「strobed」狀態。任何目前待處理的等待作業都會滿足 (在訊號上遭到封鎖的執行緒會解除封鎖,已發布的非同步等待作業會傳送埠封包),但物件訊號本身會在 zx_interrupt_ack() 的呼叫解開時立即解除宣告。

實體中斷物件「不會」實作 ZX_VIRTUAL_INTERRUPT_UNTRIGGERED,也不會斷言信號。

附註

中斷物件是 DDK 專用的,一般無法供使用者空間程序使用。

SYSCALLS