鐵人賽
IOMMU 可以選擇性的支援 memory resident interrupt file(以下簡稱 MRIF),如果實作了,使用 MRIF 可以新增大大增加虛擬 hart 的數量,前提是系統可以處理新增的負載。
如果沒有 MRIF,虛擬 hart 數量會受到實作的 IMSIC guest interrup file 數量限制的影響,因為所有 MSI 到 hart 都會經過 IMSIC。因此當只有一個 hart 時,guest interrupt file 的數量根據 RV32 或 RV64 有所不同, RV32 最多 31 個,RV64 最多 63 個。
如果有 MRIF,能夠接收設備 MSI 的虛擬 hart 數量幾乎是無限的,只會受到實體記憶體的量和他們所需要額外處理的時間限制。正如 MRIF 的名字所定義是位於記憶體當中,而非 IMSIC。
下圖顯示 IOMMU 如何在 MRIF 中紀錄傳入的 MSI:
上圖描述了,如何在 MRIF 中紀錄傳入的 MSI。當 hypervisor 正確配置時,IOMMU 會識別傳入的 MSI 用於特定的虛擬 interrupt file,並且儲存在 MRIF 紀錄此 MSI。在 MRIF 中紀錄 MSI 後,IOMMU 會向 hypervisor 發送 通知 MSI,通知它 MRIF 內容已經更改。
雖然 MRIF 提供紀錄 MSI 的地址,但它不能向 IMSIC guest interrupt file 那樣直接 interrupt hart,hypervisor 收到 通知 MSI 只表示 VM 可能需要 interrupt,hypervisor 負責檢查 MRIF 的內容,以確認是否真的要 interrupt vm。此外,雖然 IMSIC 的 guest interrupt file 可以當作 virtual hart 的 suprevisor interrupt file 使用,但在 virtual hart 執行時,將 virtual hart 的 interrupt file 保存在 MRIF 當中,hypervisor 為 virtual hart 模擬 supervisor interrupt file,以隱藏底層 MRIF。根據 virtual hart 接觸其 interrupt file 的頻率以及實現對 MRIF 的支援,此模擬的成本可能很高。
因此 MRIF 最常被使用於虛擬 hart,因為虛擬 hart 較少被替換,常常處於 idle 的狀態。當 hypervisor 確定進入 MRIF 的 MSI,應該喚醒處於 idle 的虛擬 hart 時,可以為虛擬 hart 分配 IMSIC 中的 guest interrupt file,並在虛擬 hart 回復之前,將其 interrupt file 從 MRIF 移動到此 guest interrupt file。
MRIF 佔用記憶體 512 byte,與 512 byte address 邊界對齊。 這 512 byte 被 64 個 64 byte doubleword所組成。每個 64 byte doubleword 都按照 little-endian byte 順序排列
這些 doubleword 包含 external interrupt 的 pending bit 以及 enable bit 排序如下:
external interrupt 的 pending 以及 enable bit 範圍為 k*64
到 k*64+63
。對於此範圍內 ID i,第一個(偶數) doubleword 的位元是 interrupt pending bit,而第二個(奇數)doubleword 的位元是 interrupt enable bit。
MRIF 第一個 doubleword 的 bit 0 為不存在的 interrupt 0,儲存一個假的 pending interrupt。如果 I/O 設備的寫入是儲存在 MRIF 中的 MSI ,但要寫入的 data 為 0,則 IOMMU 將會表現零視為有效的 interrupt ID,設定目標 MRIF 第一個 doubleword bit 0,並像往常一樣發送 通知 MSI 。
所有 MRIF 的大小都能榮內 2047 個有效 interrupt ID,這是 IMSIC interrupt file 允許的最大值,如果系統的實際 IMSIC 只有 N 個 interrupt ID (N < 2047)的 interrupt file,則軟體忽略大於 N 的 MRIF 內容。
MSI 寫入的 data 組成中,要在目標 interrupt file 中寫入指定的 interrupt ID,此 data 可以是 little_endian 或是 big_endian 順序,所有 IMSIC interrupt file 都需要接受以 little_endian 順序寫入 memory mapped setipnum_le
的 MSI,如果 setipnum_be
也一同實作, IMSIC interrupt file 也可以接受 big-endian 順序 的 MSI。
如果 MSI 的 data 表示 interrupt ID 在 0~2047 範圍內,則 IOMMU 將 MSI 儲存到 MRIF。如果 MRIF 支援 atomic 更新,則使用 AMOOR 操作來舉起(set bit 為 1) pending bit ,否則使用 non-atomic read-modify-write 方式進行。在 MRIF 中設定 itnerrupt pending bit 後,IOMMU 發送 通知 MSI 表示軟體已為 MRIF 配置完成。
為了支援 atomic 更新的 MRIF,除了需要之前介紹的 MRIF 結構 之外,軟體還必須具有 memory 地址,用來保存 IMSIC interrupt file eidelivery
和 eithreshold
。
將 virtual hart interrupt file 從 IMSIC 移動到 MRIF 步驟:
eidelivery
和 eithreshold
現有值保存在記憶體中,並設定 eidelivery = 0
。一旦上述步驟完成,IMSIC interrupt file 就不再使用。
每當 通知 MSI 到達時,表示 MSI 已儲存在 MRIF 中了,hypervisor 需要掃視 MRIF 的 pending 以及 enable bit,以確定是否有任何啟用的 interrupt 目前處於 pending 以及 enable 狀態,需要 interrupt 虛擬 hart 。
隨著 MRIF 的 atomic 更新,虛擬 hart 可以使用在 MRIF 中的 interrupt file 繼續執行,只要 hypervisor 為虛擬 hart 模擬一個適當的 IMSIC interrupt file。hypervisor 可以使用 AMOOR 和 AMOAND 來安全的設定或清除 MRIF 中的 interrupt pending 以及 enable bit。
將同一 interrupt file 從 MRIF 移回 IMSIC:
eidelivery = 0
,並將 eip array 歸0eithreshold
以及 eidelivery
當中。在不支援 atomic 更新的情況下,MRIF 的使用方式類似於 atomic 更新的方式,但又新增了一些複雜性。
首先,如果 虛擬 hart 控制的 I/O 設備位於多個 IOMMU 後面,則需要多個 MRIF 結構,每個 IOMMU 一個。此外,除了用於儲存 eidelivery
和eithreshold
的位置外,軟體還需要一個位置來存放 interrupt file 實現的 eip array。當虛擬 interrupt file 在記憶體中時,它的 interrupt pending bit 將所有 MRIF 以及保存的 eip array 分割。
interrupt enable bit 只存在於 MRIF 中。
將虛擬 hart 的 interrupt file 從 IMSIC 移動到記憶體中,每個 IOMMU 有一個 MRIF:
eidelivery
和 eithreshold
的值保存在記憶體中,並設定 eidelivery =0
一旦該上述步驟完成,IMSIC interrupt file 就不再使用
當虛擬 hart 的 interrupt file 保留在記憶體中時,interrupt ID 的 pending bit 保存在 eip array。MRIF 中的所有 pending bit 皆是以0開始,但當此虛擬 hart 的 MSI 到達 IOMMU 並儲存在相對應的 MRIF時,interrupt pending bit 會被舉起。
如果 MRIF 沒有 atomic 更新,則無法在 MRIF 中輕鬆清除 interrupt pending bit,當 MRIF 紀錄一個應該喚醒虛擬 hart 的 interrupt 時,最簡單的策略是在繼續執行虛擬 hart 之前,將interrupt file 移回 IMSIC 的 guest interrupt file。
要將 interrupt file 從記憶體傳輸回 IMSIC:
eidelviery = 0
,並將 eip array 歸0eithreshold
和 eidelivery
透過為每個 MRIF 分配一個 interrupt ID, hypervisor 可以最小化處理 通知 MSI,因此 通知 MSI 總是可以知道是哪個 MRIF 已被更改。 然而,如果有非常多的MRIF(可能有數千個),hypervisor 可能沒有足夠的 interrupt ID 可使用。在這種情況下,hypervisor 可以通過為自己分配一個或多個 IMSIC 的guest interrupt file 來新增其 interrupt ID ,以接收通知MSI。
如果 IOMMU 有支援 MRIF 則虛擬 hart 的數量無限,如果沒有支援 MRIF 則根據實作的 IMSIC 當中的 guest interrupt file 數量決定,由於每個 hart 配置一個 IMSIC,因此一個 hart,在 RV32 情況下,最多 31 虛擬 hart,在 RV64 情況下,最多 63 個虛擬 hart。