svn commit: r261643 - in head/sys: arm/arm arm/at91 arm/econa arm/include arm/s3c2xx0 arm/sa11x0 arm/xscale/i80321 arm/xscale/i8134x arm/xscale/ixp425 arm/xscale/pxa conf

Ian Lepore ian at FreeBSD.org
Sat Feb 8 23:54:18 UTC 2014


Author: ian
Date: Sat Feb  8 23:54:16 2014
New Revision: 261643
URL: http://svnweb.freebsd.org/changeset/base/261643

Log:
  Consolidate code related to setting up physical memory configuration into
  a new physmem.c file.  The new code provides helper routines that can be
  used by legacy SoCs and newer FDT-based systems.  There are routines to
  add one or more regions of physically contiguous ram, and exclude one or
  more physically contiguous regions of ram.  Ram can be excluded from crash
  dumps, from being given over to the vm system for allocation management,
  or both.  After all the included and excluded regions have been added,
  arm_physmem_init_kernel_globals() processes the regions into the global
  dump_avail and phys_avail arrays and realmem and physmem variables that
  communicate memory configuration to the rest of the kernel.
  
  Convert all existing SoCs to use the new helper code.

Added:
  head/sys/arm/arm/physmem.c   (contents, props changed)
  head/sys/arm/include/physmem.h   (contents, props changed)
Modified:
  head/sys/arm/arm/machdep.c
  head/sys/arm/at91/at91_machdep.c
  head/sys/arm/econa/econa_machdep.c
  head/sys/arm/include/machdep.h
  head/sys/arm/s3c2xx0/s3c24x0_machdep.c
  head/sys/arm/sa11x0/assabet_machdep.c
  head/sys/arm/xscale/i80321/ep80219_machdep.c
  head/sys/arm/xscale/i80321/iq31244_machdep.c
  head/sys/arm/xscale/i8134x/crb_machdep.c
  head/sys/arm/xscale/ixp425/avila_machdep.c
  head/sys/arm/xscale/pxa/pxa_machdep.c
  head/sys/conf/files.arm

Modified: head/sys/arm/arm/machdep.c
==============================================================================
--- head/sys/arm/arm/machdep.c	Sat Feb  8 22:21:38 2014	(r261642)
+++ head/sys/arm/arm/machdep.c	Sat Feb  8 23:54:16 2014	(r261643)
@@ -97,6 +97,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/md_var.h>
 #include <machine/metadata.h>
 #include <machine/pcb.h>
+#include <machine/physmem.h>
 #include <machine/reg.h>
 #include <machine/trap.h>
 #include <machine/undefined.h>
@@ -122,8 +123,6 @@ uint32_t cpu_reset_address = 0;
 int cold = 1;
 vm_offset_t vector_page;
 
-long realmem = 0;
-
 int (*_arm_memcpy)(void *, void *, int, int) = NULL;
 int (*_arm_bzero)(void *, int, int) = NULL;
 int _min_memcpy_size = 0;
@@ -144,9 +143,6 @@ extern vm_offset_t ksym_start, ksym_end;
 
 static struct pv_addr kernel_pt_table[KERNEL_PT_MAX];
 
-vm_paddr_t phys_avail[10];
-vm_paddr_t dump_avail[4];
-
 extern u_int data_abort_handler_address;
 extern u_int prefetch_abort_handler_address;
 extern u_int undefined_handler_address;
@@ -356,6 +352,7 @@ static void
 cpu_startup(void *dummy)
 {
 	struct pcb *pcb = thread0.td_pcb;
+	const unsigned int mbyte = 1024 * 1024;
 #ifdef ARM_TP_ADDRESS
 #ifndef ARM_CACHE_LOCK_ENABLE
 	vm_page_t m;
@@ -364,36 +361,21 @@ cpu_startup(void *dummy)
 
 	identify_arm_cpu();
 
-	printf("real memory  = %ju (%ju MB)\n", (uintmax_t)ptoa(physmem),
-	    (uintmax_t)ptoa(physmem) / 1048576);
-	realmem = physmem;
+	vm_ksubmap_init(&kmi);
 
 	/*
 	 * Display the RAM layout.
 	 */
-	if (bootverbose) {
-		int indx;
-
-		printf("Physical memory chunk(s):\n");
-		for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
-			vm_paddr_t size;
-
-			size = phys_avail[indx + 1] - phys_avail[indx];
-			printf("  0x%08jx - 0x%08jx, %ju KBytes (%ju pages)\n",
-			    (uintmax_t)phys_avail[indx],
-			    (uintmax_t)phys_avail[indx + 1] - 1,
-			    (uintmax_t)size / 1024, (uintmax_t)size / PAGE_SIZE);
-		}
-	}
-
-	vm_ksubmap_init(&kmi);
-
+	printf("real memory  = %ju (%ju MB)\n", 
+	    (uintmax_t)arm32_ptob(realmem),
+	    (uintmax_t)arm32_ptob(realmem) / mbyte);
 	printf("avail memory = %ju (%ju MB)\n",
-	    (uintmax_t)ptoa(cnt.v_free_count),
-	    (uintmax_t)ptoa(cnt.v_free_count) / 1048576);
-
-	if (bootverbose)
+	    (uintmax_t)arm32_ptob(cnt.v_free_count),
+	    (uintmax_t)arm32_ptob(cnt.v_free_count) / mbyte);
+	if (bootverbose) {
+		arm_physmem_print_tables();
 		arm_devmap_print_table();
+	}
 
 	bufinit();
 	vm_pager_bufferinit();
