تنفيذ وحدة بائع pKVM

تشرح هذه الصفحة كيفية تنفيذ وحدة بائع الجهاز الظاهري المحمي القائم على kernel (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;
    }
    

    واجهة برمجة التطبيقات (API) لوحدة بائع pKVM عبارة عن بنية تتضمن عمليات الاسترجاعات إلى برنامج مراقبة الأجهزة الافتراضية pKVM. تتبع هذه البنية نفس قواعد 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. وأخيرًا، أنشئ ملف تعريف الجذر لربط كود 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 (برنامج Hypervisor) من EL2 (وحدة النواة)

استدعاء برنامج Hypervisor (HVC) عبارة عن تعليمات تسمح للنواة باستدعاء برنامج Hypervisor. مع تقديم وحدات بائع pKVM، يمكن استخدام HVC لاستدعاء وظيفة يتم تشغيلها في EL2 (في وحدة برنامج Hypervisor) من EL1 (وحدة kernel):

  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);