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

    pKVM वेंडर मॉड्यूल एपीआई एक ऐसा स्ट्रक्चर है, जो pKVM Hypervisor को कॉलबैक इनकैप्सुलेट करता है. यह स्ट्रक्चर, एबीआई के उन ही नियमों का पालन करता है जो जीकेआई इंटरफ़ेस में होते हैं.

  2. हायपरवाइज़र कोड बनाने के लिए, hyp/Makefile बनाएं:

    hyp-obj-y := el2.o
    include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
    
  3. EL1 कर्नेल कोड (el1.c) जोड़ें. इस कोड के init सेक्शन में, pkvm_load_el2 module को कॉल किया जाना ज़रूरी है, ताकि पहले चरण से EL2 हाइपरवाइज़र कोड लोड किया जा सके.

    #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) में शामिल हों. साथ ही, आपको अपने कर्नेल कमांड-लाइन में ये चीज़ें जोड़नी होंगी:

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

initramfs में सेव किए गए pKVM वेंडर मॉड्यूल, initramfs के हस्ताक्षर और सुरक्षा को इनहेरिट करते हैं.

अगर pKVM वेंडर का कोई मॉड्यूल लोड नहीं होता है, तो सिस्टम को असुरक्षित माना जाता है. साथ ही, सुरक्षित वर्चुअल मशीन को शुरू नहीं किया जा सकेगा.

EL2 (कर्नेल मॉड्यूल) से EL2 (हायपरवाइज़र) फ़ंक्शन को कॉल करें

हाइपरवाइजर कॉल (एचवीसी) एक ऐसा निर्देश है जिसकी मदद से, कर्नेल को हाइपरवाइजर को कॉल करने की अनुमति मिलती है. pKVM वेंडर मॉड्यूल की शुरुआत होने के बाद, EL1 (कर्नेल मॉड्यूल में) से EL2 (हाइपरवाइज़र मॉड्यूल में) पर फ़ंक्शन चलाने के लिए, एचवीसी का इस्तेमाल किया जा सकता है:

  1. EL2 कोड (el2.c) में, EL2 हैंडलर का एलान करें:

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 कोड (el1.c) में, pKVM वेंडर मॉड्यूल में EL2 हैंडलर रजिस्टर करें:

    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 कोड (el1.c) में, एचवीसी को कॉल करें:

    pkvm_el2_mod_call(hvc_number);