A partir del 27 de marzo de 2025, te recomendamos que uses android-latest-release en lugar de aosp-main para compilar y contribuir a AOSP. Para obtener más información, consulta Cambios en AOSP.
Agrega el código del hipervisor EL2 (el2.c). Como mínimo, este código debe declarar una función de inicialización que acepte una referencia a la estructura pkvm_module_ops:
La API del módulo de proveedores de la pKVM es una estructura que encapsula devoluciones de llamada al hipervisor de la pKVM. Esta estructura sigue las mismas reglas de ABI que las interfaces de GKI.
Crea el hyp/Makefile para compilar el código del hipervisor:
Agrega el código del kernel EL1 (el1.c). La sección de inicialización de este código debe contener una llamada a pkvm_load_el2 module para cargar el código del hipervisor EL2 del paso 1.
Al igual que con los módulos de proveedores de GKI, los módulos de proveedores de pKVM se pueden cargar con modprobe.
Sin embargo, por motivos de seguridad, la carga debe ocurrir antes de la privación de privilegios.
Para cargar un módulo pKVM, debes asegurarte de que tus módulos se incluyan en el sistema de archivos raíz (initramfs) y debes agregar lo siguiente a la línea de comandos del kernel:
kvm-arm.protected_modules=mod1,mod2,mod3,...
Los módulos de proveedores de la pKVM almacenados en initramfs heredan la firma y la protección de initramfs.
Si no se carga uno de los módulos del proveedor de pKVM, el sistema se considerará inseguro y no será posible iniciar una máquina virtual protegida.
Llama a una función de EL2 (hipervisor) desde EL1 (módulo de kernel)
Una llamada al hipervisor (HVC) es una instrucción que permite que el kernel llame al hipervisor. Con la introducción de los módulos de proveedores de pKVM, se puede usar un HVC para llamar a una función que se ejecute en EL2 (en el módulo de hipervisor) desde EL1 (el módulo de kernel):
En el código de EL2 (el2.c), declara el controlador de EL2:
Android-14
voidpkvm_driver_hyp_hvc(structkvm_cpu_context*ctx){/* Handle the call */cpu_reg(ctx,1)=0;}
Android-15
voidpkvm_driver_hyp_hvc(structuser_pt_regs*regs){/* Handle the call */regs->regs[0]=SMCCC_RET_SUCCESS;regs->regs[1]=0;}
En tu código EL1 (el1.c), registra el controlador EL2 en el módulo de proveedor de la pKVM:
El contenido y las muestras de código que aparecen en esta página están sujetas a las licencias que se describen en la Licencia de Contenido. Java y OpenJDK son marcas registradas de Oracle o sus afiliados.
Última actualización: 2025-07-27 (UTC)
[[["Fácil de comprender","easyToUnderstand","thumb-up"],["Resolvió mi problema","solvedMyProblem","thumb-up"],["Otro","otherUp","thumb-up"]],[["Falta la información que necesito","missingTheInformationINeed","thumb-down"],["Muy complicado o demasiados pasos","tooComplicatedTooManySteps","thumb-down"],["Desactualizado","outOfDate","thumb-down"],["Problema de traducción","translationIssue","thumb-down"],["Problema con las muestras o los códigos","samplesCodeIssue","thumb-down"],["Otro","otherDown","thumb-down"]],["Última actualización: 2025-07-27 (UTC)"],[],[],null,["# Implement a pKVM vendor module\n\nThis page explains how to implement a protected kernel-based virtual machine\n(pKVM) vendor module.\n\nFor android16-6.12 and later, when you are done with these\nsteps, you should have a directory tree similar to: \n\n BUILD.bazel\n el1.c\n hyp/\n BUILD.bazel\n el2.c\n\nFor a complete example, see\n[Build a pKVM module with DDK](https://android.googlesource.com/kernel/build/+/refs/heads/main-kernel/kleaf/tests/ddk_examples/pkvm/README.md)\n.\n\nFor android15-6.6 and earlier: \n\n Makefile\n el1.c\n hyp/\n Makefile\n el2.c\n\n1. Add the EL2 hypervisor code (`el2.c`). At a minimum, this code must declare an init function accepting a reference to the `pkvm_module_ops` struct:\n\n #include \u003casm/kvm_pkvm_module.h\u003e\n\n int pkvm_driver_hyp_init(const struct pkvm_module_ops *ops)\n {\n /* Init the EL2 code */\n\n return 0;\n }\n\n The pKVM vendor module API is a struct encapsulating callbacks to the\n pKVM hypervisor. This struct follows the same ABI rules as GKI interfaces.\n | **Note:** Unlike the kernel, no symbol is exported and all calls to the hypervisor must happen through the callbacks in the struct [pkvm_module_ops](https://android.googlesource.com/kernel/common/+/refs/heads/android14-6.1/arch/arm64/include/asm/kvm_pkvm_module.h#19 \"kvm_pkvm_module.h\").\n2. Create the `hyp/Makefile` to build the hypervisor code:\n\n hyp-obj-y := el2.o\n include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module\n\n3. Add the EL1 kernel code (`el1.c`). This code's init section must contain a call to `pkvm_load_el2 module` to load the EL2 hypervisor code from step 1.\n\n #include \u003clinux/init.h\u003e\n #include \u003clinux/module.h\u003e\n #include \u003clinux/kernel.h\u003e\n #include \u003casm/kvm_pkvm_module.h\u003e\n\n int __kvm_nvhe_pkvm_driver_hyp_init(const struct pkvm_module_ops *ops);\n\n static int __init pkvm_driver_init(void)\n {\n unsigned long token;\n\n return pkvm_load_el2_module(__kvm_nvhe_pkvm_driver_hyp_init, &token);\n }\n module_init(pkvm_driver_init);\n\n | **Note:** `__kvm_nvhe_pkvm_driver_hyp_init` is a pointer to the EL2 init function in the EL2 hypervisor code (step 1).\n4. Finally, create the build rules.\n\n For android16-6.12 and later, refer to\n [Build a pKVM module with DDK](https://android.googlesource.com/kernel/build/+/refs/heads/main-kernel/kleaf/tests/ddk_examples/pkvm/README.md)\n to create `ddk_library()` for EL2 and `ddk_module()` for EL1.\n\n For android15-6.6 and earlier, create the root makefile to tie the EL1 and\n EL2 code together: \n\n ifneq ($(KERNELRELEASE),)\n clean-files := hyp/hyp.lds hyp/hyp-reloc.S\n\n obj-m := pkvm_module.o\n pkvm_module-y := el1.o hyp/kvm_nvhe.o\n\n $(PWD)/hyp/kvm_nvhe.o: FORCE\n $(Q)$(MAKE) $(build)=$(obj)/hyp $(obj)/hyp/kvm_nvhe.o\n else\n all:\n make -C $(KDIR) M=$(PWD) modules\n clean:\n make -C $(KDIR) M=$(PWD) clean\n endif\n\nLoad a pKVM module\n------------------\n\nAs with GKI vendor modules, pKVM vendor modules can be loaded using modprobe.\nHowever, for security reasons, loading must occur before deprivileging.\nTo load a pKVM module, you must ensure your modules are included in\nthe root filesystem (`initramfs`) and you must add the following to your\nkernel command-line:\n\n`kvm-arm.protected_modules=`\u003cvar translate=\"no\"\u003emod1\u003c/var\u003e`,`\u003cvar translate=\"no\"\u003emod2\u003c/var\u003e`,`\u003cvar translate=\"no\"\u003emod3\u003c/var\u003e`,`\u003cvar translate=\"no\"\u003e...\u003c/var\u003e\n\npKVM vendor modules stored in the `initramfs` inherit the signature and protection of `initramfs`.\n\nIf one of the pKVM vendor modules fails to load, the system is considered insecure and it won't be possible to start a protected virtual machine.\n\nCall an EL2 (hypervisor) function from EL1 (kernel module)\n----------------------------------------------------------\n\nAn *hypervisor call (HVC)* is an instruction that lets the kernel to call the hypervisor. With the introduction of pKVM vendor modules, an HVC can be used to call for a function to run at EL2 (in the hypervisor module) from EL1 (the kernel module):\n\n1. In the EL2 code (`el2.c`), declare the EL2 handler:\n\n**Android-14** \n\n void pkvm_driver_hyp_hvc(struct kvm_cpu_context *ctx)\n {\n /* Handle the call */\n\n cpu_reg(ctx, 1) = 0;\n }\n\n**Android-15** \n\n void pkvm_driver_hyp_hvc(struct user_pt_regs *regs)\n {\n /* Handle the call */\n\n regs-\u003eregs[0] = SMCCC_RET_SUCCESS;\n regs-\u003eregs[1] = 0;\n }\n\n| **Note:** EL2 code is non preemptable. This section must therefore be as short as possible.\n\n1. In your EL1 code (`el1.c`), register the EL2 handler in your pKVM vendor\n module:\n\n int __kvm_nvhe_pkvm_driver_hyp_init(const struct pkvm_module_ops *ops);\n void __kvm_nvhe_pkvm_driver_hyp_hvc(struct kvm_cpu_context *ctx); // Android14\n void __kvm_nvhe_pkvm_driver_hyp_hvc(struct user_pt_regs *regs); // Android15\n\n static int hvc_number;\n\n static int __init pkvm_driver_init(void)\n {\n long token;\n int ret;\n\n ret = pkvm_load_el2_module(__kvm_nvhe_pkvm_driver_hyp_init,token);\n if (ret)\n return ret;\n\n ret = pkvm_register_el2_mod_call(__kvm_nvhe_pkvm_driver_hyp_hvc, token)\n if (ret \u003c 0)\n return ret;\n\n hvc_number = ret;\n\n return 0;\n }\n module_init(pkvm_driver_init);\n\n2. In your EL1 code (`el1.c`), call the HVC:\n\n pkvm_el2_mod_call(hvc_number);"]]