svn commit: r294722 - in head/sys/arm: arm include

Svatopluk Kraus skra at FreeBSD.org
Mon Jan 25 12:43:09 UTC 2016


Author: skra
Date: Mon Jan 25 12:43:07 2016
New Revision: 294722
URL: https://svnweb.freebsd.org/changeset/base/294722

Log:
  Create new pmap dump interface for minidump and use it for existing
  pmap implementations on ARM. This way minidump code can be used without
  any platform specific modification.
  
  Also, this is the last piece missing for ARM_NEW_PMAP.
  
  Differential Revision:	https://reviews.freebsd.org/D5023

Modified:
  head/sys/arm/arm/minidump_machdep.c
  head/sys/arm/arm/pmap-v6-new.c
  head/sys/arm/arm/pmap-v6.c
  head/sys/arm/arm/pmap.c
  head/sys/arm/include/pmap-v6.h
  head/sys/arm/include/pmap.h
  head/sys/arm/include/pte.h

Modified: head/sys/arm/arm/minidump_machdep.c
==============================================================================
--- head/sys/arm/arm/minidump_machdep.c	Mon Jan 25 10:55:52 2016	(r294721)
+++ head/sys/arm/arm/minidump_machdep.c	Mon Jan 25 12:43:07 2016	(r294722)
@@ -61,8 +61,6 @@ CTASSERT(sizeof(struct kerneldumpheader)
 uint32_t *vm_page_dump;
 int vm_page_dump_size;
 
-#ifndef ARM_NEW_PMAP
-
 static struct kerneldumpheader kdh;
 
 static off_t dumplo;
@@ -196,8 +194,9 @@ blk_write_cont(struct dumperinfo *di, vm
 	return (0);
 }
 
-/* A fake page table page, to avoid having to handle both 4K and 2M pages */
-static pt_entry_t fakept[NPTEPG];
+/* A buffer for general use. Its size must be one page at least. */
+static char dumpbuf[PAGE_SIZE];
+CTASSERT(sizeof(dumpbuf) % sizeof(pt2_entry_t) == 0);
 
 int
 minidumpsys(struct dumperinfo *di)
@@ -208,9 +207,7 @@ minidumpsys(struct dumperinfo *di)
 	uint32_t bits;
 	uint32_t pa, prev_pa = 0, count = 0;
 	vm_offset_t va;
-	pd_entry_t *pdp;
-	pt_entry_t *pt, *ptp;
-	int i, k, bit, error;
+	int i, bit, error;
 	char *addr;
 
 	/*
@@ -228,48 +225,11 @@ minidumpsys(struct dumperinfo *di)
 	counter = 0;
 	/* Walk page table pages, set bits in vm_page_dump */
 	ptesize = 0;
-	for (va = KERNBASE; va < kernel_vm_end; va += NBPDR) {
-		/*
-		 * We always write a page, even if it is zero. Each
-		 * page written corresponds to 2MB of space
-		 */
-		ptesize += L2_TABLE_SIZE_REAL;
-		pmap_get_pde_pte(pmap_kernel(), va, &pdp, &ptp);
-		if (pmap_pde_v(pdp) && pmap_pde_section(pdp)) {
-			/* This is a section mapping 1M page. */
-			pa = (*pdp & L1_S_ADDR_MASK) | (va & ~L1_S_ADDR_MASK);
-			for (k = 0; k < (L1_S_SIZE / PAGE_SIZE); k++) {
-				if (is_dumpable(pa))
-					dump_add_page(pa);
-				pa += PAGE_SIZE;
-			}
-			continue;
-		}
-		if (pmap_pde_v(pdp) && pmap_pde_page(pdp)) {
-			/* Set bit for each valid page in this 1MB block */
-			addr = pmap_kenter_temporary(*pdp & L1_C_ADDR_MASK, 0);
-			pt = (pt_entry_t*)(addr +
-			    (((uint32_t)*pdp  & L1_C_ADDR_MASK) & PAGE_MASK));
-			for (k = 0; k < 256; k++) {
-				if ((pt[k] & L2_TYPE_MASK) == L2_TYPE_L) {
-					pa = (pt[k] & L2_L_FRAME) |
-					    (va & L2_L_OFFSET);
-					for (i = 0; i < 16; i++) {
-						if (is_dumpable(pa))
-							dump_add_page(pa);
-						k++;
-						pa += PAGE_SIZE;
-					}
-				} else if ((pt[k] & L2_TYPE_MASK) == L2_TYPE_S) {
-					pa = (pt[k] & L2_S_FRAME) |
-					    (va & L2_S_OFFSET);
-					if (is_dumpable(pa))
-						dump_add_page(pa);
-				}
-			}
-		} else {
-			/* Nothing, we're going to dump a null page */
-		}
+	for (va = KERNBASE; va < kernel_vm_end; va += PAGE_SIZE) {
+		pa = pmap_dump_kextract(va, NULL);
+		if (pa != 0 && is_dumpable(pa))
+			dump_add_page(pa);
+		ptesize += sizeof(pt2_entry_t);
 	}
 
 	/* Calculate dump size. */
@@ -331,9 +291,9 @@ minidumpsys(struct dumperinfo *di)
 	dumplo += sizeof(kdh);
 
 	/* Dump my header */
-	bzero(&fakept, sizeof(fakept));
-	bcopy(&mdhdr, &fakept, sizeof(mdhdr));
-	error = blk_write(di, (char *)&fakept, 0, PAGE_SIZE);
+	bzero(dumpbuf, sizeof(dumpbuf));
+	bcopy(&mdhdr, dumpbuf, sizeof(mdhdr));
+	error = blk_write(di, dumpbuf, 0, PAGE_SIZE);
 	if (error)
 		goto fail;
 
@@ -349,81 +309,21 @@ minidumpsys(struct dumperinfo *di)
 		goto fail;
 
 	/* Dump kernel page table pages */
-	for (va = KERNBASE; va < kernel_vm_end; va += NBPDR) {
-		/* We always write a page, even if it is zero */
-		pmap_get_pde_pte(pmap_kernel(), va, &pdp, &ptp);
-
-		if (pmap_pde_v(pdp) && pmap_pde_section(pdp))  {
-			if (count) {
-				error = blk_write_cont(di, prev_pa,
-				    count * L2_TABLE_SIZE_REAL);
-				if (error)
-					goto fail;
-				count = 0;
-				prev_pa = 0;
-			}
-			/* This is a single 2M block. Generate a fake PTP */
-			pa = (*pdp & L1_S_ADDR_MASK) | (va & ~L1_S_ADDR_MASK);
-			for (k = 0; k < (L1_S_SIZE / PAGE_SIZE); k++) {
-				fakept[k] = L2_S_PROTO | (pa + (k * PAGE_SIZE)) |
-				    L2_S_PROT(PTE_KERNEL,
-				    VM_PROT_READ | VM_PROT_WRITE);
-			}
-			error = blk_write(di, (char *)&fakept, 0,
-			    L2_TABLE_SIZE_REAL);
-			if (error)
-				goto fail;
-			/* Flush, in case we reuse fakept in the same block */
-			error = blk_flush(di);
-			if (error)
-				goto fail;
-			continue;
-		}
-		if (pmap_pde_v(pdp) && pmap_pde_page(pdp)) {
-			pa = *pdp & L1_C_ADDR_MASK;
-			if (!count) {
-				prev_pa = pa;
-				count++;
-			}
-			else {
-				if (pa == (prev_pa + count * L2_TABLE_SIZE_REAL))
-					count++;
-				else {
-					error = blk_write_cont(di, prev_pa,
-					    count * L2_TABLE_SIZE_REAL);
-					if (error)
-						goto fail;
-					count = 1;
-					prev_pa = pa;
-				}
-			}
-		} else {
-			if (count) {
-				error = blk_write_cont(di, prev_pa,
-				    count * L2_TABLE_SIZE_REAL);
-				if (error)
-					goto fail;
-				count = 0;
-				prev_pa = 0;
-			}
-			bzero(fakept, sizeof(fakept));
-			error = blk_write(di, (char *)&fakept, 0,
-			    L2_TABLE_SIZE_REAL);
-			if (error)
-				goto fail;
-			/* Flush, in case we reuse fakept in the same block */
-			error = blk_flush(di);
-			if (error)
+	addr = dumpbuf;
+	for (va = KERNBASE; va < kernel_vm_end; va += PAGE_SIZE) {
+		pmap_dump_kextract(va, (pt2_entry_t *)addr);
+		addr += sizeof(pt2_entry_t);
+		if (addr == dumpbuf + sizeof(dumpbuf)) {
+			error = blk_write(di, dumpbuf, 0, sizeof(dumpbuf));
+			if (error != 0)
 				goto fail;
+			addr = dumpbuf;
 		}
 	}
-
-	if (count) {
-		error = blk_write_cont(di, prev_pa, count * L2_TABLE_SIZE_REAL);
-		if (error)
+	if (addr != dumpbuf) {
+		error = blk_write(di, dumpbuf, 0, addr - dumpbuf);
+		if (error != 0)
 			goto fail;
-		count = 0;
-		prev_pa = 0;
 	}
 
 	/* Dump memory chunks */
@@ -484,17 +384,6 @@ fail:
 	return (0);
 }
 
-#else /* ARM_NEW_PMAP */
-
-int
-minidumpsys(struct dumperinfo *di)
-{
-
-	return (0);
-}
-
-#endif
-
 void
 dump_add_page(vm_paddr_t pa)
 {

Modified: head/sys/arm/arm/pmap-v6-new.c
==============================================================================
--- head/sys/arm/arm/pmap-v6-new.c	Mon Jan 25 10:55:52 2016	(r294721)
+++ head/sys/arm/arm/pmap-v6-new.c	Mon Jan 25 12:43:07 2016	(r294722)
@@ -1049,6 +1049,36 @@ pmap_kextract(vm_offset_t va)
 	return (pa);
 }
 
+/*
+ *  Extract from the kernel page table the physical address
+ *  that is mapped by the given virtual address "va". Also
+ *  return L2 page table entry which maps the address.
+ *
+ *  This is only intended to be used for panic dumps.
+ */
+vm_paddr_t
+pmap_dump_kextract(vm_offset_t va, pt2_entry_t *pte2p)
+{
+	vm_paddr_t pa;
+	pt1_entry_t pte1;
+	pt2_entry_t pte2;
+
+	pte1 = pte1_load(kern_pte1(va));
+	if (pte1_is_section(pte1)) {
+		pa = pte1_pa(pte1) | (va & PTE1_OFFSET);
+		pte2 = pa | ATTR_TO_L2(pte1) | PTE2_V;
+	} else if (pte1_is_link(pte1)) {
+		pte2 = pte2_load(pt2map_entry(va));
+		pa = pte2_pa(pte2);
+	} else {
+		pte2 = 0;
+		pa = 0;
+	}
+	if (pte2p != NULL)
+		*pte2p = pte2;
+	return (pa);
+}
+
 /*****************************************************************************
  *
  *	PMAP second stage initialization and utility functions

Modified: head/sys/arm/arm/pmap-v6.c
==============================================================================
--- head/sys/arm/arm/pmap-v6.c	Mon Jan 25 10:55:52 2016	(r294721)
+++ head/sys/arm/arm/pmap-v6.c	Mon Jan 25 12:43:07 2016	(r294722)
@@ -3536,6 +3536,52 @@ retry:
 	return (m);
 }
 
+vm_paddr_t
+pmap_dump_kextract(vm_offset_t va, pt2_entry_t *pte2p)
+{
+	struct l2_dtable *l2;
+	pd_entry_t l1pd;
+	pt_entry_t *ptep, pte;
+	vm_paddr_t pa;
+	u_int l1idx;
+
+	l1idx = L1_IDX(va);
+	l1pd = kernel_pmap->pm_l1->l1_kva[l1idx];
+	if (l1pte_section_p(l1pd)) {
+		if (l1pd & L1_S_SUPERSEC)
+			pa = (l1pd & L1_SUP_FRAME) | (va & L1_SUP_OFFSET);
+		else
+			pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET);
+		pte = L2_S_PROTO | pa |
+		    L2_S_PROT(PTE_KERNEL, VM_PROT_READ | VM_PROT_WRITE);
+	} else {
+		l2 = kernel_pmap->pm_l2[L2_IDX(l1idx)];
+		if (l2 == NULL ||
+		    (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) {
+			pte = 0;
+			pa = 0;
+			goto out;
+		}
+		pte = ptep[l2pte_index(va)];
+		if (pte == 0) {
+			pa = 0;
+			goto out;
+		}
+		switch (pte & L2_TYPE_MASK) {
+		case L2_TYPE_L:
+			pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET);
+			break;
+		default:
+			pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET);
+			break;
+		}
+	}
+out:
+	if (pte2p != NULL)
+		*pte2p = pte;
+	return (pa);
+}
+
 /*
  * Initialize a preallocated and zeroed pmap structure,
  * such as one in a vmspace structure.

Modified: head/sys/arm/arm/pmap.c
==============================================================================
--- head/sys/arm/arm/pmap.c	Mon Jan 25 10:55:52 2016	(r294721)
+++ head/sys/arm/arm/pmap.c	Mon Jan 25 12:43:07 2016	(r294722)
@@ -3738,6 +3738,52 @@ retry:
 	return (m);
 }
 
+vm_paddr_t
+pmap_dump_kextract(vm_offset_t va, pt2_entry_t *pte2p)
+{
+	struct l2_dtable *l2;
+	pd_entry_t l1pd;
+	pt_entry_t *ptep, pte;
+	vm_paddr_t pa;
+	u_int l1idx;
+
+	l1idx = L1_IDX(va);
+	l1pd = kernel_pmap->pm_l1->l1_kva[l1idx];
+	if (l1pte_section_p(l1pd)) {
+		if (l1pd & L1_S_SUPERSEC)
+			pa = (l1pd & L1_SUP_FRAME) | (va & L1_SUP_OFFSET);
+		else
+			pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET);
+		pte = L2_S_PROTO | pa |
+		    L2_S_PROT(PTE_KERNEL, VM_PROT_READ | VM_PROT_WRITE);
+	} else {
+		l2 = kernel_pmap->pm_l2[L2_IDX(l1idx)];
+		if (l2 == NULL ||
+		    (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) {
+			pte = 0;
+			pa = 0;
+			goto out;
+		}
+		pte = ptep[l2pte_index(va)];
+		if (pte == 0) {
+			pa = 0;
+			goto out;
+		}
+		switch (pte & L2_TYPE_MASK) {
+		case L2_TYPE_L:
+			pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET);
+			break;
+		default:
+			pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET);
+			break;
+		}
+	}
+out:
+	if (pte2p != NULL)
+		*pte2p = pte;
+	return (pa);
+}
+
 /*
  * Initialize a preallocated and zeroed pmap structure,
  * such as one in a vmspace structure.

Modified: head/sys/arm/include/pmap-v6.h
==============================================================================
--- head/sys/arm/include/pmap-v6.h	Mon Jan 25 10:55:52 2016	(r294721)
+++ head/sys/arm/include/pmap-v6.h	Mon Jan 25 12:43:07 2016	(r294722)
@@ -200,6 +200,8 @@ void pmap_tlb_flush_range(pmap_t , vm_of
 void pmap_dcache_wb_range(vm_paddr_t , vm_size_t , vm_memattr_t );
 
 vm_paddr_t pmap_kextract(vm_offset_t );
+vm_paddr_t pmap_dump_kextract(vm_offset_t, pt2_entry_t *);
+
 int pmap_fault(pmap_t , vm_offset_t , uint32_t , int , bool);
 #define	vtophys(va)	pmap_kextract((vm_offset_t)(va))
 

Modified: head/sys/arm/include/pmap.h
==============================================================================
--- head/sys/arm/include/pmap.h	Mon Jan 25 10:55:52 2016	(r294721)
+++ head/sys/arm/include/pmap.h	Mon Jan 25 12:43:07 2016	(r294722)
@@ -263,6 +263,7 @@ void	pmap_kremove_device(vm_offset_t, vm
 void	*pmap_kenter_temporary(vm_paddr_t pa, int i);
 void 	pmap_kenter_user(vm_offset_t va, vm_paddr_t pa);
 vm_paddr_t pmap_kextract(vm_offset_t va);
+vm_paddr_t pmap_dump_kextract(vm_offset_t, pt2_entry_t *);
 void	pmap_kremove(vm_offset_t);
 void	*pmap_mapdev(vm_offset_t, vm_size_t);
 void	pmap_unmapdev(vm_offset_t, vm_size_t);

Modified: head/sys/arm/include/pte.h
==============================================================================
--- head/sys/arm/include/pte.h	Mon Jan 25 10:55:52 2016	(r294721)
+++ head/sys/arm/include/pte.h	Mon Jan 25 12:43:07 2016	(r294722)
@@ -43,6 +43,7 @@
 #ifndef LOCORE
 typedef	uint32_t	pd_entry_t;		/* page directory entry */
 typedef	uint32_t	pt_entry_t;		/* page table entry */
+typedef	pt_entry_t	pt2_entry_t;		/* compatibility with v6 */
 #endif
 
 #define PG_FRAME	0xfffff000


More information about the svn-src-head mailing list