تنفيذ وحدة مورِّد pKVM

تشرح هذه الصفحة كيفية تطبيق وحدة مورد جهاز افتراضي محمية تستند إلى نواة (pKVM). عند الانتهاء من هذه الخطوات، يُفترض أن يكون لديك شجرة دليل مشابهة لـ:

Makefile
el1.c
hyp/
    Makefile
    el2.c
  1. أضِف رمز برنامج Hypervisor (مراقب الأجهزة الظاهرية) 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;
    }
    

    واجهة برمجة تطبيقات وحدة مورِّد pKVM هي هيكلة تغلف استدعاءات وحدة برنامج pKVM Hypervisor Platform. تتبع هذه البنية قواعد ABI نفسها التي تستخدمها واجهات GKI.

  2. أنشِئ hyp/Makefile لإنشاء رمز برنامج Hypervisor (مراقب الأجهزة الظاهرية):

    hyp-obj-y := el2.o
    include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
    
  3. أضِف رمز النواة EL1 (el1.c). يجب أن يحتوي قسم init لهذا الرمز على طلب إلى pkvm_load_el2 module لتحميل رمز Hypervisor (مراقب 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);
    
  4. أخيرًا، أنشئ ملف 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) وعليك إضافة ما يلي إلى سطر أوامر kernel:

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

تكتسِب وحدات مورِّد pKVM المخزّنة في initramfs توقيع "initramfs" وحمايته.

إذا تعذَّر تحميل إحدى وحدات مورِّد pKVM، سيُعتبر النظام غير آمن ولن يكون من الممكن بدء تشغيل جهاز افتراضي محمي.

استدعاء دالة EL2 (الخوارزمية الفائقة) من EL2 (وحدة النواة)

استدعاء دالة Hypervisor Platform (HVC) هي تعليمات تتيح للنواة استدعاء برنامج Hypervisor (مراقب الأجهزة الظاهرية). مع طرح وحدات مورّد pKVM، يمكن استخدام HVC لاستدعاء دالة في EL2 (في وحدة Hypervisor) من EL1 (وحدة النواة):

  1. في رمز EL2 (el2.c)، يُرجى تعريف معالج EL2:

    void pkvm_driver_hyp_hvc(struct kvm_cpu_context *ctx)
    {
      /* Handle the call */
    
      cpu_reg(ctx, 1) = 0;
    }
    
  2. في رمز 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);
    
  3. في رمز EL1 (el1.c)، عليك استدعاء دالة HVC:

    pkvm_el2_mod_call(hvc_number);