Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 9 Jan 2013 01:19:30 +0000 (UTC)
From:      "Cherry G. Mathew" <cherry@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r245201 - projects/amd64_xen_pv/sys/amd64/xen
Message-ID:  <201301090119.r091JUEC077574@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: cherry
Date: Wed Jan  9 01:19:30 2013
New Revision: 245201
URL: http://svnweb.freebsd.org/changeset/base/245201

Log:
  Implement mmu_map_release_va() which frees up unused page tables
  
  Approved by: gibbs (implicit)

Modified:
  projects/amd64_xen_pv/sys/amd64/xen/mmu_map.c

Modified: projects/amd64_xen_pv/sys/amd64/xen/mmu_map.c
==============================================================================
--- projects/amd64_xen_pv/sys/amd64/xen/mmu_map.c	Wed Jan  9 01:18:19 2013	(r245200)
+++ projects/amd64_xen_pv/sys/amd64/xen/mmu_map.c	Wed Jan  9 01:19:30 2013	(r245201)
@@ -88,6 +88,18 @@ pdt_index(uintptr_t va)
 	return ((va & PDPMASK) >> PDRSHIFT);
 }
 
+#if 0
+static int
+pt_index(uintptr_t va)
+{
+	/* amd64 sign extends 48th bit and upwards */
+	const uint64_t SIGNMASK = (1UL << 48) - 1;
+	va &= SIGNMASK; /* Remove sign extension */
+
+	return ((va & PDRMASK) >> PAGE_SHIFT);
+}
+#endif
+
 /* 
  * The table get functions below assume that a table cannot exist at
  * address 0
@@ -352,7 +364,7 @@ mmu_map_hold_va(struct pmap *pm, void *a
 		pdptep_ma = xpmap_ptom(pti->ptmb.vtop((uintptr_t)pdptep));
 		pdpte = xpmap_ptom(pti->ptmb.vtop((uintptr_t)pti->pdt)) | PG_RW | PG_V | PG_U; /*	XXX: revisit flags */
 		xen_queue_pt_update(pdptep_ma, pdpte);
-		
+		xen_flush_queue();
 	} else {
 		pti->pdt = (pd_entry_t *) pti->ptmb.ptov(pt);
 	}
@@ -370,12 +382,33 @@ mmu_map_hold_va(struct pmap *pm, void *a
 		pdtep_ma = xpmap_ptom(pti->ptmb.vtop((uintptr_t)pdtep));
 		pdte = xpmap_ptom(pti->ptmb.vtop((uintptr_t)pti->pt)) | PG_RW | PG_V | PG_U; /*	XXX: revisit flags */
 		xen_queue_pt_update(pdtep_ma, pdte);
-
+		xen_flush_queue();
 	} else {
 		pti->pt = (pt_entry_t *) pti->ptmb.ptov(pt);
 	}
 }
 
