pKVM tedarikçi modülü uygulama

Bu sayfada, korumalı çekirdek tabanlı sanal makine (pKVM) satıcı modülünün nasıl uygulanacağı açıklanmaktadır.

android16-6.12 ve sonraki sürümlerde bu adımları tamamladığınızda şuna benzer bir dizin ağacınız olmalıdır:

BUILD.bazel
el1.c
hyp/
    BUILD.bazel
    el2.c

Eksiksiz bir örnek için DDK ile pKVM modülü oluşturma başlıklı makaleyi inceleyin .

Android 15-6.6 ve önceki sürümler için:

Makefile
el1.c
hyp/
    Makefile
    el2.c
  1. EL2 hiper yönetici kodunu (el2.c) ekleyin. Bu kod, en azından pkvm_module_ops yapısına referans kabul eden bir init işlevi bildirmelidir:

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

    pKVM satıcı modülü API'si, pKVM hipervizörüne geri çağırmaları kapsayan bir yapıdır. Bu yapı, GKI arayüzleriyle aynı ABI kurallarını izler.

  2. Hiper yönetici kodunu oluşturmak için hyp/Makefile 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ü, 1. adımdaki EL2 hiper yönetici kodunu yüklemek için pkvm_load_el2 module çağrısını içermelidir.

    #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, derleme kurallarını oluşturun.

    android16-6.12 ve sonraki sürümlerde, EL2 için ddk_library(), EL1 için ddk_module() oluşturmak üzere DDK ile pKVM modülü oluşturma başlıklı makaleyi inceleyin.

    android15-6.6 ve önceki sürümlerde, EL1 ve EL2 kodunu birbirine bağlamak için kök makefile'ı 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 satıcı modüllerinde olduğu gibi, pKVM satıcı modülleri de modprobe kullanılarak yüklenebilir. Ancak güvenlik nedeniyle, ayrıcalık kaldırma işleminden önce yükleme yapılması gerekir. 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 saklanan pKVM satıcı modülleri, initramfs'nın imzasını ve korumasını devralır.

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

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

Hipervizör çağrısı (HVC), çekirdeğin hipervizörü çağırmasına olanak tanıyan bir talimattır. pKVM satıcı modüllerinin kullanıma sunulmasıyla birlikte, EL1'den (çekirdek modülü) EL2'de (hiper yönetici modülünde) çalıştırılacak bir işlev çağrısı yapmak için HVC kullanılabilir:

  1. EL2 kodunda (el2.c) EL2 işleyicisini bildirin:

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), pKVM tedarikçi modülünüzde EL2 işleyicisini 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);