Auf dieser Seite wird erläutert, wie Sie ein pKVM-Anbietermodul (Protected Kernel-based Virtual Machine, pKVM) implementieren. Wenn Sie diese Schritte abgeschlossen haben, sollte in etwa eine Verzeichnisstruktur wie diese aussehen:
Makefile
el1.c
hyp/
Makefile
el2.c
Fügen Sie den EL2-Hypervisor-Code (
el2.c
) hinzu. Dieser Code muss mindestens eine Init-Funktion deklarieren, die einen Verweis auf die Strukturpkvm_module_ops
akzeptiert:#include <asm/kvm_pkvm_module.h> int pkvm_driver_hyp_init(const struct pkvm_module_ops *ops) { /* Init the EL2 code */ return 0; }
Die API des pKVM-Anbietermoduls ist eine Struktur, die Rückrufe an die pKVM-Hypervisor. Diese Struktur folgt denselben ABI-Regeln wie GKI-Schnittstellen.
Erstellen Sie den
hyp/Makefile
, um den Hypervisor-Code zu erstellen:hyp-obj-y := el2.o include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
Fügen Sie den EL1-Kernel-Code (
el1.c
) hinzu. Der Init-Abschnitt dieses Codes muss einen Aufruf vonpkvm_load_el2 module
enthalten, um den EL2-Hypervisor-Code aus Schritt 1 zu laden.#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);
Erstellen Sie abschließend das Root-Makefile, um den EL1- und den EL2-Code miteinander zu verknüpfen:
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
Ein pKVM-Modul laden
Wie die GKI-Anbietermodule können pKVM-Anbietermodule mit „modprobe“ geladen werden.
Aus Sicherheitsgründen muss der Ladevorgang jedoch vor dem Deaktivieren der Berechtigungen erfolgen.
Um ein pKVM-Modul zu laden, müssen Sie darauf achten, dass Ihre Module in
das Root-Dateisystem (initramfs
). Sie müssen Folgendes zu Ihrem
Kernel-Befehlszeile:
kvm-arm.protected_modules=mod1,mod2,mod3,...
In initramfs
gespeicherte pKVM-Anbietermodule übernehmen die Signatur und den Schutz von initramfs
.
Wenn eines der pKVM-Anbietermodule nicht geladen wird, gilt das System als unsicher und es ist nicht möglich, eine geschützte virtuelle Maschine zu starten.
EL2-Funktion (Hypervisor) aus EL2 (Kernelmodul) aufrufen
Ein Hypervisor-Aufruf (HVC) ist eine Anweisung, mit der der Kernel den Hypervisor aufrufen kann. Mit der Einführung von pKVM-Anbietermodulen kann ein HVC verwendet werden, um eine Funktion zur Ausführung bei EL2 (im Hypervisor-Modul) von EL1 (dem Kernelmodul) aufzurufen:
- Deklariere im EL2-Code (
el2.c
) den EL2-Handler:
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;
}
Registrieren Sie im EL1-Code (
el1.c
) den EL2-Handler bei Ihrem pKVM-Anbieter Modul: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);
Rufe in deinem EL1-Code (
el1.c
) den HVC auf:pkvm_el2_mod_call(hvc_number);