diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c index e5edaceba884..eacdec1e1567 100644 --- a/sys/arm/arm/machdep.c +++ b/sys/arm/arm/machdep.c @@ -97,6 +97,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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(); @@ -779,44 +761,6 @@ makectx(struct trapframe *tf, struct pcb *pcb) pcb->un_32.pcb32_sp = tf->tf_usr_sp; } -/* - * 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 */ @@ -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); + 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 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; + /* 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 000000000000..db322fa6b2e5 --- /dev/null +++ b/sys/arm/arm/physmem.c @@ -0,0 +1,314 @@ +/*- + * Copyright (c) 2014 Ian Lepore + * 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 +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" + +/* + * Routines for describing and initializing anything related to physical memory. + */ + +#include +#include +#include +#include + +/* + * 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 + +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 9e73d0cc7543..d9d26d873316 100644 --- a/sys/arm/at91/at91_machdep.c +++ b/sys/arm/at91/at91_machdep.c @@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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 8f41494ffeee..d2b97b6537a2 100644 --- a/sys/arm/econa/econa_machdep.c +++ b/sys/arm/econa/econa_machdep.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -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<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 0a558495a8f4..c37f38644dc3 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 000000000000..1779d2837cd9 --- /dev/null +++ b/sys/arm/include/physmem.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2014 Ian Lepore + * 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 + +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 84776e8d1dce..b30635555458 100644 --- a/sys/arm/s3c2xx0/s3c24x0_machdep.c +++ b/sys/arm/s3c2xx0/s3c24x0_machdep.c @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -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 56b0f3024386..220db1765a80 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 44610ea0474b..cf2e35ec73b3 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 d6b1b9359fa8..8b1de7973947 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 29258d01fc9c..b411635cd3fb 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 f95480ac8a5c..7b63f92bd60b 100644 --- a/sys/arm/xscale/ixp425/avila_machdep.c +++ b/sys/arm/xscale/ixp425/avila_machdep.c @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -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 860dd7e926b9..dfaccef1b118 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 f2d024443cf8..71478e3e3f23 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