Na tej stronie dowiesz się, jak wdrożyć moduł dostawcy chronionej maszyny wirtualnej opartej na jądrze (pKVM).
W przypadku wersji android16-6.12 i nowszych po wykonaniu tych czynności powinna być widoczna struktura katalogów podobna do tej:
BUILD.bazel
el1.c
hyp/
BUILD.bazel
el2.c
Pełny przykład znajdziesz w artykule Tworzenie modułu pKVM za pomocą DDK.
W przypadku Androida 15–6.6 i starszych:
Makefile
el1.c
hyp/
Makefile
el2.c
Dodaj kod hiperwizora EL2 (
el2.c
). Musi on zawierać co najmniej deklarację funkcji init, która akceptuje odwołanie do strukturypkvm_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; }
Interfejs API modułu dostawcy pKVM to struktura zawierająca wywołania zwrotne do hiperwizora pKVM. Ta struktura jest zgodna z tymi samymi regułami interfejsu ABI co interfejsy GKI.
Utwórz
hyp/Makefile
, aby skompilować kod hiperwizora:hyp-obj-y := el2.o include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
Dodaj kod jądra EL1 (
el1.c
). Sekcja inicjowania tego kodu musi zawierać wywołaniepkvm_load_el2 module
, aby wczytać kod hiperwizora EL2 z kroku 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);
Na koniec utwórz reguły kompilacji.
W przypadku Androida 16–6.12 i nowszych zapoznaj się z artykułem Tworzenie modułu pKVM za pomocą DDK, aby utworzyć
ddk_library()
dla EL2 iddk_module()
dla EL1.W przypadku Androida 15-6.6 i starszych wersji utwórz główny plik makefile, aby połączyć kod EL1 i 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
Wczytywanie modułu pKVM
Podobnie jak w przypadku modułów dostawcy GKI, moduły dostawcy pKVM można wczytywać za pomocą polecenia modprobe.
Ze względów bezpieczeństwa wczytywanie musi jednak nastąpić przed ograniczeniem uprawnień.
Aby załadować moduł pKVM, musisz się upewnić, że moduły są uwzględnione w głównym systemie plików (initramfs
), i dodać do wiersza poleceń jądra te elementy:
kvm-arm.protected_modules=mod1,mod2,mod3,...
Moduły dostawcy pKVM przechowywane w initramfs
dziedziczą podpis i ochronę initramfs
.
Jeśli nie uda się wczytać jednego z modułów dostawcy pKVM, system zostanie uznany za niezabezpieczony i nie będzie można uruchomić chronionej maszyny wirtualnej.
Wywoływanie funkcji EL2 (hiperwizora) z EL1 (modułu jądra)
Wywołanie hiperwizora (HVC) to instrukcja, która umożliwia jądru wywołanie hiperwizora. Wraz z wprowadzeniem modułów dostawcy pKVM wywołanie HVC może służyć do wywoływania funkcji do uruchomienia na poziomie EL2 (w module hipernadzorcy) z poziomu EL1 (w module jądra):
- W kodzie EL2 (
el2.c
) zadeklaruj moduł obsługi EL2:
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;
}
W kodzie EL1 (
el1.c
) zarejestruj moduł obsługi EL2 w module dostawcy 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); // 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);
W kodzie EL1 (
el1.c
) wywołaj HVC:pkvm_el2_mod_call(hvc_number);