KVM: arm64: Consolidate stage-2 initialisation into a single function
authorQuentin Perret <qperret@google.com>
Thu, 10 Nov 2022 19:02:51 +0000 (19:02 +0000)
committerMarc Zyngier <maz@kernel.org>
Fri, 11 Nov 2022 17:16:25 +0000 (17:16 +0000)
The initialisation of guest stage-2 page-tables is currently split
across two functions: kvm_init_stage2_mmu() and kvm_arm_setup_stage2().
That is presumably for historical reasons as kvm_arm_setup_stage2()
originates from the (now defunct) KVM port for 32-bit Arm.

Simplify this code path by merging both functions into one, taking care
to map the 'struct kvm' into the hypervisor stage-1 early on in order to
simplify the failure path.

Tested-by: Vincent Donnefort <vdonnefort@google.com>
Co-developed-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Quentin Perret <qperret@google.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20221110190259.26861-19-will@kernel.org
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/kvm/arm.c
arch/arm64/kvm/mmu.c
arch/arm64/kvm/reset.c

index 8aa8492..89e6358 100644 (file)
  * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
  * not known to exist and will break with this configuration.
  *
- * The VTCR_EL2 is configured per VM and is initialised in kvm_arm_setup_stage2().
+ * The VTCR_EL2 is configured per VM and is initialised in kvm_init_stage2_mmu.
  *
  * Note that when using 4K pages, we concatenate two first level page tables
  * together. With 16K pages, we concatenate 16 first level page tables.
index 835987e..57218f0 100644 (file)
@@ -990,8 +990,6 @@ int kvm_set_ipa_limit(void);
 #define __KVM_HAVE_ARCH_VM_ALLOC
 struct kvm *kvm_arch_alloc_vm(void);
 
-int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
-
 static inline bool kvm_vm_is_protected(struct kvm *kvm)
 {
        return false;
index 7784081..e4a7e63 100644 (file)
@@ -166,7 +166,7 @@ int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size,
 void free_hyp_pgds(void);
 
 void stage2_unmap_vm(struct kvm *kvm);
-int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu);
+int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type);
 void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu);
 int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
                          phys_addr_t pa, unsigned long size, bool writable);
index d99e93e..f78eefa 100644 (file)
@@ -139,28 +139,24 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
        int ret;
 
-       ret = kvm_arm_setup_stage2(kvm, type);
-       if (ret)
-               return ret;
-
-       ret = kvm_init_stage2_mmu(kvm, &kvm->arch.mmu);
-       if (ret)
-               return ret;
-
        ret = kvm_share_hyp(kvm, kvm + 1);
        if (ret)
-               goto out_free_stage2_pgd;
+               return ret;
 
        ret = pkvm_init_host_vm(kvm);
        if (ret)
-               goto out_free_stage2_pgd;
+               goto err_unshare_kvm;
 
        if (!zalloc_cpumask_var(&kvm->arch.supported_cpus, GFP_KERNEL)) {
                ret = -ENOMEM;
-               goto out_free_stage2_pgd;
+               goto err_unshare_kvm;
        }
        cpumask_copy(kvm->arch.supported_cpus, cpu_possible_mask);
 
+       ret = kvm_init_stage2_mmu(kvm, &kvm->arch.mmu, type);
+       if (ret)
+               goto err_free_cpumask;
+
        kvm_vgic_early_init(kvm);
 
        /* The maximum number of VCPUs is limited by the host's GIC model */
@@ -169,9 +165,12 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        set_default_spectre(kvm);
        kvm_arm_init_hypercalls(kvm);
 
-       return ret;
-out_free_stage2_pgd:
-       kvm_free_stage2_pgd(&kvm->arch.mmu);
+       return 0;
+
+err_free_cpumask:
+       free_cpumask_var(kvm->arch.supported_cpus);
+err_unshare_kvm:
+       kvm_unshare_hyp(kvm, kvm + 1);
        return ret;
 }
 
index 1806116..3e56c63 100644 (file)
@@ -675,15 +675,40 @@ static struct kvm_pgtable_mm_ops kvm_s2_mm_ops = {
  * kvm_init_stage2_mmu - Initialise a S2 MMU structure
  * @kvm:       The pointer to the KVM structure
  * @mmu:       The pointer to the s2 MMU structure
+ * @type:      The machine type of the virtual machine
  *
  * Allocates only the stage-2 HW PGD level table(s).
  * Note we don't need locking here as this is only called when the VM is
  * created, which can only be done once.
  */
-int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu)
+int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type)
 {
+       u32 kvm_ipa_limit = get_kvm_ipa_limit();
        int cpu, err;
        struct kvm_pgtable *pgt;
+       u64 mmfr0, mmfr1;
+       u32 phys_shift;
+
+       if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+               return -EINVAL;
+
+       phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
+       if (phys_shift) {
+               if (phys_shift > kvm_ipa_limit ||
+                   phys_shift < ARM64_MIN_PARANGE_BITS)
+                       return -EINVAL;
+       } else {
+               phys_shift = KVM_PHYS_SHIFT;
+               if (phys_shift > kvm_ipa_limit) {
+                       pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n",
+                                    current->comm);
+                       return -EINVAL;
+               }
+       }
+
+       mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+       mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
+       kvm->arch.vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift);
 
        if (mmu->pgt != NULL) {
                kvm_err("kvm_arch already initialized?\n");
index 5ae1847..e0267f6 100644 (file)
@@ -395,32 +395,3 @@ int kvm_set_ipa_limit(void)
 
        return 0;
 }
-
-int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
-{
-       u64 mmfr0, mmfr1;
-       u32 phys_shift;
-
-       if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
-               return -EINVAL;
-
-       phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type);
-       if (phys_shift) {
-               if (phys_shift > kvm_ipa_limit ||
-                   phys_shift < ARM64_MIN_PARANGE_BITS)
-                       return -EINVAL;
-       } else {
-               phys_shift = KVM_PHYS_SHIFT;
-               if (phys_shift > kvm_ipa_limit) {
-                       pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n",
-                                    current->comm);
-                       return -EINVAL;
-               }
-       }
-
-       mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
-       mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
-       kvm->arch.vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift);
-
-       return 0;
-}