kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Christoffer Dall <christoffer.dall@linaro.org>
To: Paolo Bonzini <pbonzini@redhat.com>, Gleb Natapov <gleb@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org,
	kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org,
	Christoffer Dall <christoffer.dall@linaro.org>
Subject: [GIT PULL 03/51] arm/arm64: KVM: Fix and refactor unmap_range
Date: Mon,  4 Aug 2014 10:46:20 +0200	[thread overview]
Message-ID: <1407142028-31105-4-git-send-email-christoffer.dall@linaro.org> (raw)
In-Reply-To: <1407142028-31105-1-git-send-email-christoffer.dall@linaro.org>

unmap_range() was utterly broken, to quote Marc, and broke in all sorts
of situations.  It was also quite complicated to follow and didn't
follow the usual scheme of having a separate iterating function for each
level of page tables.

Address this by refactoring the code and introduce a pgd_clear()
function.

Reviewed-by: Jungseok Lee <jays.lee@samsung.com>
Reviewed-by: Mario Smarduch <m.smarduch@samsung.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/include/asm/kvm_mmu.h   |  12 +++
 arch/arm/kvm/mmu.c               | 157 +++++++++++++++++++++------------------
 arch/arm64/include/asm/kvm_mmu.h |  15 ++++
 3 files changed, 111 insertions(+), 73 deletions(-)

diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 5c7aa3c..5cc0b0f 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -127,6 +127,18 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
 	(__boundary - 1 < (end) - 1)? __boundary: (end);		\
 })
 
+static inline bool kvm_page_empty(void *ptr)
+{
+	struct page *ptr_page = virt_to_page(ptr);
+	return page_count(ptr_page) == 1;
+}
+
+
+#define kvm_pte_table_empty(ptep) kvm_page_empty(ptep)
+#define kvm_pmd_table_empty(pmdp) kvm_page_empty(pmdp)
+#define kvm_pud_table_empty(pudp) (0)
+
+
 struct kvm;
 
 #define kvm_flush_dcache_to_poc(a,l)	__cpuc_flush_dcache_area((a), (l))
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 16f8049..2336061 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -90,104 +90,115 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
 	return p;
 }
 
-static bool page_empty(void *ptr)
+static void clear_pgd_entry(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr)
 {
-	struct page *ptr_page = virt_to_page(ptr);
-	return page_count(ptr_page) == 1;
+	pud_t *pud_table __maybe_unused = pud_offset(pgd, 0);
+	pgd_clear(pgd);
+	kvm_tlb_flush_vmid_ipa(kvm, addr);
+	pud_free(NULL, pud_table);
+	put_page(virt_to_page(pgd));
 }
 
 static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr)
 {
-	if (pud_huge(*pud)) {
-		pud_clear(pud);
-		kvm_tlb_flush_vmid_ipa(kvm, addr);
-	} else {
-		pmd_t *pmd_table = pmd_offset(pud, 0);
-		pud_clear(pud);
-		kvm_tlb_flush_vmid_ipa(kvm, addr);
-		pmd_free(NULL, pmd_table);
-	}
+	pmd_t *pmd_table = pmd_offset(pud, 0);
+	VM_BUG_ON(pud_huge(*pud));
+	pud_clear(pud);
+	kvm_tlb_flush_vmid_ipa(kvm, addr);
+	pmd_free(NULL, pmd_table);
 	put_page(virt_to_page(pud));
 }
 
 static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr)
 {
-	if (kvm_pmd_huge(*pmd)) {
-		pmd_clear(pmd);
-		kvm_tlb_flush_vmid_ipa(kvm, addr);
-	} else {
-		pte_t *pte_table = pte_offset_kernel(pmd, 0);
-		pmd_clear(pmd);
-		kvm_tlb_flush_vmid_ipa(kvm, addr);
-		pte_free_kernel(NULL, pte_table);
-	}
+	pte_t *pte_table = pte_offset_kernel(pmd, 0);
+	VM_BUG_ON(kvm_pmd_huge(*pmd));
+	pmd_clear(pmd);
+	kvm_tlb_flush_vmid_ipa(kvm, addr);
+	pte_free_kernel(NULL, pte_table);
 	put_page(virt_to_page(pmd));
 }
 
-static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr)
+static void unmap_ptes(struct kvm *kvm, pmd_t *pmd,
+		       phys_addr_t addr, phys_addr_t end)
 {
-	if (pte_present(*pte)) {
-		kvm_set_pte(pte, __pte(0));
-		put_page(virt_to_page(pte));
-		kvm_tlb_flush_vmid_ipa(kvm, addr);
-	}
+	phys_addr_t start_addr = addr;
+	pte_t *pte, *start_pte;
+
+	start_pte = pte = pte_offset_kernel(pmd, addr);
+	do {
+		if (!pte_none(*pte)) {
+			kvm_set_pte(pte, __pte(0));
+			put_page(virt_to_page(pte));
+			kvm_tlb_flush_vmid_ipa(kvm, addr);
+		}
+	} while (pte++, addr += PAGE_SIZE, addr != end);
+
+	if (kvm_pte_table_empty(start_pte))
+		clear_pmd_entry(kvm, pmd, start_addr);
 }
 