@@ -780,44 +762,6 @@ makectx(struct trapframe *tf, struct pcb
 }
 
 /*
- * Make a standard dump_avail array.  Can't make the phys_avail
- * since we need to do that after we call pmap_bootstrap, but this
- * is needed before pmap_boostrap.
- */
-void
-arm_dump_avail_init(vm_paddr_t physaddr, vm_offset_t ramsize, size_t max)
-{
-#ifdef LINUX_BOOT_ABI
-	/*
-	 * Linux boot loader passes us the actual banks of memory, so use them
-	 * to construct the dump_avail array.
-	 */
-	if (membanks > 0) 
-	{
-		int i, j;
-
-		if (max < (membanks + 1) * 2)
-			panic("dump_avail[%d] too small for %d banks\n",
-			    max, membanks);
-		for (j = 0, i = 0; i < membanks; i++) {
-			dump_avail[j++] = round_page(memstart[i]);
-			dump_avail[j++] = trunc_page(memstart[i] + memsize[i]);
-		}
-		dump_avail[j++] = 0;
-		dump_avail[j++] = 0;
-		return;
-	}
-#endif
-	if (max < 4)
-		panic("dump_avail too small\n");
-
-	dump_avail[0] = round_page(physaddr);
-	dump_avail[1] = trunc_page(physaddr + ramsize);
-	dump_avail[2] = 0;
-	dump_avail[3] = 0;
-}
-
-/*
  * Fake up a boot descriptor table
  */
 vm_offset_t
@@ -910,11 +854,8 @@ linux_parse_boot_param(struct arm_boot_p
 		case ATAG_CORE:
 			break;
 		case ATAG_MEM:
-			if (membanks < LBABI_MAX_BANKS) {
-				memstart[membanks] = walker->u.tag_mem.start;
-				memsize[membanks] = walker->u.tag_mem.size;
-			}
-			membanks++;
+			arm_physmem_hardware_region(walker->u.tag_mem.start,
+			    walker->u.tag_mem.size);
 			break;
 		case ATAG_INITRD2:
 			break;
@@ -1077,120 +1018,10 @@ print_kenv(void)
 		debugf(" %x %s\n", (uint32_t)cp, cp);
 }
 
