Index: sys/amd64/amd64/machdep.c =================================================================== --- sys/amd64/amd64/machdep.c +++ sys/amd64/amd64/machdep.c @@ -124,6 +124,7 @@ #include #include #include +#include #include #include #include @@ -210,21 +211,6 @@ long Maxmem = 0; long realmem = 0; -/* - * The number of PHYSMAP entries must be one less than the number of - * PHYSSEG entries because the PHYSMAP entry that spans the largest - * physical address that is accessible by ISA DMA is split into two - * PHYSSEG entries. - */ -#define PHYSMAP_SIZE (2 * (VM_PHYSSEG_MAX - 1)) - -vm_paddr_t phys_avail[PHYSMAP_SIZE + 2]; -vm_paddr_t dump_avail[PHYSMAP_SIZE + 2]; - -/* must be 2 less so 0 0 can signal end of chunks */ -#define PHYS_AVAIL_ARRAY_END (nitems(phys_avail) - 2) -#define DUMP_AVAIL_ARRAY_END (nitems(dump_avail) - 2) - struct kva_md_info kmi; static struct trapframe proc0_tf; Index: sys/amd64/include/pmap.h =================================================================== --- sys/amd64/include/pmap.h +++ sys/amd64/include/pmap.h @@ -239,6 +239,8 @@ #include +#include + typedef u_int64_t pd_entry_t; typedef u_int64_t pt_entry_t; typedef u_int64_t pdp_entry_t; @@ -393,8 +395,6 @@ extern caddr_t CADDR1; extern pt_entry_t *CMAP1; -extern vm_paddr_t phys_avail[]; -extern vm_paddr_t dump_avail[]; extern vm_offset_t virtual_avail; extern vm_offset_t virtual_end; extern vm_paddr_t dmaplimit; Index: sys/conf/files.amd64 =================================================================== --- sys/conf/files.amd64 +++ sys/conf/files.amd64 @@ -618,6 +618,7 @@ isa/syscons_isa.c optional sc isa/vga_isa.c optional vga kern/kern_clocksource.c standard +kern/kern_physmem.c standard kern/imgact_aout.c optional compat_aout kern/imgact_gzip.c optional gzip kern/link_elf_obj.c standard Index: sys/conf/files.i386 =================================================================== --- sys/conf/files.i386 +++ sys/conf/files.i386 @@ -542,6 +542,7 @@ isa/syscons_isa.c optional sc isa/vga_isa.c optional vga kern/kern_clocksource.c standard +kern/kern_physmem.c standard kern/imgact_aout.c optional compat_aout kern/imgact_gzip.c optional gzip kern/subr_sfbuf.c standard Index: sys/i386/i386/machdep.c =================================================================== --- sys/i386/i386/machdep.c +++ sys/i386/i386/machdep.c @@ -127,6 +127,7 @@ #include #include #include +#include #include #include #include @@ -192,21 +193,6 @@ FEATURE(pae, "Physical Address Extensions"); #endif -/* - * The number of PHYSMAP entries must be one less than the number of - * PHYSSEG entries because the PHYSMAP entry that spans the largest - * physical address that is accessible by ISA DMA is split into two - * PHYSSEG entries. - */ -#define PHYSMAP_SIZE (2 * (VM_PHYSSEG_MAX - 1)) - -vm_paddr_t phys_avail[PHYSMAP_SIZE + 2]; -vm_paddr_t dump_avail[PHYSMAP_SIZE + 2]; - -/* must be 2 less so 0 0 can signal end of chunks */ -#define PHYS_AVAIL_ARRAY_END (nitems(phys_avail) - 2) -#define DUMP_AVAIL_ARRAY_END (nitems(dump_avail) - 2) - struct kva_md_info kmi; static struct trapframe proc0_tf; Index: sys/i386/include/pmap.h =================================================================== --- sys/i386/include/pmap.h +++ sys/i386/include/pmap.h @@ -171,6 +171,8 @@ #include +#include + #if defined(PAE) || defined(PAE_TABLES) typedef uint64_t pdpt_entry_t; @@ -358,8 +360,6 @@ extern caddr_t CADDR3; extern pt_entry_t *CMAP3; -extern vm_paddr_t phys_avail[]; -extern vm_paddr_t dump_avail[]; extern char *ptvmmap; /* poor name! */ extern vm_offset_t virtual_avail; extern vm_offset_t virtual_end; Index: sys/kern/kern_physmem.c =================================================================== --- /dev/null +++ sys/kern/kern_physmem.c @@ -0,0 +1,178 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Johannes Lundberg + * + * 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 +#include +#include + +static int phys_avail_free_count(void); +static void phys_avail_insert_at(int index, vm_paddr_t val); +static void phys_avail_delete_at(int index); + +vm_paddr_t phys_avail[PHYSMAP_SIZE + 2]; +vm_paddr_t dump_avail[PHYSMAP_SIZE + 2]; + +static int +phys_avail_free_count(void) +{ + int i; + + for (i = PHYS_AVAIL_ARRAY_END; i > 0 && + phys_avail[i - 1] == 0 && phys_avail[i] == 0; i -= 2); + + return (PHYS_AVAIL_ARRAY_END - i); +} + +static void +phys_avail_insert_at(int index, vm_paddr_t val) +{ + int i; + + KASSERT(phys_avail_free_count() > 0, + ("phys_avail_insert_at: phys_avail has no more free slots")); + KASSERT(index >= 0 && index <= PHYS_AVAIL_ARRAY_END, + ("phys_avail_insert_at: index %d is out of range", index)); + + for (i = PHYS_AVAIL_ARRAY_END; i >= index; i--) { + phys_avail[i + 1] = phys_avail[i]; + } + phys_avail[i + 1] = val; +} + +static void +phys_avail_delete_at(int index) +{ + int i; + + KASSERT(index >= 0 && index <= PHYS_AVAIL_ARRAY_END, + ("phys_avail_delete_at: index %d is out of range", index)); + + i = index; + while (i <= PHYS_AVAIL_ARRAY_END) { + phys_avail[i] = phys_avail[i + 1]; + i++; + } +} + +void +phys_avail_reserve(vm_paddr_t start, vm_paddr_t end) +{ + int deleted, i; + + KASSERT(start < end, ("phys_avail_reserve: invalid range start = " + "0x%016jx, end = 0x%016jx", (uintmax_t)start, (uintmax_t)end)); + + /* Check if new hole is before first segment. */ + if (end <= phys_avail[0]) + return; + + i = 0; + /* Check if between segments (inside existing hole) */ + while (phys_avail[i + 2] != 0 && phys_avail[i + 3] != 0) { + if (start >= phys_avail[i + 1] && end <= phys_avail[i + 2]) + return; + i += 2; + } + + /* Check if after last segment end (i+1). */ + if (start >= phys_avail[i + 1]) + return; + + i=0; + /* Check if inside any segment */ + while (phys_avail[i + 1] != 0) { + if (start > phys_avail[i] && end < phys_avail[i + 1]) { + phys_avail_insert_at(i + 1, end); + phys_avail_insert_at(i + 1, start); + return; + } + i += 2; + } + + /* Other cases */ + i=0; + while (phys_avail[i] < start && i <= PHYS_AVAIL_ARRAY_END) { + i++; + } + + if (phys_avail[i + 1] == 0) { + /* The new hole starts in the last segment and ends after. */ + phys_avail[i] = start; + return; + } + + /* At the index located on or after the new hole start. */ + if (i % 2 == 0) { + /* + * Even index mean beginning of a segment. If hole ends in + * segment, shrink the segment. If exact match, delete the + * segment. Other cases are handled below. + */ + if (start == phys_avail[i]) { + if (end < phys_avail[i + 1]) { + phys_avail[i] = end; + return; + } else if (end == phys_avail[i + 1]) { + phys_avail_delete_at(i); + phys_avail_delete_at(i); + return; + } + } + } else { + /* + * Odd index mean the hole starts inside a memory segment. + * Shrink segment to hole start. + */ + phys_avail[i] = start; + i++; + } + + deleted = 0; + while (phys_avail[i] <= end && phys_avail[i + 1] != 0) { + phys_avail_delete_at(i); + deleted++; + } + + /* At the index located after the new hole end. */ + if (i % 2 == 0 && deleted % 2 == 1) { + /* + * If index is even and odd number of entries have been deleted, + * we are at the end of a segment. Insert hole end before this + * segment end. + */ + phys_avail_insert_at(i, end); + } else if (i % 2 == 1) { + /* + * Odd index mean our hole ends in the previous segment, + * move segment start to new hole end. + */ + phys_avail[i - 1] = start; + } +} Index: sys/x86/acpica/srat.c =================================================================== --- sys/x86/acpica/srat.c +++ sys/x86/acpica/srat.c @@ -53,6 +53,7 @@ #include #include #include +#include #include @@ -431,7 +432,7 @@ parse_srat(void) { unsigned int idx, size; - vm_paddr_t addr; + vm_paddr_t start, end; int error; if (resource_disabled("srat", 0)) @@ -453,17 +454,18 @@ idx -= 2; size = sizeof(*cpus) * (max_apic_id + 1); - addr = trunc_page(phys_avail[idx + 1] - size); - KASSERT(addr >= phys_avail[idx], + end = phys_avail[idx + 1]; + start = trunc_page(end - size); + KASSERT(start >= phys_avail[idx], ("Not enough memory for SRAT table items")); - phys_avail[idx + 1] = addr - 1; + phys_avail_reserve(start, end); /* * We cannot rely on PHYS_TO_DMAP because this code is also used in * i386, so use pmap_mapbios to map the memory, this will end up using * the default memory attribute (WB), and the DMAP when available. */ - cpus = (struct cpu_info *)pmap_mapbios(addr, size); + cpus = (struct cpu_info *)pmap_mapbios(start, size); bzero(cpus, size); /* Index: sys/x86/include/physmem.h =================================================================== --- /dev/null +++ sys/x86/include/physmem.h @@ -0,0 +1,53 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 The FreeBSD Foundation + * Copyright (c) 1992 Terrence R. Lambert. + * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. + * + * 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. + */ + +#ifndef _MACHINE_PHYSMEM_H_ +#define _MACHINE_PHYSMEM_H_ + +#include +#include + +/* + * The number of PHYSMAP entries must be one less than the number of + * PHYSSEG entries because the PHYSMAP entry that spans the largest + * physical address that is accessible by ISA DMA is split into two + * PHYSSEG entries. + */ +#define PHYSMAP_SIZE (2 * (VM_PHYSSEG_MAX - 1)) + +/* must be 2 less so 0 0 can signal end of chunks */ +#define PHYS_AVAIL_ARRAY_END (nitems(phys_avail) - 2) +#define DUMP_AVAIL_ARRAY_END (nitems(dump_avail) - 2) + +/* kern_physmem.c */ +extern vm_paddr_t phys_avail[PHYSMAP_SIZE + 2]; +extern vm_paddr_t dump_avail[PHYSMAP_SIZE + 2]; +void phys_avail_reserve(vm_paddr_t start, vm_paddr_t end); + +#endif /* _MACHINE_PHYSMEM_H_ */