本頁說明如何實作受保護核心型虛擬機器 (pKVM) 廠商模組。完成這些步驟後,您應該擁有類似如下的目錄樹狀結構:
Makefile
el1.c
hyp/
Makefile
el2.c
新增 EL2 管理程序程式碼 (
el2.c
)。這個程式碼至少必須宣告一個接受pkvm_module_ops
結構體參照的 init 函式:#include <asm/kvm_pkvm_module.h> int pkvm_driver_hyp_init(const struct pkvm_module_ops *ops) { /* Init the EL2 code */ return 0; }
pKVM 供應商模組 API 是一種結構體,用於封裝 pKVM 管理程序這個結構遵循與 GKI 介面相同的 ABI 規則。
建立
hyp/Makefile
來建構管理程序程式碼:hyp-obj-y := el2.o include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
新增 EL1 核心程式碼 (
el1.c
)。這個程式碼的 init 部分必須包含pkvm_load_el2 module
的呼叫,才能載入步驟 1 的 EL2 管理程序程式碼。#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <asm/kvm_pkvm_module.h> int __kvm_nvhe_pkvm_driver_hyp_init(const struct pkvm_module_ops *ops); static int __init pkvm_driver_init(void) { unsigned long token; return pkvm_load_el2_module(__kvm_nvhe_pkvm_driver_hyp_init, &token); } module_init(pkvm_driver_init);
最後,建立根 makefile,將 EL1 和 EL2 程式碼結合在一起:
ifneq ($(KERNELRELEASE),) clean-files := hyp/hyp.lds hyp/hyp-reloc.S obj-m := pkvm_module.o pkvm_module-y := el1.o hyp/kvm_nvhe.o $(PWD)/hyp/kvm_nvhe.o: FORCE $(Q)$(MAKE) $(build)=$(obj)/hyp $(obj)/hyp/kvm_nvhe.o else all: make -C $(KDIR) M=$(PWD) modules clean: make -C $(KDIR) M=$(PWD) clean endif
載入 pKVM 模組
和 GKI 供應商模組一樣,您可以使用 modprobe 載入 pKVM 供應商模組。
但基於安全考量,載入作業必須在卸除權限前發生。
如要載入 pKVM 模組,您必須確認模組包含在
根檔案系統 (initramfs
),您必須將下列內容加入
核心指令列:
kvm-arm.protected_modules=mod1,mod2,mod3,...
儲存在 initramfs
中的 pKVM 供應商模組會繼承 initramfs
的簽章和保護功能。
如果其中一個 pKVM 供應商模組無法載入,系統會將該系統視為不安全,因而無法啟動受保護的虛擬機器。
從 EL2 (核心模組) 呼叫 EL2 (管理程序) 函式
管理程序呼叫 (HVC) 是讓核心呼叫管理程序的指示。導入 pKVM 供應商模組後,HVC 可用於呼叫從 EL1 (核心模組) 的 EL2 (在管理程序模組中) 執行的函式:
- 在 EL2 程式碼 (
el2.c
) 中宣告 EL2 處理常式:
Android-14
void pkvm_driver_hyp_hvc(struct kvm_cpu_context *ctx)
{
/* Handle the call */
cpu_reg(ctx, 1) = 0;
}
Android-15
void pkvm_driver_hyp_hvc(struct user_pt_regs *regs)
{
/* Handle the call */
regs->regs[0] = SMCCC_RET_SUCCESS;
regs->regs[1] = 0;
}
在 EL1 程式碼 (
el1.c
) 中,前往 pKVM 供應商註冊 EL2 處理常式 模組:int __kvm_nvhe_pkvm_driver_hyp_init(const struct pkvm_module_ops *ops); void __kvm_nvhe_pkvm_driver_hyp_hvc(struct kvm_cpu_context *ctx); // Android14 void __kvm_nvhe_pkvm_driver_hyp_hvc(struct user_pt_regs *regs); // Android15 static int hvc_number; static int __init pkvm_driver_init(void) { long token; int ret; ret = pkvm_load_el2_module(__kvm_nvhe_pkvm_driver_hyp_init,token); if (ret) return ret; ret = pkvm_register_el2_mod_call(__kvm_nvhe_pkvm_driver_hyp_hvc, token) if (ret < 0) return ret; hvc_number = ret; return 0; } module_init(pkvm_driver_init);
在 EL1 程式碼 (
el1.c
) 中呼叫 HVC:pkvm_el2_mod_call(hvc_number);