Kể từ ngày 27 tháng 3 năm 2025, bạn nên sử dụng android-latest-release thay vì aosp-main để xây dựng và đóng góp cho AOSP. Để biết thêm thông tin, hãy xem phần Thay đổi đối với AOSP.
API mô-đun nhà cung cấp pKVM là một cấu trúc đóng gói các lệnh gọi lại đến trình điều khiển ảo hoá pKVM. Cấu trúc này tuân theo các quy tắc ABI giống như giao diện GKI.
Tạo hyp/Makefile để tạo mã trình điều khiển ảo hoá:
Cũng như các mô-đun nhà cung cấp GKI, bạn có thể tải các mô-đun nhà cung cấp pKVM bằng modprobe.
Tuy nhiên, vì lý do bảo mật, quá trình tải phải diễn ra trước khi thu hồi đặc quyền.
Để tải mô-đun pKVM, bạn phải đảm bảo các mô-đun của mình có trong hệ thống tệp gốc (initramfs) và bạn phải thêm nội dung sau vào dòng lệnh hạt nhân:
kvm-arm.protected_modules=mod1,mod2,mod3,...
Các mô-đun nhà cung cấp pKVM được lưu trữ trong initramfs kế thừa chữ ký và tính năng bảo vệ của initramfs.
Nếu một trong các mô-đun nhà cung cấp pKVM không tải được, thì hệ thống sẽ được coi là không an toàn và bạn sẽ không thể khởi động máy ảo được bảo vệ.
Gọi hàm EL2 (trình điều khiển ảo hoá) từ EL1 (mô-đun hạt nhân)
Lệnh gọi trình điều khiển ảo hoá (HVC) là một lệnh cho phép nhân gọi trình điều khiển ảo hoá. Với việc ra mắt các mô-đun nhà cung cấp pKVM, bạn có thể sử dụng HVC để gọi một hàm chạy ở EL2 (trong mô-đun trình điều khiển ảo hoá) từ EL1 (mô-đun hạt nhân):
Trong mã EL2 (el2.c), hãy khai báo trình xử lý 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;}
Trong mã EL1 (el1.c), hãy đăng ký trình xử lý EL2 trong mô-đun nhà cung cấp pKVM:
Nội dung và mã mẫu trên trang này phải tuân thủ các giấy phép như mô tả trong phần Giấy phép nội dung. Java và OpenJDK là nhãn hiệu hoặc nhãn hiệu đã đăng ký của Oracle và/hoặc đơn vị liên kết của Oracle.
Cập nhật lần gần đây nhất: 2025-07-27 UTC.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 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);"]]