À partir du 27 mars 2025, nous vous recommandons d'utiliser android-latest-release au lieu de aosp-main pour créer et contribuer à AOSP. Pour en savoir plus, consultez la section Modifications apportées à AOSP.
Restez organisé à l'aide des collections
Enregistrez et classez les contenus selon vos préférences.
Cette page explique comment implémenter un module fournisseur de machine virtuelle basée sur le noyau protégé (pKVM).
Pour android16-6.12 et versions ultérieures, une fois ces étapes effectuées, vous devriez obtenir une arborescence de répertoires semblable à celle-ci:
Ajoutez le code de l'hyperviseur EL2 (el2.c). Ce code doit au moins déclarer une fonction d'initialisation acceptant une référence à la structure pkvm_module_ops:
L'API du module du fournisseur pKVM est une struct encapsulant les rappels de l'hyperviseur pKVM. Cette structure suit les mêmes règles ABI que les interfaces GKI.
Créez le hyp/Makefile pour créer le code de l'hyperviseur:
Ajoutez le code du kernel EL1 (el1.c). La section d'initialisation de ce code doit contenir un appel à pkvm_load_el2 module pour charger le code de l'hyperviseur EL2 à partir de l'étape 1.
Comme pour les modules du fournisseur GKI, les modules du fournisseur pKVM peuvent être chargés à l'aide de modprobe.
Toutefois, pour des raisons de sécurité, le chargement doit avoir lieu avant la privation de privilèges.
Pour charger un module pKVM, vous devez vous assurer que vos modules sont inclus dans le système de fichiers racine (initramfs) et que vous ajoutez les éléments suivants à votre ligne de commande du noyau:
kvm-arm.protected_modules=mod1,mod2,mod3,...
Les modules du fournisseur de pKVM stockés dans le initramfs héritent de la signature et de la protection de initramfs.
Si le chargement de l'un des modules du fournisseur de pKVM échoue, le système est considéré comme non sécurisé et il est impossible de démarrer une machine virtuelle protégée.
Appeler une fonction EL2 (hyperviseur) à partir d'EL1 (kernel module)
Un appel d'hyperviseur (HVC) est une instruction qui permet au noyau d'appeler l'hyperviseur. Avec l'introduction des modules du fournisseur pKVM, un HVC peut être utilisé pour appeler une fonction à exécuter à EL2 (dans le module de l'hyperviseur) à partir d'EL1 (le module du noyau):
Dans le code EL2 (el2.c), déclarez le gestionnaire 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;}
Dans votre code EL1 (el1.c), enregistrez le gestionnaire EL2 dans votre module fournisseur pKVM:
Le contenu et les exemples de code de cette page sont soumis aux licences décrites dans la Licence de contenu. Java et OpenJDK sont des marques ou des marques déposées d'Oracle et/ou de ses sociétés affiliées.
Dernière mise à jour le 2025/07/27 (UTC).
[[["Facile à comprendre","easyToUnderstand","thumb-up"],["J'ai pu résoudre mon problème","solvedMyProblem","thumb-up"],["Autre","otherUp","thumb-up"]],[["Il n'y a pas l'information dont j'ai besoin","missingTheInformationINeed","thumb-down"],["Trop compliqué/Trop d'étapes","tooComplicatedTooManySteps","thumb-down"],["Obsolète","outOfDate","thumb-down"],["Problème de traduction","translationIssue","thumb-down"],["Mauvais exemple/Erreur de code","samplesCodeIssue","thumb-down"],["Autre","otherDown","thumb-down"]],["Dernière mise à jour le 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);"]]