本页介绍了如何实现受保护的基于内核的虚拟机 (pKVM) 供应商模块。完成这些步骤后,您应该会看到类似于下方所示的目录树:
Makefile
el1.c
hyp/
Makefile
el2.c
添加 EL2 Hypervisor 代码 (
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 Hypervisor 的回调。此结构体遵循与 GKI 接口相同的 ABI 规则。
创建
hyp/Makefile
以构建 Hypervisor 代码:hyp-obj-y := el2.o include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
添加 EL1 内核代码 (
el1.c
)。此代码的 init 部分必须包含对pkvm_load_el2 module
的调用,以加载第 1 步中的 EL2 Hypervisor 代码。#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 (Hypervisor) 函数
Hypervisor 调用 (HVC) 是一条可让内核调用 Hypervisor 的指令。引入 pKVM 供应商模块后,HVC 可用于从 EL1(内核模块)调用会在 EL2(Hypervisor 模块)运行的函数:
- 在 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);