[PATCH v5 13/13] ARM: KVM: Support SMP guests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch is a beginning attempt to support SMP guests. So far we only
add locking for the second stage PGD stored on the kvm_arch struct.

WARNING: This code is untested and does not yet support SMP guests.

Signed-off-by: Christoffer Dall <c.dall@xxxxxxxxxxxxxxxxxxxxxx>
---
 arch/arm/include/asm/kvm_host.h |   12 ++++++--
 arch/arm/kvm/arm.c              |    1 +
 arch/arm/kvm/mmu.c              |   57 +++++++++++++++++++++++++--------------
 3 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 7fcc412..555a6f1 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -31,9 +31,15 @@ struct kvm_vcpu;
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 
 struct kvm_arch {
-	u32    vmid;	/* The VMID used for the virt. memory system */
-	pgd_t *pgd;	/* 1-level 2nd stage table */
-	u64    vttbr;	/* VTTBR value associated with above pgd and vmid */
+	/* The VMID used for the virt. memory system */
+	u32    vmid;
+
+	/* 1-level 2nd stage table and lock */
+	struct mutex pgd_mutex;
+	pgd_t *pgd;
+
+	/* VTTBR value associated with above pgd and vmid */
+	u64    vttbr;
 };
 
 #define EXCEPTION_NONE      0
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 9c5c38e..14ccc4d 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -119,6 +119,7 @@ int kvm_arch_init_vm(struct kvm *kvm)
 	ret = kvm_alloc_stage2_pgd(kvm);
 	if (ret)
 		goto out_fail_alloc;
+	mutex_init(&kvm->arch.pgd_mutex);
 
 	pgd_phys = virt_to_phys(kvm->arch.pgd);
 	kvm->arch.vttbr = pgd_phys & ((1LLU << 40) - 1) & ~((2 << VTTBR_X) - 1);
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 50c9571..baeb8a1 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -177,6 +177,9 @@ out:
  * Allocates the 1st level table only of size defined by PGD2_ORDER (can
  * support either full 40-bit input addresses or limited to 32-bit input
  * addresses). Clears the allocated pages.
+ *
+ * Note we don't need locking here as this is only called when the VM is
+ * destroyed, which can only be done once.
  */
 int kvm_alloc_stage2_pgd(struct kvm *kvm)
 {
@@ -204,6 +207,9 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
  * Walks the level-1 page table pointed to by kvm->arch.pgd and frees all
  * underlying level-2 and level-3 tables before freeing the actual level-1 table
  * and setting the struct pointer to NULL.
+ *
+ * Note we don't need locking here as this is only called when the VM is
+ * destroyed, which can only be done once.
  */
 void kvm_free_stage2_pgd(struct kvm *kvm)
 {
@@ -239,49 +245,38 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
 	kvm->arch.pgd = NULL;
 }
 
-static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
-			  gfn_t gfn, struct kvm_memory_slot *memslot)
+static int __user_mem_abort(struct kvm *kvm, phys_addr_t addr, pfn_t pfn)
 {
-	pfn_t pfn;
 	pgd_t *pgd;
 	pud_t *pud;
 	pmd_t *pmd;
 	pte_t *pte, new_pte;
 
-	pfn = gfn_to_pfn(vcpu->kvm, gfn);
-
-	if (is_error_pfn(pfn)) {
-		kvm_err(-EFAULT, "Guest gfn %u (0x%08lx) does not have "
-				"corresponding host mapping",
-				gfn, gfn << PAGE_SHIFT);
-		return -EFAULT;
-	}
-
 	/* Create 2nd stage page table mapping - Level 1 */
-	pgd = vcpu->kvm->arch.pgd + pgd_index(fault_ipa);
-	pud = pud_offset(pgd, fault_ipa);
+	pgd = kvm->arch.pgd + pgd_index(addr);
+	pud = pud_offset(pgd, addr);
 	if (pud_none(*pud)) {
-		pmd = pmd_alloc_one(NULL, fault_ipa);
+		pmd = pmd_alloc_one(NULL, addr);
 		if (!pmd) {
 			kvm_err(-ENOMEM, "Cannot allocate 2nd stage pmd");
 			return -ENOMEM;
 		}
 		pud_populate(NULL, pud, pmd);
-		pmd += pmd_index(fault_ipa);
+		pmd += pmd_index(addr);
 	} else
-		pmd = pmd_offset(pud, fault_ipa);
+		pmd = pmd_offset(pud, addr);
 
 	/* Create 2nd stage page table mapping - Level 2 */
 	if (pmd_none(*pmd)) {
-		pte = pte_alloc_one_kernel(NULL, fault_ipa);
+		pte = pte_alloc_one_kernel(NULL, addr);
 		if (!pte) {
 			kvm_err(-ENOMEM, "Cannot allocate 2nd stage pte");
 			return -ENOMEM;
 		}
 		pmd_populate_kernel(NULL, pmd, pte);
-		pte += pte_index(fault_ipa);
+		pte += pte_index(addr);
 	} else
-		pte = pte_offset_kernel(pmd, fault_ipa);
+		pte = pte_offset_kernel(pmd, addr);
 
 	/* Create 2nd stage page table mapping - Level 3 */
 	new_pte = pfn_pte(pfn, PAGE_KVM_GUEST);
@@ -290,6 +285,28 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	return 0;
 }
 
+static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+			  gfn_t gfn, struct kvm_memory_slot *memslot)
+{
+	pfn_t pfn;
+	int ret;
+
+	pfn = gfn_to_pfn(vcpu->kvm, gfn);
+
+	if (is_error_pfn(pfn)) {
+		kvm_err(-EFAULT, "Guest gfn %u (0x%08lx) does not have "
+				"corresponding host mapping",
+				gfn, gfn << PAGE_SHIFT);
+		return -EFAULT;
+	}
+
+	mutex_lock(&vcpu->kvm->arch.pgd_mutex);
+	ret = __user_mem_abort(vcpu->kvm, fault_ipa, pfn);
+	mutex_unlock(&vcpu->kvm->arch.pgd_mutex);
+
+	return ret;
+}
+
 /**
  * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
  * @vcpu: The VCPU pointer

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux