Kexec 切換概念

Kexec 切換 (KHO) 是一種機制,允許 Linux 在 kexec 期間保留記憶體區域,這些區域可能包含序列化的系統狀態。

它引入了多個概念

KHO FDT

每個 KHO kexec 都帶有一個 KHO 特定的扁平化裝置樹 (FDT) blob,用於描述保留的記憶體區域。 這些區域包含序列化的子系統狀態,或在 kexec 期間不應觸及的記憶體資料。 KHO 後,子系統可以從 KHO FDT 檢索和恢復保留的記憶體區域。

KHO 僅使用 FDT 容器格式和 libfdt 庫,但不遵守與普通裝置樹相同的屬性語義:屬性以本機位元組序傳遞,並且不存在像 regsranges 這樣的標準化屬性,因此沒有 #...-cells 屬性。

KHO 仍在開發中。 FDT 模式不穩定,將來會發生變化。

暫存區域

要啟動到 kexec,我們需要有一個物理上連續的記憶體範圍,其中不包含移交的記憶體。 然後,Kexec 將目標核心和 initrd 放入該區域。 在頁面分配器初始化之前,新核心專門使用此區域進行記憶體分配。

我們透過暫存區域保證我們始終擁有這樣的區域:在首次啟動時,KHO 分配多個物理上連續的記憶體區域。 由於 kexec 後,這些區域將被早期記憶體分配使用,因此每個 NUMA 節點都有一個暫存區域,外加一個滿足不需要特定 NUMA 節點分配請求的暫存區域。 預設情況下,暫存區域的大小是根據啟動期間分配的記憶體量計算的。 可以使用 kho_scratch 核心命令列選項顯式定義暫存區域的大小。 初始化頁面分配器時,暫存區域宣告為 CMA,以便其記憶體可以在系統生命週期中使用。 CMA 保證沒有移交頁面落入該區域,因為移交頁面必須位於靜態物理記憶體位置,並且 CMA 強制只有可移動頁面才能位於內部。

在 KHO kexec 之後,我們忽略 kho_scratch 核心命令列選項,而是重用最初分配的完全相同的區域。 這允許我們遞迴執行任意數量的 KHO kexec。 因為我們將此區域用於啟動記憶體分配和 kexec blob 的目標記憶體,所以該記憶體區域的某些部分可能會被保留。 這些保留與下一個 KHO 無關,因為 kexec 甚至可以覆蓋原始核心。

KHO 完成階段

為了啟用基於使用者空間的 kexec 檔案載入器,核心需要在執行實際的 kexec 之前能夠提供描述當前核心狀態的 FDT。 生成該 FDT 的過程稱為序列化。 當 FDT 生成時,系統的某些屬性可能會變得不可變,因為它們已經寫入 FDT。 該狀態稱為 KHO 完成階段。

公共 API

struct folio *kho_restore_folio(phys_addr_t phys)

從保留的記憶體中重新建立 folio。

引數

phys_addr_t phys

folio 的物理地址。

返回

成功時返回指向 struct folio 的指標,失敗時返回 NULL。

int kho_add_subtree(struct kho_serialization *ser, const char *name, void *fdt)

記錄 KHO 根樹中子 FDT 的物理地址。

引數

struct kho_serialization *ser

由 KHO 通知程式傳遞的序列化控制物件。

const char *name

子樹的名稱。

void *fdt

子樹 blob。

描述

在 KHO 根 FDT 中建立一個名為 **name** 的新子節點,並記錄 **fdt** 的物理地址。 **fdt** 的頁面也必須由 KHO 保留,以便新核心在 kexec 後檢索它。

debugfs blob 條目也在 /sys/kernel/debug/kho/out/sub_fdts/**name** 建立。

返回

成功時返回 0,失敗時返回錯誤程式碼

int kho_preserve_folio(struct folio *folio)

在 kexec 期間保留一個 folio。

引數

struct folio *folio

要保留的 folio。

描述

指示 KHO 在 kexec 期間保留整個 folio。 順序也將被保留。

返回

成功時返回 0,失敗時返回錯誤程式碼

int kho_preserve_phys(phys_addr_t phys, size_t size)

在 kexec 期間保留一個物理上連續的範圍。

引數

phys_addr_t phys

範圍的物理地址。

size_t size

範圍的大小。

描述

指示 KHO 在 kexec 期間保留從 **phys** 到 **phys** + **size** 的記憶體範圍。

返回

成功時返回 0,失敗時返回錯誤程式碼

int kho_retrieve_subtree(const char *name, phys_addr_t *phys)

按名稱檢索保留的子 FDT。

引數

const char *name

傳遞給 kho_add_subtree() 的子 FDT 的名稱。

phys_addr_t *phys

如果找到,子 FDT 的物理地址將儲存在 **phys** 中。

描述

檢索名為 **name** 的保留子 FDT,並將其物理地址儲存在 **phys** 中。

返回

成功時返回 0,失敗時返回錯誤程式碼