-static void
-physmap_init(struct mem_region *availmem_regions, int availmem_regions_sz,
-    vm_offset_t kernload)
-{
-	int i, j, cnt;
-	vm_offset_t phys_kernelend;
-	uint32_t s, e, sz;
-	struct mem_region *mp, *mp1;
-
-	phys_kernelend = kernload + (virtual_avail - KERNVIRTADDR);
-
-	/*
-	 * Remove kernel physical address range from avail
-	 * regions list. Page align all regions.
-	 * Non-page aligned memory isn't very interesting to us.
-	 * Also, sort the entries for ascending addresses.
-	 */
-	sz = 0;
-	cnt = availmem_regions_sz;
-	debugf("processing avail regions:\n");
-	for (mp = availmem_regions; mp->mr_size; mp++) {
-		s = mp->mr_start;
-		e = mp->mr_start + mp->mr_size;
-		debugf(" %08x-%08x -> ", s, e);
-		/* Check whether this region holds all of the kernel. */
-		if (s < kernload && e > phys_kernelend) {
-			availmem_regions[cnt].mr_start = phys_kernelend;
-			availmem_regions[cnt++].mr_size = e - phys_kernelend;
-			e = kernload;
-		}
-		/* Look whether this regions starts within the kernel. */
-		if (s >= kernload && s < phys_kernelend) {
-			if (e <= phys_kernelend)
-				goto empty;
-			s = phys_kernelend;
-		}
-		/* Now look whether this region ends within the kernel. */
-		if (e > kernload && e <= phys_kernelend) {
-			if (s >= kernload) {
-				goto empty;
-			}
-			e = kernload;
-		}
-		/* Now page align the start and size of the region. */
-		s = round_page(s);
-		e = trunc_page(e);
-		if (e < s)
-			e = s;
-		sz = e - s;
-		debugf("%08x-%08x = %x\n", s, e, sz);
-
-		/* Check whether some memory is left here. */
-		if (sz == 0) {
-		empty:
-			printf("skipping\n");
-			bcopy(mp + 1, mp,
-			    (cnt - (mp - availmem_regions)) * sizeof(*mp));
-			cnt--;
-			mp--;
-			continue;
-		}
-
-		/* Do an insertion sort. */
-		for (mp1 = availmem_regions; mp1 < mp; mp1++)
-			if (s < mp1->mr_start)
-				break;
-		if (mp1 < mp) {
-			bcopy(mp1, mp1 + 1, (char *)mp - (char *)mp1);
-			mp1->mr_start = s;
-			mp1->mr_size = sz;
-		} else {
-			mp->mr_start = s;
-			mp->mr_size = sz;
-		}
-	}
-	availmem_regions_sz = cnt;
-
-	/* Fill in phys_avail table, based on availmem_regions */
-	debugf("fill in phys_avail:\n");
-	for (i = 0, j = 0; i < availmem_regions_sz; i++, j += 2) {
-
-		debugf(" region: 0x%08x - 0x%08x (0x%08x)\n",
-		    availmem_regions[i].mr_start,
-		    availmem_regions[i].mr_start + availmem_regions[i].mr_size,
-		    availmem_regions[i].mr_size);
-
-		/*
-		 * We should not map the page at PA 0x0000000, the VM can't
-		 * handle it, as pmap_extract() == 0 means failure.
-		 */
-		if (availmem_regions[i].mr_start > 0 ||
-		    availmem_regions[i].mr_size > PAGE_SIZE) {
-			vm_size_t size;
-			phys_avail[j] = availmem_regions[i].mr_start;
-
-			size = availmem_regions[i].mr_size;
-			if (phys_avail[j] == 0) {
-				phys_avail[j] += PAGE_SIZE;
-				size -= PAGE_SIZE;
-			}
-			phys_avail[j + 1] = availmem_regions[i].mr_start + size;
-		} else
-			j -= 2;
-	}
-	phys_avail[j] = 0;
-	phys_avail[j + 1] = 0;
-}
-
 void *
 initarm(struct arm_boot_params *abp)
 {
-	struct mem_region memory_regions[FDT_MEM_REGIONS];
-	struct mem_region availmem_regions[FDT_MEM_REGIONS];
-	struct mem_region reserved_regions[FDT_MEM_REGIONS];
+	struct mem_region mem_regions[FDT_MEM_REGIONS];
 	struct pv_addr kernel_l1pt;
 	struct pv_addr dpcpu;
 	vm_offset_t dtbp, freemempos, l2_start, lastaddr;
@@ -1198,13 +1029,7 @@ initarm(struct arm_boot_params *abp)
 	char *env;
 	void *kmdp;
 	u_int l1pagetable;
-	int i = 0, j = 0, err_devmap = 0;
-	int memory_regions_sz;
-	int availmem_regions_sz;
-	int reserved_regions_sz;
-	vm_offset_t start, end;
-	vm_offset_t rstart, rend;
-	int curr;
+	int i, j, err_devmap, mem_regions_sz;
 
 	lastaddr = parse_boot_param(abp);
 	memsize = 0;
@@ -1235,72 +1060,14 @@ initarm(struct arm_boot_params *abp)
 		while (1);
 
 	/* Grab physical memory regions information from device tree. */
-	if (fdt_get_mem_regions(memory_regions, &memory_regions_sz,
-	    &memsize) != 0)
-		while(1);
-
-	/* Grab physical memory regions information from device tree. */
-	if (fdt_get_reserved_regions(reserved_regions, &reserved_regions_sz) != 0)
-		reserved_regions_sz = 0;
-		
-	/*
-	 * Now exclude all the reserved regions
-	 */
-	curr = 0;
-	for (i = 0; i < memory_regions_sz; i++) {
-		start = memory_regions[i].mr_start;
-		end = start + memory_regions[i].mr_size;
-		for (j = 0; j < reserved_regions_sz; j++) {
-			rstart = reserved_regions[j].mr_start;
-			rend = rstart + reserved_regions[j].mr_size;
-			/* 
-			 * Restricted region is before available
-			 * Skip restricted region
-			 */
-			if (rend <= start)
-				continue;
-			/* 
-			 * Restricted region is behind available
-			 * No  further processing required
-			 */
-			if (rstart >= end)
-				break;
-			/*
-			 * Restricted region includes memory region
-			 * skip available region
-			 */
-			if ((start >= rstart) && (rend >= end)) {
-				start = rend;
-				end = rend;
-				break;
-			}
-			/*
-			 * Memory region includes restricted region
-			 */
-			if ((rstart > start) && (end > rend)) {
-				availmem_regions[curr].mr_start = start;
-				availmem_regions[curr++].mr_size = rstart - start;
-				start = rend;
-				break;
-			}
-			/*
-			 * Memory region partially overlaps with restricted
-			 */
-			if ((rstart >= start) && (rstart <= end)) {
-				end = rstart;
-			}
-			else if ((rend >= start) && (rend <= end)) {
-				start = rend;
-			}
-		}
-
-		if (end > start) {
-			availmem_regions[curr].mr_start = start;
-			availmem_regions[curr++].mr_size = end - start;
-		}
-	}
-
-	availmem_regions_sz = curr;
+	if (fdt_get_mem_regions(mem_regions, &mem_regions_sz, &memsize) != 0)
+		panic("Cannot get physical memory regions");
+	arm_physmem_hardware_regions(mem_regions, mem_regions_sz);
+
+	/* Grab reserved memory regions information from device tree. */
+	if (fdt_get_reserved_regions(mem_regions, &mem_regions_sz) == 0)
+		arm_physmem_exclude_regions(mem_regions, mem_regions_sz, 
+		    EXFLAG_NODUMP | EXFLAG_NOALLOC);
 
 	/* Platform-specific initialisation */
 	initarm_early_init();
@@ -1339,7 +1106,7 @@ initarm(struct arm_boot_params *abp)
 		freemempos += PAGE_SIZE;
 	valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
 
-	for (i = 0; i < l2size; ++i) {
+	for (i = 0, j = 0; i < l2size; ++i) {
 		if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
 			valloc_pages(kernel_pt_table[i],
 			    L2_TABLE_SIZE / PAGE_SIZE);
@@ -1498,17 +1265,22 @@ initarm(struct arm_boot_params *abp)
 
 	arm_intrnames_init();
 	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
-	arm_dump_avail_init(abp->abp_physaddr, memsize,
-	    sizeof(dump_avail) / sizeof(dump_avail[0]));
 	pmap_bootstrap(freemempos, &kernel_l1pt);
 	msgbufp = (void *)msgbufpv.pv_va;
 	msgbufinit(msgbufp, msgbufsize);
 	mutex_init();
 
 	/*
-	 * Prepare map of physical memory regions available to vm subsystem.
+	 * Exclude the kernel (and all the things we allocated which immediately
+	 * follow the kernel) from the VM allocation pool but not from crash
+	 * dumps.  virtual_avail is a global variable which tracks the kva we've
+	 * "allocated" while setting up pmaps.
+	 *
+	 * Prepare the list of physical memory available to the vm subsystem.
 	 */
-	physmap_init(availmem_regions, availmem_regions_sz, abp->abp_physaddr);
+	arm_physmem_exclude_region(abp->abp_physaddr, 
+	    (virtual_avail - KERNVIRTADDR), EXFLAG_NOALLOC);
+	arm_physmem_init_kernel_globals();
 
 	init_param2(physmem);
 	kdb_init();

Added: head/sys/arm/arm/physmem.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm/arm/physmem.c	Sat Feb  8 23:54:16 2014	(r261643)
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 2014 Ian Lepore <ian at freebsd.org>
+ * All rights excluded.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
+/*
+ * Routines for describing and initializing anything related to physical memory.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <vm/vm.h>
+#include <machine/physmem.h>
+
+/*
+ * These structures are used internally to keep track of regions of physical
+ * ram, and regions within the physical ram that need to be excluded.  An
+ * exclusion region can be excluded from crash dumps, from the vm pool of pages
+ * that can be allocated, or both, depending on the exclusion flags associated
+ * with the region.
+ */
+#define	MAX_HWCNT	10
+#define	MAX_EXCNT	10
+
+struct region {
+	vm_offset_t	addr;
+	vm_size_t	size;
+	uint32_t	flags;
+};
+
+static struct region hwregions[MAX_HWCNT];
+static struct region exregions[MAX_EXCNT];
+
+static size_t hwcnt;
+static size_t excnt;
+
+/*
+ * These "avail lists" are globals used to communicate physical memory layout to 
+ * other parts of the kernel.  Within the arrays, each value is the starting
+ * address of a contiguous area of physical address space.  The values at even
+ * indexes are areas that contain usable memory and the values at odd indexes
+ * are areas that aren't usable.  Each list is terminated by a pair of zero
+ * entries.
+ *
+ * dump_avail tells the dump code what regions to include in a crash dump, and
+ * phys_avail is the way we hand all the remaining physical ram we haven't used
+ * in early kernel init over to the vm system for allocation management.
+ *
+ * We size these arrays to hold twice as many available regions as we allow for
+ * hardware memory regions, to allow for the fact that exclusions can split a
+ * hardware region into two or more available regions.  In the real world there
+ * will typically be one or two hardware regions and two or three exclusions.
+ *
+ * Each available region in this list occupies two array slots (the start of the
+ * available region and the start of the unavailable region that follows it).
+ */
+#define	MAX_AVAIL_REGIONS	(MAX_HWCNT * 2)
+#define	MAX_AVAIL_ENTRIES	(MAX_AVAIL_REGIONS * 2)
+
+vm_paddr_t phys_avail[MAX_AVAIL_ENTRIES + 2]; /* +2 to allow for a pair  */
+vm_paddr_t dump_avail[MAX_AVAIL_ENTRIES + 2]; /* of zeroes to terminate. */
+
+/* This is the total number of hardware pages, excluded or not. */
+long realmem;
+
+/*
+ * Print the contents of the physical and excluded region tables using the
+ * provided printf-like output function (which will be either printf or
+ * db_printf).
+ */
+static void
+physmem_dump_tables(int (*prfunc)(const char *, ...))
+{
+	int flags, i;
+	uintmax_t addr, size;
+	const unsigned int mbyte = 1024 * 1024;
+
+	prfunc("Physical memory chunk(s):\n");
+	for (i = 0; i < hwcnt; ++i) {
+		addr = hwregions[i].addr;
+		size = hwregions[i].size;
+		prfunc("  0x%08jx - 0x%08jx, %5ju MB (%7ju pages)\n", addr,
+		    addr + size - 1, size / mbyte, size / PAGE_SIZE);
+	}
+
+	prfunc("Excluded memory regions:\n");
+	for (i = 0; i < excnt; ++i) {
+		addr  = exregions[i].addr;
+		size  = exregions[i].size;
+		flags = exregions[i].flags;
+		prfunc("  0x%08jx - 0x%08jx, %5ju MB (%7ju pages) %s %s\n",
+		    addr, addr + size - 1, size / mbyte, size / PAGE_SIZE,
+		    (flags & EXFLAG_NOALLOC) ? "NoAlloc" : "",
+		    (flags & EXFLAG_NODUMP)  ? "NoDump" : "");
+	}
+}
+
+/*
+ * Print the contents of the static mapping table.  Used for bootverbose.
+ */
+void
+arm_physmem_print_tables()
+{
+
+	physmem_dump_tables(printf);
+}
+
+/*
+ * Walk the list of hardware regions, processing it against the list of
+ * exclusions that contain the given exflags, and generating an "avail list".
+ *
+ * Updates the kernel global 'realmem' with the sum of all pages in hw regions.
+ *
+ * Returns the number of pages of non-excluded memory added to the avail list.
+ */
+static long
+regions_to_avail(vm_paddr_t *avail, uint32_t exflags)
+{
+	size_t acnt, exi, hwi;
+	vm_paddr_t end, start, xend, xstart;
+	long availmem;
+	const struct region *exp, *hwp;
+
+	realmem = 0;
+	availmem = 0;
+	acnt = 0;
+	for (hwi = 0, hwp = hwregions; hwi < hwcnt; ++hwi, ++hwp) {
+		start = hwp->addr;
+		end   = hwp->size + start;
+		realmem += arm32_btop(end - start);
+		for (exi = 0, exp = exregions; exi < excnt; ++exi, ++exp) {
+			xstart = exp->addr;
+			xend   = exp->size + xstart;
+			/*
+			 * If the excluded region ends before this hw region,
+			 * continue checking with the next excluded region.
+			 */
+			if (xend <= start)
+				continue;
+			/*
+			 * If the excluded region begins after this hw region
+			 * we're done because both lists are sorted.
+			 */
+			if (xstart >= end)
+				break;
+			/*
+			 * If the excluded region completely covers this hw
+			 * region, shrink this hw region to zero size.
+			 */
+			if ((start >= xstart) && (end <= xend)) {
+				start = xend;
+				end = xend;
+				break;
+			}
+			/*
+			 * If the excluded region falls wholly within this hw
+			 * region without abutting or overlapping the beginning
+			 * or end, create an available entry from the leading
+			 * fragment, then adjust the start of this hw region to
+			 * the end of the excluded region, and continue checking
+			 * the next excluded region because another exclusion
+			 * could affect the remainder of this hw region.
+			 */
+			if ((xstart > start) && (xend < end)) {
+				avail[acnt++] = start;
+				avail[acnt++] = xstart;
+				availmem += arm32_btop(xstart - start);
+				start = xend;
+				continue;
+			}
+			/*
+			 * If excluded region partially overlaps this region,
+			 * trim the excluded portion off the appropriate end.
+			 */
+			if ((xstart >= start) && (xstart <= end)) {
+				end = xstart;
+			} else if ((xend >= start) && (xend <= end)) {
+				start = xend;
+			}
+		}
+		/*
+		 * If the trimming actions above left a non-zero size, create an
+		 * available entry for it.
+		 */
+		if (end > start) {
+			avail[acnt++] = start;
+			avail[acnt++] = end;
+			availmem += arm32_btop(end - start);
+		}
+		if (acnt >= MAX_AVAIL_ENTRIES)
+			panic("Not enough space in the dump/phys_avail arrays");
+	}
+
+	return (availmem);
+}
+
+/*
+ * Insertion-sort a new entry into a regions list; sorted by start address.
+ */
+static void
+insert_region(struct region *regions, size_t rcnt, vm_offset_t addr,
+    vm_size_t size, uint32_t flags)
+{
+	size_t i;
+	struct region *ep, *rp;
+
+	ep = regions + rcnt;
+	for (i = 0, rp = regions; i < rcnt; ++i, ++rp) {
+		if (addr < rp->addr) {
+			bcopy(rp, rp + 1, (ep - rp) * sizeof(*rp));
+			break;
+		}
+	}
+	rp->addr  = addr;
+	rp->size  = size;
+	rp->flags = flags;
+}
+
+/*
+ * Add a hardware memory region.
+ */
+void
+arm_physmem_hardware_region(vm_offset_t pa, vm_size_t sz)
+{
+	vm_offset_t adj;
+
+	/*
+	 * Filter out the page at PA 0x00000000.  The VM can't handle it, as
+	 * pmap_extract() == 0 means failure.
+	 */
+	if (pa == 0) {
+		pa  = PAGE_SIZE;
+		sz -= PAGE_SIZE;
+	}
+
+	/*
+	 * Round the starting address up to a page boundary, and truncate the
+	 * ending page down to a page boundary.
+	 */
+	adj = round_page(pa) - pa;
+	pa  = round_page(pa);
+	sz  = trunc_page(sz - adj);
+
+	if (hwcnt < nitems(hwregions))
+		insert_region(hwregions, hwcnt++, pa, sz, 0);
+}
+
+/*
+ * Add an exclusion region.
+ */
+void arm_physmem_exclude_region(vm_offset_t pa, vm_size_t sz, uint32_t exflags)
+{
+	vm_offset_t adj;
+
+	/*
+	 * Truncate the starting address down to a page boundary, and round the
+	 * ending page up to a page boundary.
+	 */
+	adj = pa - trunc_page(pa);
+	pa  = trunc_page(pa);
+	sz  = round_page(sz + adj);
+
+	if (excnt < nitems(exregions))
+		insert_region(exregions, excnt++, pa, sz, exflags);
+}
+
+/*
+ * Process all the regions added earlier into the global avail lists.
+ */
+void
+arm_physmem_init_kernel_globals(void)
+{
+
+	regions_to_avail(dump_avail, EXFLAG_NODUMP);
+	physmem = regions_to_avail(phys_avail, EXFLAG_NOALLOC);
+}
+
+#ifdef DDB
+#include <ddb/ddb.h>
+
+DB_SHOW_COMMAND(physmem, db_show_physmem)
+{
+
+	physmem_dump_tables(db_printf);
+}
+
+#endif /* DDB */
+

Modified: head/sys/arm/at91/at91_machdep.c
==============================================================================
--- head/sys/arm/at91/at91_machdep.c	Sat Feb  8 22:21:38 2014	(r261642)
+++ head/sys/arm/at91/at91_machdep.c	Sat Feb  8 23:54:16 2014	(r261643)
@@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/exec.h>
 #include <sys/kdb.h>
 #include <sys/msgbuf.h>
+#include <machine/physmem.h>
 #include <machine/reg.h>
 #include <machine/cpu.h>
 #include <machine/board.h>
@@ -199,9 +200,6 @@ const struct arm_devmap_entry at91_devma
 
 /* Physical and virtual addresses for some global pages */
 
-vm_paddr_t phys_avail[10];
-vm_paddr_t dump_avail[4];
-
 struct pv_addr systempage;
 struct pv_addr msgbufpv;
 struct pv_addr irqstack;
@@ -630,8 +628,6 @@ initarm(struct arm_boot_params *abp)
 	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
 
 	pmap_curmaxkvaddr = afterkern + L1_S_SIZE * (KERNEL_PT_KERN_NUM - 1);
-	arm_dump_avail_init(abp->abp_physaddr, memsize,
-	    sizeof(dump_avail)/sizeof(dump_avail[0]));
 	/* Always use the 256MB of KVA we have available between the kernel and devices */
 	vm_max_kernel_address = KERNVIRTADDR + (256 << 20);
 	pmap_bootstrap(freemempos, &kernel_l1pt);
@@ -639,15 +635,21 @@ initarm(struct arm_boot_params *abp)
 	msgbufinit(msgbufp, msgbufsize);
 	mutex_init();
 
-	i = 0;
-#if PHYSADDR != KERNPHYSADDR
-	phys_avail[i++] = PHYSADDR;
-	phys_avail[i++] = KERNPHYSADDR;
-#endif
-	phys_avail[i++] = virtual_avail - KERNVIRTADDR + KERNPHYSADDR;
-	phys_avail[i++] = PHYSADDR + memsize;
-	phys_avail[i++] = 0;
-	phys_avail[i++] = 0;
+	/*
+	 * Add the physical ram we have available.
+	 *
+	 * Exclude the kernel, and all the things we allocated which immediately
+	 * follow the kernel, from the VM allocation pool but not from crash
+	 * dumps.  virtual_avail is a global variable which tracks the kva we've
+	 * "allocated" while setting up pmaps.
+	 *
+	 * Prepare the list of physical memory available to the vm subsystem.
+	 */
+	arm_physmem_hardware_region(PHYSADDR, memsize);
+	arm_physmem_exclude_region(abp->abp_physaddr, 
+	    virtual_avail - KERNVIRTADDR, EXFLAG_NOALLOC);
+	arm_physmem_init_kernel_globals();
+
 	init_param2(physmem);
 	kdb_init();
 	return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -

Modified: head/sys/arm/econa/econa_machdep.c
==============================================================================
--- head/sys/arm/econa/econa_machdep.c	Sat Feb  8 22:21:38 2014	(r261642)
+++ head/sys/arm/econa/econa_machdep.c	Sat Feb  8 23:54:16 2014	(r261643)
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/exec.h>
 #include <sys/kdb.h>
 #include <sys/msgbuf.h>
+#include <machine/physmem.h>
 #include <machine/reg.h>
 #include <machine/cpu.h>
 
@@ -98,9 +99,6 @@ struct pv_addr kernel_pt_table[NUM_KERNE
 
 /* Physical and virtual addresses for some global pages */
 
-vm_paddr_t phys_avail[10];
-vm_paddr_t dump_avail[4];
-
 struct pv_addr systempage;
 struct pv_addr msgbufpv;
 struct pv_addr irqstack;
@@ -284,7 +282,6 @@ initarm(struct arm_boot_params *abp)
 	cninit();
 	mem_info = ((*ddr) >> 4) & 0x3;
 	memsize = (8<<mem_info)*1024*1024;
-	physmem = memsize / PAGE_SIZE;
 
 	/*
 	 * Pages were allocated during the secondary bootstrap for the
@@ -322,8 +319,6 @@ initarm(struct arm_boot_params *abp)
 	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
 
 	pmap_curmaxkvaddr = afterkern + L1_S_SIZE * (KERNEL_PT_KERN_NUM - 1);
-	arm_dump_avail_init(abp->abp_physaddr, memsize,
-	    sizeof(dump_avail) / sizeof(dump_avail[0]));
 	vm_max_kernel_address = KERNVIRTADDR + 3 * memsize;
 	pmap_bootstrap(freemempos, &kernel_l1pt);
 
@@ -332,16 +327,21 @@ initarm(struct arm_boot_params *abp)
 
 	mutex_init();
 
-	i = 0;
-#if PHYSADDR != KERNPHYSADDR
-	phys_avail[i++] = PHYSADDR;
-	phys_avail[i++] = KERNPHYSADDR;
-#endif
-	phys_avail[i++] = virtual_avail - KERNVIRTADDR + KERNPHYSADDR;
-
-	phys_avail[i++] = PHYSADDR + memsize;
-	phys_avail[i++] = 0;
-	phys_avail[i++] = 0;
+	/*
+	 * Add the physical ram we have available.
+	 *
+	 * Exclude the kernel, and all the things we allocated which immediately
+	 * follow the kernel, from the VM allocation pool but not from crash
+	 * dumps.  virtual_avail is a global variable which tracks the kva we've
+	 * "allocated" while setting up pmaps.
+	 *
+	 * Prepare the list of physical memory available to the vm subsystem.
+	 */
+	arm_physmem_hardware_region(PHYSADDR, memsize);
+	arm_physmem_exclude_region(abp->abp_physaddr, 
+	    virtual_avail - KERNVIRTADDR, EXFLAG_NOALLOC);
+	arm_physmem_init_kernel_globals();
+
 	init_param2(physmem);
 	kdb_init();
 

Modified: head/sys/arm/include/machdep.h
==============================================================================
--- head/sys/arm/include/machdep.h	Sat Feb  8 22:21:38 2014	(r261642)
+++ head/sys/arm/include/machdep.h	Sat Feb  8 23:54:16 2014	(r261643)
@@ -71,7 +71,4 @@ void initarm_late_init(void);
 void board_set_serial(uint64_t);
 void board_set_revision(uint32_t);
 
-/* Setup standard arrays */
-void arm_dump_avail_init(vm_paddr_t, vm_offset_t, size_t);
-
 #endif /* !_MACHINE_MACHDEP_H_ */

Added: head/sys/arm/include/physmem.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm/include/physmem.h	Sat Feb  8 23:54:16 2014	(r261643)
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2014 Ian Lepore <ian at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	_MACHINE_PHYSMEM_H_
+#define	_MACHINE_PHYSMEM_H_
+
+/*
+ * Routines to help configure physical ram.
+ *
+ * Multiple regions of contiguous physical ram can be added (in any order).
+ *
+ * Multiple regions of physical ram that should be excluded from crash dumps, or
+ * memory allocation, or both, can be added (in any order).
+ *
+ * After all early kernel init is done and it's time to configure all
+ * remainining non-excluded physical ram for use by other parts of the kernel,
+ * arm_physmem_init_kernel_globals() processes the hardware regions and
+ * exclusion regions to generate the global dump_avail and phys_avail arrays
+ * that communicate physical ram configuration to other parts of the kernel.
+ */
+
+#define	EXFLAG_NODUMP	0x01
+#define	EXFLAG_NOALLOC	0x02
+
+void arm_physmem_hardware_region(vm_offset_t pa, vm_size_t sz);
+void arm_physmem_exclude_region(vm_offset_t pa, vm_size_t sz, uint32_t flags);
+void arm_physmem_init_kernel_globals(void);
+void arm_physmem_print_tables(void);
+
+/*
+ * Convenience routines for FDT.
+ */
+
+#ifdef FDT
+
+#include <machine/ofw_machdep.h>
+
+inline void 
+arm_physmem_hardware_regions(struct mem_region * mrptr, int mrcount)
+{
+	while (mrcount--) {
+		arm_physmem_hardware_region(mrptr->mr_start, mrptr->mr_size);
+		++mrptr;
+	}
+}
+
+inline void
+arm_physmem_exclude_regions(struct mem_region * mrptr, int mrcount, 
+    uint32_t exflags)
+{
+	while (mrcount--) {
+		arm_physmem_exclude_region(mrptr->mr_start, mrptr->mr_size, 
+		    exflags);
+		++mrptr;
+	}
+}
+
+#endif /* FDT */
+
+#endif
+

Modified: head/sys/arm/s3c2xx0/s3c24x0_machdep.c
==============================================================================
--- head/sys/arm/s3c2xx0/s3c24x0_machdep.c	Sat Feb  8 22:21:38 2014	(r261642)
+++ head/sys/arm/s3c2xx0/s3c24x0_machdep.c	Sat Feb  8 23:54:16 2014	(r261643)
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/exec.h>
 #include <sys/kdb.h>
 #include <sys/msgbuf.h>
+#include <machine/physmem.h>
 #include <machine/reg.h>
 #include <machine/cpu.h>
 
@@ -113,9 +114,6 @@ struct pv_addr kernel_pt_table[NUM_KERNE
 
 /* Physical and virtual addresses for some global pages */
 
-vm_paddr_t phys_avail[10];
-vm_paddr_t dump_avail[4];
-
 struct pv_addr systempage;
 struct pv_addr msgbufpv;
 struct pv_addr irqstack;
@@ -384,20 +382,26 @@ initarm(struct arm_boot_params *abp)
 	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
 
 	pmap_curmaxkvaddr = afterkern + 0x100000 * (KERNEL_PT_KERN_NUM - 1);
-	arm_dump_avail_init(abp->abp_physaddr, memsize,
-	    sizeof(dump_avail) / sizeof(dump_avail[0]));
 	vm_max_kernel_address = KERNVIRTADDR + 3 * memsize;
 	pmap_bootstrap(freemempos, &kernel_l1pt);
 	msgbufp = (void*)msgbufpv.pv_va;
 	msgbufinit(msgbufp, msgbufsize);
 	mutex_init();
 
-	physmem = memsize / PAGE_SIZE;
-
-	phys_avail[0] = virtual_avail - KERNVIRTADDR + KERNPHYSADDR;
-	phys_avail[1] = PHYSADDR + memsize;
-	phys_avail[2] = 0;
-	phys_avail[3] = 0;
+	/*
+	 * Add the physical ram we have available.
+	 *
+	 * Exclude the kernel, and all the things we allocated which immediately
+	 * follow the kernel, from the VM allocation pool but not from crash
+	 * dumps.  virtual_avail is a global variable which tracks the kva we've
+	 * "allocated" while setting up pmaps.
+	 *
+	 * Prepare the list of physical memory available to the vm subsystem.
+	 */
+	arm_physmem_hardware_region(PHYSADDR, memsize);
+	arm_physmem_exclude_region(abp->abp_physaddr, 
+	    virtual_avail - KERNVIRTADDR, EXFLAG_NOALLOC);
+	arm_physmem_init_kernel_globals();
 
 	init_param2(physmem);
 	kdb_init();

Modified: head/sys/arm/sa11x0/assabet_machdep.c
==============================================================================
--- head/sys/arm/sa11x0/assabet_machdep.c	Sat Feb  8 22:21:38 2014	(r261642)
+++ head/sys/arm/sa11x0/assabet_machdep.c	Sat Feb  8 23:54:16 2014	(r261643)
@@ -122,8 +122,6 @@ extern vm_offset_t sa1_cache_clean_addr;
 #endif

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list