หน้านี้อธิบายวิธีการใช้โมดูลผู้จำหน่ายเครื่องเสมือนที่ใช้เคอร์เนล (pKVM) ที่ได้รับการป้องกัน เมื่อคุณทำตามขั้นตอนเหล่านี้เสร็จแล้ว คุณควรมีแผนผังไดเร็กทอรีที่คล้ายกับ:
Makefile
el1.c
hyp/
Makefile
el2.c
เพิ่มโค้ดไฮเปอร์ไวเซอร์ EL2 (
el2.c
) อย่างน้อยที่สุด รหัสนี้จะต้องประกาศฟังก์ชัน init ที่ยอมรับการอ้างอิงถึงโครงสร้างpkvm_module_ops
:#include <asm/kvm_pkvm_module.h> int pkvm_driver_hyp_init(const struct pkvm_module_ops *ops) { /* Init the EL2 code */ return 0; }
API โมดูลผู้จำหน่าย pKVM เป็นโครงสร้างที่ห่อหุ้มการเรียกกลับไปยังไฮเปอร์ไวเซอร์ pKVM โครงสร้างนี้เป็นไปตามกฎ ABI เดียวกันกับอินเทอร์เฟซ GKI
สร้าง
hyp/Makefile
เพื่อสร้างโค้ดไฮเปอร์ไวเซอร์:hyp-obj-y := el2.o include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
เพิ่มโค้ดเคอร์เนล EL1 (
el1.c
) ส่วนเริ่มต้นของโค้ดนี้ต้องมีการเรียกpkvm_load_el2 module
เพื่อโหลดโค้ดไฮเปอร์ไวเซอร์ EL2 จากขั้นตอนที่ 1#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);
สุดท้าย ให้สร้าง root makefile เพื่อผูกโค้ด EL1 และ EL2 เข้าด้วยกัน:
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
เช่นเดียวกับโมดูลผู้จำหน่าย GKI โมดูลผู้จำหน่าย pKVM สามารถโหลดได้โดยใช้ modprobe อย่างไรก็ตาม ด้วยเหตุผลด้านความปลอดภัย การโหลดจะต้องเกิดขึ้นก่อนที่จะถูกลิดรอนสิทธิ์ หากต้องการโหลดโมดูล pKVM คุณต้องแน่ใจว่าโมดูลของคุณรวมอยู่ในระบบไฟล์รูท ( initramfs
) และคุณต้องเพิ่มสิ่งต่อไปนี้ในบรรทัดคำสั่งเคอร์เนลของคุณ:
kvm-arm.protected_modules= mod1 , mod2 , mod3 , ...
โมดูลผู้จำหน่าย pKVM ที่จัดเก็บไว้ใน initramfs
สืบทอดลายเซ็นและการป้องกันของ initramfs
หากโมดูลผู้จำหน่าย pKVM ตัวใดตัวหนึ่งไม่สามารถโหลดได้ ระบบจะถือว่าไม่ปลอดภัย และจะไม่สามารถเริ่มเครื่องเสมือนที่ได้รับการป้องกันได้
เรียกใช้ฟังก์ชัน EL2 (ไฮเปอร์ไวเซอร์) จาก EL2 (โมดูลเคอร์เนล)
การเรียกไฮเปอร์ไวเซอร์ (HVC) คือคำสั่งที่ให้เคอร์เนลเรียกไฮเปอร์ไวเซอร์ ด้วยการเปิดตัวโมดูลผู้จำหน่าย pKVM HVC สามารถใช้เพื่อเรียกฟังก์ชันให้ทำงานที่ EL2 (ในโมดูลไฮเปอร์ไวเซอร์) จาก EL1 (โมดูลเคอร์เนล):
ในโค้ด EL2 (
el2.c
) ให้ประกาศตัวจัดการ EL2:void pkvm_driver_hyp_hvc(struct kvm_cpu_context *ctx) { /* Handle the call */ cpu_reg(ctx, 1) = 0; }
ในโค้ด EL1 ของคุณ (
el1.c
) ให้ลงทะเบียนตัวจัดการ EL2 ในโมดูลผู้ขาย pKVM ของคุณ: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); 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);
ในรหัส EL1 ของคุณ (
el1.c
) ให้โทรหา HVC:pkvm_el2_mod_call(hvc_number);