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.
This commit is contained in:
ian 2014-02-08 23:54:16 +00:00
parent 5da54698fa
commit 30d95028f0
14 changed files with 494 additions and 328 deletions

View File

@ -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();
@ -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();

314
sys/arm/arm/physmem.c Normal file
View File

@ -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 */

View File

@ -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 -

View File

@ -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();

View File

@ -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_ */

86
sys/arm/include/physmem.h Normal file
View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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