Index: head/sys/arm/arm/machdep.c =================================================================== --- head/sys/arm/arm/machdep.c +++ head/sys/arm/arm/machdep.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -83,7 +84,6 @@ #include #include #include -#include #include #include #include @@ -123,6 +123,9 @@ int cold = 1; vm_offset_t vector_page; +/* The address at which the kernel was loaded. Set early in initarm(). */ +vm_paddr_t arm_physmem_kernaddr; + int (*_arm_memcpy)(void *, void *, int, int) = NULL; int (*_arm_bzero)(void *, int, int) = NULL; int _min_memcpy_size = 0; @@ -160,7 +163,6 @@ #endif struct kva_md_info kmi; - /* * arm32_vector_init: * @@ -237,7 +239,7 @@ (uintmax_t)arm32_ptob(vm_free_count()), (uintmax_t)arm32_ptob(vm_free_count()) / mbyte); if (bootverbose) { - arm_physmem_print_tables(); + physmem_print_tables(); devmap_print_table(); } @@ -870,11 +872,11 @@ /* Grab physical memory regions information from device tree. */ 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); + physmem_hardware_regions(mem_regions, mem_regions_sz); /* Grab reserved memory regions information from device tree. */ if (fdt_get_reserved_regions(mem_regions, &mem_regions_sz) == 0) - arm_physmem_exclude_regions(mem_regions, mem_regions_sz, + physmem_exclude_regions(mem_regions, mem_regions_sz, EXFLAG_NODUMP | EXFLAG_NOALLOC); /* Platform-specific initialisation */ @@ -1081,9 +1083,9 @@ * * Prepare the list of physical memory available to the vm subsystem. */ - arm_physmem_exclude_region(abp->abp_physaddr, + physmem_exclude_region(abp->abp_physaddr, (virtual_avail - KERNVIRTADDR), EXFLAG_NOALLOC); - arm_physmem_init_kernel_globals(); + physmem_init_kernel_globals(); init_param2(physmem); dbg_monitor_init(); @@ -1149,11 +1151,11 @@ if (fdt_get_mem_regions(mem_regions, &mem_regions_sz,NULL) != 0) panic("Cannot get physical memory regions"); } - arm_physmem_hardware_regions(mem_regions, mem_regions_sz); + physmem_hardware_regions(mem_regions, mem_regions_sz); /* Grab reserved memory regions information from device tree. */ if (fdt_get_reserved_regions(mem_regions, &mem_regions_sz) == 0) - arm_physmem_exclude_regions(mem_regions, mem_regions_sz, + physmem_exclude_regions(mem_regions, mem_regions_sz, EXFLAG_NODUMP | EXFLAG_NOALLOC); /* @@ -1288,9 +1290,9 @@ * * Prepare the list of physical memory available to the vm subsystem. */ - arm_physmem_exclude_region(abp->abp_physaddr, + physmem_exclude_region(abp->abp_physaddr, pmap_preboot_get_pages(0) - abp->abp_physaddr, EXFLAG_NOALLOC); - arm_physmem_init_kernel_globals(); + physmem_init_kernel_globals(); init_param2(physmem); /* Init message buffer. */ Index: head/sys/arm/arm/machdep_boot.c =================================================================== --- head/sys/arm/arm/machdep_boot.c +++ head/sys/arm/arm/machdep_boot.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #if defined(LINUX_BOOT_ABI) @@ -46,7 +47,6 @@ #include #include #include -#include #include /* For KERNVIRTADDR */ #ifdef FDT @@ -228,7 +228,7 @@ case ATAG_CORE: break; case ATAG_MEM: - arm_physmem_hardware_region(walker->u.tag_mem.start, + physmem_hardware_region(walker->u.tag_mem.start, walker->u.tag_mem.size); break; case ATAG_INITRD2: Index: head/sys/arm/arm/mp_machdep.c =================================================================== --- head/sys/arm/arm/mp_machdep.c +++ head/sys/arm/arm/mp_machdep.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #ifdef VFP Index: head/sys/arm/arm/physmem.c =================================================================== --- head/sys/arm/arm/physmem.c +++ head/sys/arm/arm/physmem.c @@ -1,406 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * 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. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "opt_acpi.h" -#include "opt_ddb.h" - -/* - * Routines for describing and initializing anything related to physical memory. - */ - -#include -#include -#include -#include -#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. - */ -#ifdef DEV_ACPI -#define MAX_HWCNT 32 /* ACPI needs more regions */ -#define MAX_EXCNT 32 -#else -#define MAX_HWCNT 16 -#define MAX_EXCNT 16 -#endif - -#if defined(__arm__) -#define MAX_PHYS_ADDR 0xFFFFFFFFull -#define pm_btop(x) arm32_btop(x) -#elif defined(__aarch64__) -#define MAX_PHYS_ADDR 0xFFFFFFFFFFFFFFFFull -#define pm_btop(x) arm64_btop(x) -#endif - -struct region { - vm_paddr_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; - -/* - * realmem is the total number of hardware pages, excluded or not. - * Maxmem is one greater than the last physical page number. - */ -long realmem; -long Maxmem; - -/* The address at which the kernel was loaded. Set early in initarm(). */ -vm_paddr_t arm_physmem_kernaddr; - -/* - * 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" : ""); - } - -#ifdef DEBUG - prfunc("Avail lists:\n"); - for (i = 0; phys_avail[i] != 0; ++i) { - prfunc(" phys_avail[%d] 0x%08x\n", i, phys_avail[i]); - } - for (i = 0; dump_avail[i] != 0; ++i) { - prfunc(" dump_avail[%d] 0x%08x\n", i, dump_avail[i]); - } -#endif -} - -/* - * Print the contents of the static mapping table. Used for bootverbose. - */ -void -arm_physmem_print_tables(void) -{ - - 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 value at *pavail with the sum of all pages in all hw regions. - * - * Returns the number of pages of non-excluded memory added to the avail list. - */ -static size_t -regions_to_avail(vm_paddr_t *avail, uint32_t exflags, size_t maxavail, - long *pavail, long *prealmem) -{ - size_t acnt, exi, hwi; - uint64_t end, start, xend, xstart; - long availmem, totalmem; - const struct region *exp, *hwp; - - totalmem = 0; - availmem = 0; - acnt = 0; - for (hwi = 0, hwp = hwregions; hwi < hwcnt; ++hwi, ++hwp) { - start = hwp->addr; - end = hwp->size + start; - totalmem += pm_btop((vm_offset_t)(end - start)); - for (exi = 0, exp = exregions; exi < excnt; ++exi, ++exp) { - /* - * If the excluded region does not match given flags, - * continue checking with the next excluded region. - */ - if ((exp->flags & exflags) == 0) - continue; - 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)) { - if (acnt > 0 && - avail[acnt - 1] == (vm_paddr_t)start) { - avail[acnt - 1] = (vm_paddr_t)xstart; - } else { - avail[acnt++] = (vm_paddr_t)start; - avail[acnt++] = (vm_paddr_t)xstart; - } - availmem += - pm_btop((vm_offset_t)(xstart - start)); - start = xend; - continue; - } - /* - * We know the excluded region overlaps either the start - * or end of this hardware region (but not both), trim - * the excluded portion off the appropriate end. - */ - if (xstart <= start) - start = xend; - else - end = xstart; - } - /* - * If the trimming actions above left a non-zero size, create an - * available entry for it. - */ - if (end > start) { - if (acnt > 0 && avail[acnt - 1] == (vm_paddr_t)start) { - avail[acnt - 1] = (vm_paddr_t)end; - } else { - avail[acnt++] = (vm_paddr_t)start; - avail[acnt++] = (vm_paddr_t)end; - } - availmem += pm_btop((vm_offset_t)(end - start)); - } - if (acnt >= maxavail) - panic("Not enough space in the dump/phys_avail arrays"); - } - - if (pavail != NULL) - *pavail = availmem; - if (prealmem != NULL) - *prealmem = totalmem; - return (acnt); -} - -/* - * Insertion-sort a new entry into a regions list; sorted by start address. - */ -static size_t -insert_region(struct region *regions, size_t rcnt, vm_paddr_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 (rp->addr == addr && rp->size == size) /* Pure dup. */ - return (rcnt); - if (flags == rp->flags) { - if (addr + size == rp->addr) { - rp->addr = addr; - rp->size += size; - return (rcnt); - } else if (rp->addr + rp->size == addr) { - rp->size += size; - return (rcnt); - } - } - if (addr < rp->addr) { - bcopy(rp, rp + 1, (ep - rp) * sizeof(*rp)); - break; - } - } - rp->addr = addr; - rp->size = size; - rp->flags = flags; - rcnt++; - - return (rcnt); -} - -/* - * Add a hardware memory region. - */ -void -arm_physmem_hardware_region(uint64_t pa, uint64_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) { - if (sz <= PAGE_SIZE) - return; - pa = PAGE_SIZE; - sz -= PAGE_SIZE; - } else if (pa > MAX_PHYS_ADDR) { - /* This range is past usable memory, ignore it */ - return; - } - - /* - * Also filter out the page at the end of the physical address space -- - * if addr is non-zero and addr+size is zero we wrapped to the next byte - * beyond what vm_paddr_t can express. That leads to a NULL pointer - * deref early in startup; work around it by leaving the last page out. - * - * XXX This just in: subtract out a whole megabyte, not just 1 page. - * Reducing the size by anything less than 1MB results in the NULL - * pointer deref in _vm_map_lock_read(). Better to give up a megabyte - * than leave some folks with an unusable system while we investigate. - */ - if ((pa + sz) > (MAX_PHYS_ADDR - 1024 * 1024)) { - sz = MAX_PHYS_ADDR - pa + 1; - if (sz <= 1024 * 1024) - return; - sz -= 1024 * 1024; - } - - /* - * 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 (sz > 0 && hwcnt < nitems(hwregions)) - hwcnt = insert_region(hwregions, hwcnt, pa, sz, 0); -} - -/* - * Add an exclusion region. - */ -void -arm_physmem_exclude_region(vm_paddr_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)) - panic("failed to exclude region %#jx-%#jx", (uintmax_t)pa, - (uintmax_t)(pa + sz)); - excnt = insert_region(exregions, excnt, pa, sz, exflags); -} - -size_t -arm_physmem_avail(vm_paddr_t *avail, size_t maxavail) -{ - - return (regions_to_avail(avail, EXFLAG_NOALLOC, maxavail, NULL, NULL)); -} - -/* - * Process all the regions added earlier into the global avail lists. - * - * Updates the kernel global 'physmem' with the number of physical pages - * available for use (all pages not in any exclusion region). - * - * Updates the kernel global 'Maxmem' with the page number one greater then the - * last page of physical memory in the system. - */ -void -arm_physmem_init_kernel_globals(void) -{ - size_t nextidx; - - regions_to_avail(dump_avail, EXFLAG_NODUMP, PHYS_AVAIL_ENTRIES, NULL, - NULL); - nextidx = regions_to_avail(phys_avail, EXFLAG_NOALLOC, - PHYS_AVAIL_ENTRIES, &physmem, &realmem); - if (nextidx == 0) - panic("No memory entries in phys_avail"); - Maxmem = atop(phys_avail[nextidx - 1]); -} - -#ifdef DDB -#include - -DB_SHOW_COMMAND(physmem, db_show_physmem) -{ - - physmem_dump_tables(db_printf); -} - -#endif /* DDB */ - Index: head/sys/arm/arm/pmap-v6.c =================================================================== --- head/sys/arm/arm/pmap-v6.c +++ head/sys/arm/arm/pmap-v6.c @@ -117,8 +117,6 @@ #include #endif -#include - #include #include #include Index: head/sys/arm/include/md_var.h =================================================================== --- head/sys/arm/include/md_var.h +++ head/sys/arm/include/md_var.h @@ -42,6 +42,7 @@ extern int vm_page_dump_size; extern u_long elf_hwcap; extern u_long elf_hwcap2; +extern vm_paddr_t arm_physmem_kernaddr; extern int (*_arm_memcpy)(void *, void *, int, int); extern int (*_arm_bzero)(void *, int, int); Index: head/sys/arm/include/physmem.h =================================================================== --- head/sys/arm/include/physmem.h +++ head/sys/arm/include/physmem.h @@ -1,94 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * 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_ - -/* - * The physical address at which the kernel was loaded. - */ -extern vm_paddr_t arm_physmem_kernaddr; - -/* - * 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(uint64_t pa, uint64_t sz); -void arm_physmem_exclude_region(vm_paddr_t pa, vm_size_t sz, uint32_t flags); -size_t arm_physmem_avail(vm_paddr_t *avail, size_t maxavail); -void arm_physmem_init_kernel_globals(void); -void arm_physmem_print_tables(void); - -/* - * Convenience routines for FDT. - */ - -#ifdef FDT - -#include - -static 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; - } -} - -static 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 - Index: head/sys/arm64/arm64/machdep.c =================================================================== --- head/sys/arm64/arm64/machdep.c +++ head/sys/arm64/arm64/machdep.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -82,8 +83,6 @@ #include #include -#include - #ifdef VFP #include #endif @@ -855,7 +854,7 @@ */ break; default: - arm_physmem_exclude_region(p->md_phys, p->md_pages * PAGE_SIZE, + physmem_exclude_region(p->md_phys, p->md_pages * PAGE_SIZE, EXFLAG_NOALLOC); } } @@ -886,7 +885,7 @@ /* * We're allowed to use any entry with these types. */ - arm_physmem_hardware_region(p->md_phys, + physmem_hardware_region(p->md_phys, p->md_pages * PAGE_SIZE); break; } @@ -1113,10 +1112,10 @@ if (fdt_get_mem_regions(mem_regions, &mem_regions_sz, NULL) != 0) panic("Cannot get physical memory regions"); - arm_physmem_hardware_regions(mem_regions, mem_regions_sz); + physmem_hardware_regions(mem_regions, mem_regions_sz); } if (fdt_get_reserved_mem(mem_regions, &mem_regions_sz) == 0) - arm_physmem_exclude_regions(mem_regions, mem_regions_sz, + physmem_exclude_regions(mem_regions, mem_regions_sz, EXFLAG_NODUMP | EXFLAG_NOALLOC); #endif @@ -1124,7 +1123,7 @@ efifb = (struct efi_fb *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_EFI_FB); if (efifb != NULL) - arm_physmem_exclude_region(efifb->fb_addr, efifb->fb_size, + physmem_exclude_region(efifb->fb_addr, efifb->fb_size, EXFLAG_NOALLOC); /* Set the pcpu data, this is needed by pmap_bootstrap */ @@ -1153,7 +1152,7 @@ /* Exclude entries neexed in teh DMAP region, but not phys_avail */ if (efihdr != NULL) exclude_efi_map_entries(efihdr); - arm_physmem_init_kernel_globals(); + physmem_init_kernel_globals(); devmap_bootstrap(0, NULL); @@ -1182,7 +1181,7 @@ if (boothowto & RB_VERBOSE) { print_efi_map_entries(efihdr); - arm_physmem_print_tables(); + physmem_print_tables(); } early_boot = 0; Index: head/sys/arm64/arm64/pmap.c =================================================================== --- head/sys/arm64/arm64/pmap.c +++ head/sys/arm64/arm64/pmap.c @@ -119,6 +119,7 @@ #include #include #include +#include #include #include #include @@ -148,8 +149,6 @@ #include #include -#include - #define PMAP_ASSERT_STAGE1(pmap) MPASS((pmap)->pm_stage == PM_STAGE1) #define NL0PG (PAGE_SIZE/(sizeof (pd_entry_t))) @@ -861,7 +860,7 @@ /* Assume the address we were loaded to is a valid physical address */ min_pa = KERNBASE - kern_delta; - physmap_idx = arm_physmem_avail(physmap, nitems(physmap)); + physmap_idx = physmem_avail(physmap, nitems(physmap)); physmap_idx /= 2; /* @@ -942,7 +941,7 @@ pa = pmap_early_vtophys(l1pt, freemempos); - arm_physmem_exclude_region(start_pa, pa - start_pa, EXFLAG_NOALLOC); + physmem_exclude_region(start_pa, pa - start_pa, EXFLAG_NOALLOC); cpu_tlb_flushID(); } Index: head/sys/conf/files.arm =================================================================== --- head/sys/conf/files.arm +++ head/sys/conf/files.arm @@ -58,7 +58,6 @@ arm/arm/mpcore_timer.c optional mpcore_timer arm/arm/nexus.c standard arm/arm/ofw_machdep.c optional fdt -arm/arm/physmem.c standard arm/arm/pl190.c optional pl190 arm/arm/pl310.c optional pl310 arm/arm/platform.c optional platform @@ -116,6 +115,7 @@ kern/pic_if.m optional intrng kern/subr_busdma_bufalloc.c standard kern/subr_devmap.c standard +kern/subr_physmem.c standard kern/subr_sfbuf.c standard libkern/arm/aeabi_unwind.c standard libkern/arm/divsi3.S standard Index: head/sys/conf/files.arm64 =================================================================== --- head/sys/conf/files.arm64 +++ head/sys/conf/files.arm64 @@ -85,7 +85,6 @@ arm/arm/gic_acpi.c optional acpi arm/arm/gic_fdt.c optional fdt arm/arm/pmu.c standard -arm/arm/physmem.c standard arm/broadcom/bcm2835/bcm2835_audio.c optional sound vchiq fdt \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc fdt @@ -291,6 +290,7 @@ kern/pic_if.m optional intrng kern/subr_devmap.c standard kern/subr_intr.c optional intrng +kern/subr_physmem.c standard libkern/bcmp.c standard libkern/memcmp.c standard \ compile-with "${NORMAL_C:N-fsanitize*}" Index: head/sys/kern/subr_physmem.c =================================================================== --- head/sys/kern/subr_physmem.c +++ head/sys/kern/subr_physmem.c @@ -0,0 +1,399 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_acpi.h" +#include "opt_ddb.h" + +/* + * Routines for describing and initializing anything related to physical memory. + */ + +#include +#include +#include +#include +#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. + */ +#ifdef DEV_ACPI +#define MAX_HWCNT 32 /* ACPI needs more regions */ +#define MAX_EXCNT 32 +#else +#define MAX_HWCNT 16 +#define MAX_EXCNT 16 +#endif + +#if defined(__arm__) +#define MAX_PHYS_ADDR 0xFFFFFFFFull +#elif defined(__aarch64__) || defined(__riscv) +#define MAX_PHYS_ADDR 0xFFFFFFFFFFFFFFFFull +#endif + +struct region { + vm_paddr_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; + +/* + * realmem is the total number of hardware pages, excluded or not. + * Maxmem is one greater than the last physical page number. + */ +long realmem; +long Maxmem; + +/* + * 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" : ""); + } + +#ifdef DEBUG + prfunc("Avail lists:\n"); + for (i = 0; phys_avail[i] != 0; ++i) { + prfunc(" phys_avail[%d] 0x%08x\n", i, phys_avail[i]); + } + for (i = 0; dump_avail[i] != 0; ++i) { + prfunc(" dump_avail[%d] 0x%08x\n", i, dump_avail[i]); + } +#endif +} + +/* + * Print the contents of the static mapping table. Used for bootverbose. + */ +void +physmem_print_tables(void) +{ + + 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 value at *pavail with the sum of all pages in all hw regions. + * + * Returns the number of pages of non-excluded memory added to the avail list. + */ +static size_t +regions_to_avail(vm_paddr_t *avail, uint32_t exflags, size_t maxavail, + long *pavail, long *prealmem) +{ + size_t acnt, exi, hwi; + uint64_t end, start, xend, xstart; + long availmem, totalmem; + const struct region *exp, *hwp; + + totalmem = 0; + availmem = 0; + acnt = 0; + for (hwi = 0, hwp = hwregions; hwi < hwcnt; ++hwi, ++hwp) { + start = hwp->addr; + end = hwp->size + start; + totalmem += atop((vm_offset_t)(end - start)); + for (exi = 0, exp = exregions; exi < excnt; ++exi, ++exp) { + /* + * If the excluded region does not match given flags, + * continue checking with the next excluded region. + */ + if ((exp->flags & exflags) == 0) + continue; + 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)) { + if (acnt > 0 && + avail[acnt - 1] == (vm_paddr_t)start) { + avail[acnt - 1] = (vm_paddr_t)xstart; + } else { + avail[acnt++] = (vm_paddr_t)start; + avail[acnt++] = (vm_paddr_t)xstart; + } + availmem += atop((vm_offset_t)(xstart - start)); + start = xend; + continue; + } + /* + * We know the excluded region overlaps either the start + * or end of this hardware region (but not both), trim + * the excluded portion off the appropriate end. + */ + if (xstart <= start) + start = xend; + else + end = xstart; + } + /* + * If the trimming actions above left a non-zero size, create an + * available entry for it. + */ + if (end > start) { + if (acnt > 0 && avail[acnt - 1] == (vm_paddr_t)start) { + avail[acnt - 1] = (vm_paddr_t)end; + } else { + avail[acnt++] = (vm_paddr_t)start; + avail[acnt++] = (vm_paddr_t)end; + } + availmem += atop((vm_offset_t)(end - start)); + } + if (acnt >= maxavail) + panic("Not enough space in the dump/phys_avail arrays"); + } + + if (pavail != NULL) + *pavail = availmem; + if (prealmem != NULL) + *prealmem = totalmem; + return (acnt); +} + +/* + * Insertion-sort a new entry into a regions list; sorted by start address. + */ +static size_t +insert_region(struct region *regions, size_t rcnt, vm_paddr_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 (rp->addr == addr && rp->size == size) /* Pure dup. */ + return (rcnt); + if (flags == rp->flags) { + if (addr + size == rp->addr) { + rp->addr = addr; + rp->size += size; + return (rcnt); + } else if (rp->addr + rp->size == addr) { + rp->size += size; + return (rcnt); + } + } + if (addr < rp->addr) { + bcopy(rp, rp + 1, (ep - rp) * sizeof(*rp)); + break; + } + } + rp->addr = addr; + rp->size = size; + rp->flags = flags; + rcnt++; + + return (rcnt); +} + +/* + * Add a hardware memory region. + */ +void +physmem_hardware_region(uint64_t pa, uint64_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) { + if (sz <= PAGE_SIZE) + return; + pa = PAGE_SIZE; + sz -= PAGE_SIZE; + } else if (pa > MAX_PHYS_ADDR) { + /* This range is past usable memory, ignore it */ + return; + } + + /* + * Also filter out the page at the end of the physical address space -- + * if addr is non-zero and addr+size is zero we wrapped to the next byte + * beyond what vm_paddr_t can express. That leads to a NULL pointer + * deref early in startup; work around it by leaving the last page out. + * + * XXX This just in: subtract out a whole megabyte, not just 1 page. + * Reducing the size by anything less than 1MB results in the NULL + * pointer deref in _vm_map_lock_read(). Better to give up a megabyte + * than leave some folks with an unusable system while we investigate. + */ + if ((pa + sz) > (MAX_PHYS_ADDR - 1024 * 1024)) { + sz = MAX_PHYS_ADDR - pa + 1; + if (sz <= 1024 * 1024) + return; + sz -= 1024 * 1024; + } + + /* + * 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 (sz > 0 && hwcnt < nitems(hwregions)) + hwcnt = insert_region(hwregions, hwcnt, pa, sz, 0); +} + +/* + * Add an exclusion region. + */ +void +physmem_exclude_region(vm_paddr_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)) + panic("failed to exclude region %#jx-%#jx", (uintmax_t)pa, + (uintmax_t)(pa + sz)); + excnt = insert_region(exregions, excnt, pa, sz, exflags); +} + +size_t +physmem_avail(vm_paddr_t *avail, size_t maxavail) +{ + + return (regions_to_avail(avail, EXFLAG_NOALLOC, maxavail, NULL, NULL)); +} + +/* + * Process all the regions added earlier into the global avail lists. + * + * Updates the kernel global 'physmem' with the number of physical pages + * available for use (all pages not in any exclusion region). + * + * Updates the kernel global 'Maxmem' with the page number one greater then the + * last page of physical memory in the system. + */ +void +physmem_init_kernel_globals(void) +{ + size_t nextidx; + + regions_to_avail(dump_avail, EXFLAG_NODUMP, PHYS_AVAIL_ENTRIES, NULL, + NULL); + nextidx = regions_to_avail(phys_avail, EXFLAG_NOALLOC, + PHYS_AVAIL_ENTRIES, &physmem, &realmem); + if (nextidx == 0) + panic("No memory entries in phys_avail"); + Maxmem = atop(phys_avail[nextidx - 1]); +} + +#ifdef DDB +#include + +DB_SHOW_COMMAND(physmem, db_show_physmem) +{ + + physmem_dump_tables(db_printf); +} + +#endif /* DDB */ Index: head/sys/sys/physmem.h =================================================================== --- head/sys/sys/physmem.h +++ head/sys/sys/physmem.h @@ -0,0 +1,88 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * 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 _SYS_PHYSMEM_H_ +#define _SYS_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, + * 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 physmem_hardware_region(uint64_t pa, uint64_t sz); +void physmem_exclude_region(vm_paddr_t pa, vm_size_t sz, uint32_t flags); +size_t physmem_avail(vm_paddr_t *avail, size_t maxavail); +void physmem_init_kernel_globals(void); +void physmem_print_tables(void); + +/* + * Convenience routines for FDT. + */ + +#ifdef FDT + +#include + +static inline void +physmem_hardware_regions(struct mem_region * mrptr, int mrcount) +{ + while (mrcount--) { + physmem_hardware_region(mrptr->mr_start, mrptr->mr_size); + ++mrptr; + } +} + +static inline void +physmem_exclude_regions(struct mem_region * mrptr, int mrcount, + uint32_t exflags) +{ + while (mrcount--) { + physmem_exclude_region(mrptr->mr_start, mrptr->mr_size, + exflags); + ++mrptr; + } +} + +#endif /* FDT */ + +#endif /* !_SYS_PHYSMEM_H_ */