הטמעת מודול ספק pKVM

דף זה מסביר כיצד ליישם מודול ספק מוגן מבוסס ליבה (pKVM). כשתסיים עם השלבים האלה, אמור להיות לך עץ ספריות הדומה ל:

Makefile
el1.c
hyp/
    Makefile
    el2.c
  1. הוסף את קוד ההיפרוויזר 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 hypervisor. מבנה זה עוקב אחר אותם כללי 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 כדי לטעון את קוד ההיפרוויזר 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 ) ועליך להוסיף את הדברים הבאים לשורת הפקודה של הליבה שלך:

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

מודולי ספק pKVM המאוחסנים ב- initramfs יורשים את החתימה וההגנה של initramfs .

אם אחד ממודולי ספקי pKVM נכשל בטעינת המערכת, המערכת נחשבת לא מאובטחת ולא ניתן יהיה להפעיל מכונה וירטואלית מוגנת.

קרא לפונקציית EL2 (hypervisor) מ-EL2 (מודול ליבה)

קריאת hypervisor (HVC) היא הוראה המאפשרת לקרנל לקרוא ל-hypervisor. עם הצגת מודולי ספקי pKVM, ניתן להשתמש ב-HVC כדי לקרוא לפונקציה לפעול ב-EL2 (במודול היפרוויזר) מ-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);