+/*$FreeBSD: head/lib/libc/string/memrchr.c 178051 2008-04-10 00:12:44Z delphij $*/
+/*
+ * Reverse memchr()
+ * Find the last occurrence of 'c' in the buffer 's' of size 'n'.
+ */
+static void *
+memrchr(const void *s, int c, size_t n)
+{
+	const unsigned char *cp;
+
+	if (n != 0) {
+		cp = (unsigned char *)s + n;
+		do {
+			if (*(--cp) == (unsigned char)c)
+				return((void *)cp);
+		} while (--n != 0);
+	}
+	return(NULL);
+}
+
+
 void
 mmu_map_release_va(struct pmap *pm, void *addr, uintptr_t va)
 {
@@ -385,5 +418,107 @@ mmu_map_release_va(struct pmap *pm, void
 	struct mmu_map_index *pti = addr;
 	KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
 
-	/* XXX: */
+	/*
+	 * We're expected to be called after an init-ed pti has either
+	 * been inspected, or held.
+	 */
+
+	pti->pml4t = pmap_get_pml4t(pm);
+
+	if (pti->pml4t == 0) {
+		return;
+	}
+
+	if (pti->pt != NULL) {
+		KASSERT(pti->pdt != 0, ("Invalid pdt\n"));
+	}
+
+	if (pti->pdt != NULL) { /* Zap pdte */
+
+		pd_entry_t *pdtep;
+		vm_paddr_t pdtep_ma;
+
+		pdtep = &pti->pdt[pdt_index(va)];
+
+		if (pti->pt == NULL) {
+			KASSERT(*pdtep == 0, ("%s(%d): mmu state machine out of sync!\n", __func__, __LINE__));
+		} else {
+
+			/* We can free the PT only after the PDT entry is zapped */
+			if (memrchr(pti->pt, 0, PAGE_SIZE) == ((char *)pti->pt + PAGE_SIZE - 1)) {
+			  (void) pdtep_ma;
+
+				/* Zap the backing PDT entry */
+				pdtep_ma = xpmap_ptom(pti->ptmb.vtop((uintptr_t)pdtep));
+				xen_queue_pt_update(pdtep_ma, 0);
+				xen_flush_queue();
+
+				/* The PT is empty. Free it and zero the
+				 * pointer */
+				if (pti->ptmb.free) pti->ptmb.free((uintptr_t)pti->pt);
+				pti->pt = NULL;
+
+			}
+
+		}
+
+		KASSERT(pti->pdpt != 0, ("Invalid pdpt\n"));
+	}
+
+	if (pti->pdpt != NULL) { /* Zap pdpte */
+
+		pdp_entry_t *pdptep;
+		vm_paddr_t pdptep_ma;
+
+		pdptep = &pti->pdpt[pdpt_index(va)];
+
+		if (pti->pdt == NULL) {
+			KASSERT(*pdptep == 0, ("%s(%d): mmu state machine out of sync!\n", __func__, __LINE__));
+		}
+
+		/* We can free the PDT only after the PDPT entry is zapped */
+		if (memrchr(pti->pdt, 0, PAGE_SIZE) == ((char *)pti->pdt + PAGE_SIZE - 1)) {
+			pdptep_ma = xpmap_ptom(pti->ptmb.vtop((uintptr_t)pdptep));
+			xen_queue_pt_update(pdptep_ma, 0);
+			xen_flush_queue();
+
+			/* The PDT is empty. Free it and zero the
+			 * pointer 
+			 */
+			if (pti->ptmb.free) pti->ptmb.free((uintptr_t)pti->pdt);
+			pti->pdt = NULL;
+		}
+		KASSERT(pti->pml4t != 0, ("Invalid pml4t\n"));
+	}
+
+	if (pti->pml4t != NULL) { /* Zap pml4te */
+		pml4_entry_t *pml4tep;
+		vm_paddr_t pml4tep_ma;
+
+		pml4tep = &pti->pml4t[pml4t_index(va)];
+
+		if (pti->pdpt == NULL) {
+			KASSERT(*pml4tep == 0, ("%s(%d): mmu state machine out of sync!\n", __func__, __LINE__));
+		}
+
+		if (memrchr(pti->pdpt, 0, PAGE_SIZE) == ((char *)pti->pdpt + PAGE_SIZE - 1)) {
+			pml4tep_ma = xpmap_ptom(pti->ptmb.vtop((uintptr_t)pml4tep)
+);
+			xen_queue_pt_update(pml4tep_ma, 0);
+			xen_flush_queue();
+
+			/* The PDPT is empty. Free it and zero the
+			 * pointer 
+			 */
+			if (pti->ptmb.free) pti->ptmb.free((uintptr_t)pti->pdpt);
+			pti->pdpt = NULL;
+		}
+	}			
+
+	/* 
+	 * We leave the pml4t to be managed by pmap, since there are
+	 * higher level aliasing issues across pmaps and vcpus that
+	 * can't be addressed here.
+	 */
 }
+					



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201301090119.r091JUEC077574>