একটি pKVM ভেন্ডর মডিউল প্রয়োগ করুন

এই পৃষ্ঠাটি ব্যাখ্যা করে কিভাবে একটি সুরক্ষিত কার্নেল-ভিত্তিক ভার্চুয়াল মেশিন (pKVM) ভেন্ডর মডিউল প্রয়োগ করতে হয়। যখন আপনি এই পদক্ষেপগুলি সম্পন্ন করেন, তখন আপনার অনুরূপ একটি ডিরেক্টরি গাছ থাকা উচিত:

Makefile
el1.c
hyp/
    Makefile
    el2.c
  1. EL2 হাইপারভাইজার কোড ( el2.c ) যোগ করুন। সর্বনিম্নভাবে, এই কোডটিকে অবশ্যই একটি init ফাংশন ঘোষণা করতে হবে যা pkvm_module_ops struct-এর একটি রেফারেন্স গ্রহণ করে:

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

    pKVM ভেন্ডর মডিউল API হল একটি struct encapsulating pKVM হাইপারভাইজারে কলব্যাক। এই কাঠামোটি GKI ইন্টারফেসের মতো একই ABI নিয়ম অনুসরণ করে।

  2. হাইপারভাইজার কোড তৈরি করতে hyp/Makefile তৈরি করুন:

    hyp-obj-y := el2.o
    include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
    
  3. EL1 কার্নেল কোড যোগ করুন ( el1.c )। ধাপ 1 থেকে EL2 হাইপারভাইজার কোড লোড করার জন্য এই কোডের init বিভাগে অবশ্যই pkvm_load_el2 module একটি কল থাকতে হবে।

    #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 মডিউল লোড করার জন্য, আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপনার মডিউলগুলি root ফাইল-সিস্টেমে ( initramfs ) অন্তর্ভুক্ত করা হয়েছে এবং আপনাকে অবশ্যই আপনার কার্নেল কমান্ড-লাইনে নিম্নলিখিতগুলি যোগ করতে হবে:

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

initramfs এ সংরক্ষিত pKVM ভেন্ডর মডিউলগুলি initramfs এর স্বাক্ষর ও সুরক্ষার উত্তরাধিকারী হয়।

pKVM ভেন্ডর মডিউলগুলির একটি লোড করতে ব্যর্থ হলে, সিস্টেমটিকে অনিরাপদ বলে মনে করা হয় এবং এটি একটি সুরক্ষিত ভার্চুয়াল মেশিন চালু করা সম্ভব হবে না।

EL2 (কার্ণেল মডিউল) থেকে একটি EL2 (হাইপারভাইজার) ফাংশন কল করুন

একটি হাইপারভাইজার কল (HVC) হল একটি নির্দেশ যা কার্নেলকে হাইপারভাইজারকে কল করতে দেয়। pKVM ভেন্ডর মডিউলের প্রবর্তনের সাথে, EL1 (কার্নেল মডিউল) থেকে EL2 (হাইপারভাইজার মডিউলে) চালানোর জন্য একটি ফাংশন কল করার জন্য একটি HVC ব্যবহার করা যেতে পারে:

  1. EL2 কোডে ( el2.c ), EL2 হ্যান্ডলার ঘোষণা করুন:

অ্যান্ড্রয়েড-14

  void pkvm_driver_hyp_hvc(struct kvm_cpu_context *ctx)
  {
    /* Handle the call */

    cpu_reg(ctx, 1) = 0;
  }

অ্যান্ড্রয়েড-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 ), HVC-কে কল করুন:

    pkvm_el2_mod_call(hvc_number);
    
,

এই পৃষ্ঠাটি ব্যাখ্যা করে কিভাবে একটি সুরক্ষিত কার্নেল-ভিত্তিক ভার্চুয়াল মেশিন (pKVM) ভেন্ডর মডিউল প্রয়োগ করতে হয়। যখন আপনি এই পদক্ষেপগুলি সম্পন্ন করেন, তখন আপনার অনুরূপ একটি ডিরেক্টরি গাছ থাকা উচিত:

Makefile
el1.c
hyp/
    Makefile
    el2.c
  1. EL2 হাইপারভাইজার কোড ( el2.c ) যোগ করুন। সর্বনিম্নভাবে, এই কোডটিকে অবশ্যই একটি init ফাংশন ঘোষণা করতে হবে যা pkvm_module_ops struct-এর একটি রেফারেন্স গ্রহণ করে:

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

    pKVM ভেন্ডর মডিউল API হল একটি struct encapsulating pKVM হাইপারভাইজারে কলব্যাক। এই কাঠামোটি GKI ইন্টারফেসের মতো একই ABI নিয়ম অনুসরণ করে।

  2. হাইপারভাইজার কোড তৈরি করতে hyp/Makefile তৈরি করুন:

    hyp-obj-y := el2.o
    include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
    
  3. EL1 কার্নেল কোড যোগ করুন ( el1.c )। ধাপ 1 থেকে EL2 হাইপারভাইজার কোড লোড করার জন্য এই কোডের init বিভাগে অবশ্যই pkvm_load_el2 module একটি কল থাকতে হবে।

    #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 মডিউল লোড করার জন্য, আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপনার মডিউলগুলি root ফাইল-সিস্টেমে ( initramfs ) অন্তর্ভুক্ত করা হয়েছে এবং আপনাকে অবশ্যই আপনার কার্নেল কমান্ড-লাইনে নিম্নলিখিতগুলি যোগ করতে হবে:

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

initramfs এ সংরক্ষিত pKVM ভেন্ডর মডিউলগুলি initramfs এর স্বাক্ষর ও সুরক্ষার উত্তরাধিকারী হয়।

pKVM ভেন্ডর মডিউলগুলির একটি লোড করতে ব্যর্থ হলে, সিস্টেমটিকে অনিরাপদ বলে মনে করা হয় এবং এটি একটি সুরক্ষিত ভার্চুয়াল মেশিন চালু করা সম্ভব হবে না।

EL2 (কার্ণেল মডিউল) থেকে একটি EL2 (হাইপারভাইজার) ফাংশন কল করুন

একটি হাইপারভাইজার কল (HVC) হল একটি নির্দেশ যা কার্নেলকে হাইপারভাইজারকে কল করতে দেয়। pKVM ভেন্ডর মডিউলের প্রবর্তনের সাথে, EL1 (কার্নেল মডিউল) থেকে EL2 (হাইপারভাইজার মডিউলে) চালানোর জন্য একটি ফাংশন কল করার জন্য একটি HVC ব্যবহার করা যেতে পারে:

  1. EL2 কোডে ( el2.c ), EL2 হ্যান্ডলার ঘোষণা করুন:

অ্যান্ড্রয়েড-14

  void pkvm_driver_hyp_hvc(struct kvm_cpu_context *ctx)
  {
    /* Handle the call */

    cpu_reg(ctx, 1) = 0;
  }

অ্যান্ড্রয়েড-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 ), HVC-কে কল করুন:

    pkvm_el2_mod_call(hvc_number);