-static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
-			unsigned long long start, u64 size)
+static void unmap_pmds(struct kvm *kvm, pud_t *pud,
+		       phys_addr_t addr, phys_addr_t end)
 {
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *pte;
-	unsigned long long addr = start, end = start + size;
-	u64 next;
+	phys_addr_t next, start_addr = addr;
+	pmd_t *pmd, *start_pmd;
 
-	while (addr < end) {
-		pgd = pgdp + pgd_index(addr);
-		pud = pud_offset(pgd, addr);
-		pte = NULL;
-		if (pud_none(*pud)) {
-			addr = kvm_pud_addr_end(addr, end);
-			continue;
-		}
-
-		if (pud_huge(*pud)) {
-			/*
-			 * If we are dealing with a huge pud, just clear it and
-			 * move on.
-			 */
-			clear_pud_entry(kvm, pud, addr);
-			addr = kvm_pud_addr_end(addr, end);
-			continue;
+	start_pmd = pmd = pmd_offset(pud, addr);
+	do {
+		next = kvm_pmd_addr_end(addr, end);
+		if (!pmd_none(*pmd)) {
+			if (kvm_pmd_huge(*pmd)) {
+				pmd_clear(pmd);
+				kvm_tlb_flush_vmid_ipa(kvm, addr);
+				put_page(virt_to_page(pmd));
+			} else {
+				unmap_ptes(kvm, pmd, addr, next);
+			}
 		}
+	} while (pmd++, addr = next, addr != end);
 
-		pmd = pmd_offset(pud, addr);
-		if (pmd_none(*pmd)) {
-			addr = kvm_pmd_addr_end(addr, end);
-			continue;
-		}
+	if (kvm_pmd_table_empty(start_pmd))
+		clear_pud_entry(kvm, pud, start_addr);
+}
 
-		if (!kvm_pmd_huge(*pmd)) {
-			pte = pte_offset_kernel(pmd, addr);
-			clear_pte_entry(kvm, pte, addr);
-			next = addr + PAGE_SIZE;
-		}
+static void unmap_puds(struct kvm *kvm, pgd_t *pgd,
+		       phys_addr_t addr, phys_addr_t end)
+{
+	phys_addr_t next, start_addr = addr;
+	pud_t *pud, *start_pud;
 
-		/*
-		 * If the pmd entry is to be cleared, walk back up the ladder
-		 */
-		if (kvm_pmd_huge(*pmd) || (pte && page_empty(pte))) {
-			clear_pmd_entry(kvm, pmd, addr);
-			next = kvm_pmd_addr_end(addr, end);
-			if (page_empty(pmd) && !page_empty(pud)) {
-				clear_pud_entry(kvm, pud, addr);
-				next = kvm_pud_addr_end(addr, end);
+	start_pud = pud = pud_offset(pgd, addr);
+	do {
+		next = kvm_pud_addr_end(addr, end);
+		if (!pud_none(*pud)) {
+			if (pud_huge(*pud)) {
+				pud_clear(pud);
+				kvm_tlb_flush_vmid_ipa(kvm, addr);
+				put_page(virt_to_page(pud));
+			} else {
+				unmap_pmds(kvm, pud, addr, next);
 			}
 		}
+	} while (pud++, addr = next, addr != end);
 
-		addr = next;
-	}
+	if (kvm_pud_table_empty(start_pud))
+		clear_pgd_entry(kvm, pgd, start_addr);
+}
+
+
+static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
+			phys_addr_t start, u64 size)
+{
+	pgd_t *pgd;
+	phys_addr_t addr = start, end = start + size;
+	phys_addr_t next;
+
+	pgd = pgdp + pgd_index(addr);
+	do {
+		next = kvm_pgd_addr_end(addr, end);
+		unmap_puds(kvm, pgd, addr, next);
+	} while (pgd++, addr = next, addr != end);
 }
 
 static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 7d29847..8e138c7 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -125,6 +125,21 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
 #define kvm_pud_addr_end(addr, end)	pud_addr_end(addr, end)
 #define kvm_pmd_addr_end(addr, end)	pmd_addr_end(addr, end)
 
+static inline bool kvm_page_empty(void *ptr)
+{
+	struct page *ptr_page = virt_to_page(ptr);
+	return page_count(ptr_page) == 1;
+}
+
+#define kvm_pte_table_empty(ptep) kvm_page_empty(ptep)
+#ifndef CONFIG_ARM64_64K_PAGES
+#define kvm_pmd_table_empty(pmdp) kvm_page_empty(pmdp)
+#else
+#define kvm_pmd_table_empty(pmdp) (0)
+#endif
+#define kvm_pud_table_empty(pudp) (0)
+
+
 struct kvm;
 
 #define kvm_flush_dcache_to_poc(a,l)	__flush_dcache_area((a), (l))
-- 
2.0.0


  parent reply	other threads:[~2014-08-04  8:47 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-04  8:46 [GIT PULL 00/51] KVM/ARM updates for 3.17 Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 01/51] irqchip: gic: Move some bits of GICv2 to a library-type file Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 02/51] irqchip: gic-v3: Initial support for GICv3 Christoffer Dall
2014-08-04  8:46 ` Christoffer Dall [this message]
2014-08-04  8:46 ` [GIT PULL 04/51] ARM: KVM: Unmap IPA on memslot delete/move Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 05/51] ARM: KVM: user_mem_abort: support stage 2 MMIO page mapping Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 06/51] arm64: KVM: export demux regids as KVM_REG_ARM64 Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 07/51] arm64: KVM: allow export and import of generic timer regs Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 08/51] arm64: GICv3 device tree binding documentation Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 09/51] arm64: boot protocol documentation update for GICv3 Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 10/51] KVM: arm/arm64: vgic: move GICv2 registers to their own structure Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 11/51] KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 12/51] KVM: ARM: vgic: abstract access to the ELRSR bitmap Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 13/51] KVM: ARM: vgic: abstract EISR bitmap access Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 14/51] KVM: ARM: vgic: abstract MISR decoding Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 15/51] KVM: ARM: vgic: move underflow handling to vgic_ops Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 16/51] KVM: ARM: vgic: abstract VMCR access Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 17/51] KVM: ARM: vgic: introduce vgic_enable Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 18/51] KVM: ARM: introduce vgic_params structure Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 19/51] KVM: ARM: vgic: split GICv2 backend from the main vgic code Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 20/51] KVM: ARM: vgic: revisit implementation of irqchip_in_kernel Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 21/51] arm64: KVM: remove __kvm_hyp_code_{start,end} from hyp.S Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 22/51] arm64: KVM: split GICv2 world switch from hyp code Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 23/51] arm64: KVM: move HCR_EL2.{IMO,FMO} manipulation into the vgic switch code Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 24/51] KVM: ARM: vgic: add the GICv3 backend Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 25/51] arm64: KVM: vgic: add GICv3 world switch Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 26/51] arm64: KVM: vgic: enable GICv2 emulation on top on GICv3 hardware Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 27/51] ARM: virt: fix wrong HSCTLR.EE bit setting Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 28/51] ARM: KVM: fix vgic V7 assembler code to work in BE image Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 29/51] ARM: KVM: handle 64bit values passed to mrcc or from mcrr instructions in BE case Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 30/51] ARM: KVM: __kvm_vcpu_run function return result fix " Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 31/51] ARM: KVM: vgic mmio should hold data as LE bytes array " Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 32/51] ARM: KVM: MMIO support BE host running LE code Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 33/51] ARM: KVM: one_reg coproc set and get BE fixes Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 34/51] ARM: KVM: enable KVM in Kconfig on big-endian systems Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 35/51] ARM64: KVM: MMIO support BE host running LE code Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 36/51] ARM64: KVM: store kvm_vcpu_fault_info est_el2 as word Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 37/51] ARM64: KVM: fix vgic_bitmap_get_reg function for BE 64bit case Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 38/51] ARM64: KVM: set and get of sys registers in BE case Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 39/51] ARM64: KVM: fix big endian issue in access_vm_reg for 32bit guest Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 40/51] arm64: KVM: rename pm_fake handler to trap_raz_wi Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 41/51] arm64: move DBG_MDSCR_* to asm/debug-monitors.h Christoffer Dall
2014-08-04  8:46 ` [GIT PULL 42/51] arm64: KVM: add trap handlers for AArch64 debug registers Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 43/51] arm64: KVM: common infrastructure for handling AArch32 CP14/CP15 Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 44/51] arm64: KVM: use separate tables for AArch32 32 and 64bit traps Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 45/51] arm64: KVM: check ordering of all system register tables Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 46/51] arm64: KVM: add trap handlers for AArch32 debug registers Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 47/51] arm64: KVM: implement lazy world switch for " Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 48/51] arm64: KVM: enable trapping of all " Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 49/51] arm64: KVM: GICv3: move system register access to msr_s/mrs_s Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 50/51] KVM: arm64: GICv3: mandate page-aligned GICV region Christoffer Dall
2014-08-04  8:47 ` [GIT PULL 51/51] arm64: KVM: fix 64bit CP15 VM access for 32bit guests Christoffer Dall

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1407142028-31105-4-git-send-email-christoffer.dall@linaro.org \
    --to=christoffer.dall@linaro.org \
    --cc=gleb@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=pbonzini@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).