pKVM tedarikçi firma modülünü uygulama

Bu sayfada, korumalı çekirdek tabanlı sanal makine (pKVM) tedarikçi modülünün nasıl uygulanacağı açıklanmaktadır. Bu adımları tamamladığınızda aşağıdaki gibi bir dizin ağacınız olmalıdır:

Makefile
el1.c
hyp/
    Makefile
    el2.c
  1. EL2 hipervizör kodunu (el2.c) ekleyin. Bu kodda en azından pkvm_module_ops yapısına referans kabul eden bir init işlevi tanımlanmalıdır:

    #include <asm/kvm_pkvm_module.h>
    
    int pkvm_driver_hyp_init(const struct pkvm_module_ops *ops)
    {
      /* Init the EL2 code */
    
      return 0;
    }
    

    pKVM tedarikçi modülü API'si, pKVM hipervizörüne geri çağrıları kapsayan bir yapıdır. Bu yapı, GKI arayüzleriyle aynı ABI kurallarına uyar.

  2. Hipervizör kodunu oluşturmak için hyp/Makefile dosyasını oluşturun:

    hyp-obj-y := el2.o
    include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
    
  3. EL1 çekirdek kodunu (el1.c) ekleyin. Bu kodun init bölümünde, 1. adımdaki EL2 hipervizör kodunu yüklemek için pkvm_load_el2 module çağrısı bulunmalıdır.

    #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);
    
  4. Son olarak, EL1 ve EL2 kodunu birbirine bağlamak için kök makefile'i oluşturun:

    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 modülü yükleme

GKI tedarikçi modüllerinde olduğu gibi, pKVM tedarikçi modülleri modprobe kullanılarak yüklenebilir. Ancak, güvenlik nedeniyle, yükleme ayrıcalığı kaldırılmadan önce gerçekleşmelidir. pKVM modülü yüklemek için modüllerinizin kök dosya sistemine (initramfs) dahil edildiğinden emin olmanız ve çekirdek komut satırınıza aşağıdakileri eklemeniz gerekir:

kvm-arm.protected_modules=mod1,mod2,mod3,...

initramfs içinde depolanan pKVM tedarikçi modülleri, initramfs imzasını ve korumasını devralır.

pKVM tedarikçi modüllerinden biri yüklenemezse sistem güvenli kabul edilmez ve korumalı bir sanal makine başlatılamaz.

EL2'den (çekirdek modülü) bir EL2 (hipervizör) işlevi çağırma

Hipervizör çağrısı (HVC), çekirdeğin hipervizörü çağırmasına olanak tanıyan bir talimattır. pKVM tedarikçi modüllerinin kullanıma sunulmasıyla birlikte, bir HVC, EL1'den (çekirdek modülü) EL2'de (hiyerarşik sanallaştırıcı modülü) çalışacak bir işlevi çağırmak için kullanılabilir:

  1. EL2 kodunda (el2.c) EL2 işleyicisini tanımlayın:

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;
  }
  1. EL1 kodunuzda (el1.c), EL2 işleyicisini pKVM tedarikçi modülünüze kaydedin:

    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);
    
  2. EL1 kodunuzda (el1.c) HVC'yi arayın:

    pkvm_el2_mod_call(hvc_number);