Auf dieser Seite wird beschrieben, wie Sie ein pKVM-Anbietermodul (Protected Kernel-based Virtual Machine) implementieren.
Bei android16-6.12 und höher sollte nach Abschluss dieser Schritte eine Verzeichnisstruktur wie die folgende vorhanden sein:
BUILD.bazel
el1.c
hyp/
    BUILD.bazel
    el2.c
Ein vollständiges Beispiel finden Sie unter pKVM-Modul mit DDK erstellen.
Für android15-6.6 und niedriger:
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- pkvm_module_ops-Struktur 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 pKVM-Anbietermodul-API ist eine Struktur, die Callbacks zum pKVM-Hypervisor kapselt. Diese Struktur folgt denselben ABI-Regeln wie GKI-Schnittstellen. 
- Erstellen Sie das - 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-Kernelcode ( - el1.c) hinzu. Der Initialisierungsabschnitt dieses Codes muss einen Aufruf von- pkvm_load_el2 moduleenthalten, um den EL2-Hypervisorcode 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 zum Schluss die Build-Regeln. - Für android16-6.12 und höher finden Sie unter pKVM-Modul mit DDK erstellen Informationen zum Erstellen von - ddk_library()für EL2 und- ddk_module()für EL1.- Erstellen Sie für android15-6.6 und früher das Root-Makefile, um den EL1- und EL2-Code 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
pKVM-Modul laden
Wie bei GKI-Anbietermodulen können pKVM-Anbietermodule mit modprobe geladen werden.
Aus Sicherheitsgründen muss das Laden jedoch vor dem Entfernen der Berechtigungen erfolgen.
Damit Sie ein pKVM-Modul laden können, müssen Sie dafür sorgen, dass Ihre Module im Stammdateisystem (initramfs) enthalten sind, und der Kernel-Befehlszeile Folgendes hinzufügen:
kvm-arm.protected_modules=mod1,mod2,mod3,...
pKVM-Anbietermodule, die in initramfs gespeichert sind, erben die Signatur und den Schutz von initramfs.
Wenn eines der pKVM-Anbietermodule nicht geladen werden kann, gilt das System als unsicher und es ist nicht möglich, eine geschützte virtuelle Maschine zu starten.
EL2-Funktion (Hypervisor) aus EL1 (Kernelmodul) aufrufen
Ein Hypervisor-Aufruf (HVC) ist ein Befehl, mit dem der Kernel den Hypervisor aufrufen kann. Mit der Einführung von pKVM-Anbietermodulen kann mit einem HVC eine Funktion aufgerufen werden, die auf EL2 (im Hypervisor-Modul) von EL1 (dem Kernelmodul) aus ausgeführt werden soll:
- Deklarieren Sie 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 den EL2-Handler in Ihrem pKVM-Anbietermodul in Ihrem EL1-Code ( - el1.c):- 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);
- Rufen Sie den HVC in Ihrem EL1-Code ( - el1.c) auf:- pkvm_el2_mod_call(hvc_number);