summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/arm/arm/machdep.c292
-rw-r--r--sys/arm/arm/physmem.c314
-rw-r--r--sys/arm/at91/at91_machdep.c30
-rw-r--r--sys/arm/econa/econa_machdep.c30
-rw-r--r--sys/arm/include/machdep.h3
-rw-r--r--sys/arm/include/physmem.h86
-rw-r--r--sys/arm/s3c2xx0/s3c24x0_machdep.c26
-rw-r--r--sys/arm/sa11x0/assabet_machdep.c2
-rw-r--r--sys/arm/xscale/i80321/ep80219_machdep.c3
-rw-r--r--sys/arm/xscale/i80321/iq31244_machdep.c3
-rw-r--r--sys/arm/xscale/i8134x/crb_machdep.c3
-rw-r--r--sys/arm/xscale/ixp425/avila_machdep.c26
-rw-r--r--sys/arm/xscale/pxa/pxa_machdep.c3
-rw-r--r--sys/conf/files.arm1
14 files changed, 494 insertions, 328 deletions
diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c
index e5edace..eacdec1 100644
--- a/sys/arm/arm/machdep.c
+++ b/sys/arm/arm/machdep.c
@@ -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 *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_params *abp)
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 (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);
- if (end > start) {
- availmem_regions[curr].mr_start = start;
- availmem_regions[curr++].mr_size = end - start;
- }
- }
-
- availmem_regions_sz = curr;
+ /* 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();
diff --git a/sys/arm/arm/physmem.c b/sys/arm/arm/physmem.c
new file mode 100644
index 0000000..db322fa
--- /dev/null
+++ b/sys/arm/arm/physmem.c
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 2014 Ian Lepore <ian@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 */
+
diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c
index 9e73d0c..d9d26d8 100644
--- a/sys/arm/at91/at91_machdep.c
+++ b/sys/arm/at91/at91_machdep.c
@@ -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_devmap[] = {
/* 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 -
diff --git a/sys/arm/econa/econa_machdep.c b/sys/arm/econa/econa_machdep.c
index 8f41494..d2b97b6 100644
--- a/sys/arm/econa/econa_machdep.c
+++ b/sys/arm/econa/econa_machdep.c
@@ -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_KERNEL_PTS];
/* 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;
+ /*
+ * 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();
- phys_avail[i++] = PHYSADDR + memsize;
- phys_avail[i++] = 0;
- phys_avail[i++] = 0;
init_param2(physmem);
kdb_init();
diff --git a/sys/arm/include/machdep.h b/sys/arm/include/machdep.h
index 0a55849..c37f386 100644
--- a/sys/arm/include/machdep.h
+++ b/sys/arm/include/machdep.h
@@ -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_ */
diff --git a/sys/arm/include/physmem.h b/sys/arm/include/physmem.h
new file mode 100644
index 0000000..1779d28
--- /dev/null
+++ b/sys/arm/include/physmem.h
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2014 Ian Lepore <ian@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
+
diff --git a/sys/arm/s3c2xx0/s3c24x0_machdep.c b/sys/arm/s3c2xx0/s3c24x0_machdep.c
index 84776e8..b306355 100644
--- a/sys/arm/s3c2xx0/s3c24x0_machdep.c
+++ b/sys/arm/s3c2xx0/s3c24x0_machdep.c
@@ -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_KERNEL_PTS];
/* 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();
diff --git a/sys/arm/sa11x0/assabet_machdep.c b/sys/arm/sa11x0/assabet_machdep.c
index 56b0f30..220db17 100644
--- a/sys/arm/sa11x0/assabet_machdep.c
+++ b/sys/arm/sa11x0/assabet_machdep.c
@@ -122,8 +122,6 @@ extern vm_offset_t sa1_cache_clean_addr;
#endif
/* Physical and virtual addresses for some global pages */
-vm_paddr_t phys_avail[10];
-vm_paddr_t dump_avail[4];
vm_paddr_t physical_start;
vm_paddr_t physical_end;
vm_paddr_t physical_freestart;
diff --git a/sys/arm/xscale/i80321/ep80219_machdep.c b/sys/arm/xscale/i80321/ep80219_machdep.c
index 44610ea..cf2e35e 100644
--- a/sys/arm/xscale/i80321/ep80219_machdep.c
+++ b/sys/arm/xscale/i80321/ep80219_machdep.c
@@ -110,9 +110,6 @@ struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
/* 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;
diff --git a/sys/arm/xscale/i80321/iq31244_machdep.c b/sys/arm/xscale/i80321/iq31244_machdep.c
index d6b1b93..8b1de79 100644
--- a/sys/arm/xscale/i80321/iq31244_machdep.c
+++ b/sys/arm/xscale/i80321/iq31244_machdep.c
@@ -110,9 +110,6 @@ struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
/* 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;
diff --git a/sys/arm/xscale/i8134x/crb_machdep.c b/sys/arm/xscale/i8134x/crb_machdep.c
index 29258d0..b411635 100644
--- a/sys/arm/xscale/i8134x/crb_machdep.c
+++ b/sys/arm/xscale/i8134x/crb_machdep.c
@@ -113,9 +113,6 @@ struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
/* 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;
diff --git a/sys/arm/xscale/ixp425/avila_machdep.c b/sys/arm/xscale/ixp425/avila_machdep.c
index f95480a..7b63f92 100644
--- a/sys/arm/xscale/ixp425/avila_machdep.c
+++ b/sys/arm/xscale/ixp425/avila_machdep.c
@@ -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>
@@ -114,9 +115,6 @@ struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
/* 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;
@@ -391,7 +389,6 @@ initarm(struct arm_boot_params *abp)
memsize = ixp435_ddram_size();
else
memsize = ixp425_sdram_size();
- physmem = memsize / PAGE_SIZE;
/* Set stack for exception handlers */
@@ -405,19 +402,26 @@ initarm(struct arm_boot_params *abp)
arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
pmap_curmaxkvaddr = afterkern + PAGE_SIZE;
- arm_dump_avail_init(abp->abp_physaddr, memsize,
- sizeof(dump_avail) / sizeof(dump_avail[0]));
vm_max_kernel_address = 0xe0000000;
pmap_bootstrap(pmap_curmaxkvaddr, &kernel_l1pt);
msgbufp = (void*)msgbufpv.pv_va;
msgbufinit(msgbufp, msgbufsize);
mutex_init();
- i = 0;
- phys_avail[i++] = round_page(virtual_avail - KERNBASE + PHYSADDR);
- phys_avail[i++] = trunc_page(PHYSADDR + memsize - 1);
- 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();
diff --git a/sys/arm/xscale/pxa/pxa_machdep.c b/sys/arm/xscale/pxa/pxa_machdep.c
index 860dd7e..dfaccef 100644
--- a/sys/arm/xscale/pxa/pxa_machdep.c
+++ b/sys/arm/xscale/pxa/pxa_machdep.c
@@ -110,9 +110,6 @@ struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
/* Physical and virtual addresses for some global pages */
-vm_paddr_t phys_avail[PXA2X0_SDRAM_BANKS * 2 + 4];
-vm_paddr_t dump_avail[PXA2X0_SDRAM_BANKS * 2 + 4];
-
struct pv_addr systempage;
struct pv_addr msgbufpv;
struct pv_addr irqstack;
diff --git a/sys/conf/files.arm b/sys/conf/files.arm
index f2d0244..71478e3 100644
--- a/sys/conf/files.arm
+++ b/sys/conf/files.arm
@@ -33,6 +33,7 @@ arm/arm/mem.c optional mem
arm/arm/minidump_machdep.c optional mem
arm/arm/mp_machdep.c optional smp
arm/arm/nexus.c standard
+arm/arm/physmem.c standard
arm/arm/pl190.c optional pl190
arm/arm/pl310.c optional pl310
arm/arm/pmap.c optional cpu_arm9 | cpu_arm9e | cpu_fa526 | cpu_sa1100 | cpu_sa1110 | cpu_xscale_80219 | cpu_xscale_80321 | cpu_xscale_81342 | cpu_xscale_ixp425 | cpu_xscale_ixp435 | cpu_xscale_pxa2x0
OpenPOWER on IntegriCloud