arm/arm64 (and to a small extent powerpc) have memory regions which get built from hardware descriptions (DT/ACPI/EFI) and then used to build page tables. Move memregions to common code, tweaking the API a bit at the same time, e.g. change 'mem_region' to 'memregions'. The biggest change is there is now a default number of memory regions which, if too small, should be overridden at setup time with a new init function, memregions_init(). Signed-off-by: Andrew Jones <andrew.jones@xxxxxxxxx> --- arm/Makefile.common | 1 + arm/selftest.c | 3 +- lib/arm/asm/setup.h | 14 ------- lib/arm/mmu.c | 1 + lib/arm/setup.c | 93 ++++++++++----------------------------------- lib/memregions.c | 82 +++++++++++++++++++++++++++++++++++++++ lib/memregions.h | 29 ++++++++++++++ 7 files changed, 136 insertions(+), 87 deletions(-) create mode 100644 lib/memregions.c create mode 100644 lib/memregions.h diff --git a/arm/Makefile.common b/arm/Makefile.common index dc92a7433350..4dfd570fa59e 100644 --- a/arm/Makefile.common +++ b/arm/Makefile.common @@ -42,6 +42,7 @@ cflatobjs += lib/alloc_page.o cflatobjs += lib/vmalloc.o cflatobjs += lib/alloc.o cflatobjs += lib/devicetree.o +cflatobjs += lib/memregions.o cflatobjs += lib/migrate.o cflatobjs += lib/on-cpus.o cflatobjs += lib/pci.o diff --git a/arm/selftest.c b/arm/selftest.c index 9f459ed3d571..007d2309d01c 100644 --- a/arm/selftest.c +++ b/arm/selftest.c @@ -8,6 +8,7 @@ #include <libcflat.h> #include <util.h> #include <devicetree.h> +#include <memregions.h> #include <vmalloc.h> #include <asm/setup.h> #include <asm/ptrace.h> @@ -90,7 +91,7 @@ static bool check_pabt_init(void) highest_end = PAGE_ALIGN(r->end); } - if (mem_region_get_flags(highest_end) != MR_F_UNKNOWN) + if (memregions_get_flags(highest_end) != MR_F_UNKNOWN) return false; vaddr = (unsigned long)vmap(highest_end, PAGE_SIZE); diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h index 060691165a20..9f8ef82efb90 100644 --- a/lib/arm/asm/setup.h +++ b/lib/arm/asm/setup.h @@ -13,22 +13,8 @@ extern u64 cpus[NR_CPUS]; /* per-cpu IDs (MPIDRs) */ extern int nr_cpus; -#define MR_F_IO (1U << 0) -#define MR_F_CODE (1U << 1) -#define MR_F_RESERVED (1U << 2) -#define MR_F_UNKNOWN (1U << 31) - -struct mem_region { - phys_addr_t start; - phys_addr_t end; - unsigned int flags; -}; -extern struct mem_region *mem_regions; extern phys_addr_t __phys_offset, __phys_end; -extern struct mem_region *mem_region_find(phys_addr_t paddr); -extern unsigned int mem_region_get_flags(phys_addr_t paddr); - #define PHYS_OFFSET (__phys_offset) #define PHYS_END (__phys_end) diff --git a/lib/arm/mmu.c b/lib/arm/mmu.c index b16517a3200d..eb5e82a95f06 100644 --- a/lib/arm/mmu.c +++ b/lib/arm/mmu.c @@ -6,6 +6,7 @@ * This work is licensed under the terms of the GNU LGPL, version 2. */ #include <cpumask.h> +#include <memregions.h> #include <asm/setup.h> #include <asm/thread_info.h> #include <asm/mmu.h> diff --git a/lib/arm/setup.c b/lib/arm/setup.c index b6fc453e5b31..0382cbdaf5a1 100644 --- a/lib/arm/setup.c +++ b/lib/arm/setup.c @@ -13,6 +13,7 @@ #include <libcflat.h> #include <libfdt/libfdt.h> #include <devicetree.h> +#include <memregions.h> #include <alloc.h> #include <alloc_phys.h> #include <alloc_page.h> @@ -31,7 +32,7 @@ #define MAX_DT_MEM_REGIONS 16 #define NR_EXTRA_MEM_REGIONS 64 -#define NR_INITIAL_MEM_REGIONS (MAX_DT_MEM_REGIONS + NR_EXTRA_MEM_REGIONS) +#define NR_MEM_REGIONS (MAX_DT_MEM_REGIONS + NR_EXTRA_MEM_REGIONS) extern unsigned long _text, _etext, _data, _edata; @@ -41,8 +42,7 @@ u32 initrd_size; u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (u64)~0 }; int nr_cpus; -static struct mem_region __initial_mem_regions[NR_INITIAL_MEM_REGIONS + 1]; -struct mem_region *mem_regions = __initial_mem_regions; +static struct mem_region arm_mem_regions[NR_MEM_REGIONS + 1]; phys_addr_t __phys_offset = (phys_addr_t)-1, __phys_end = 0; extern void exceptions_init(void); @@ -114,68 +114,14 @@ static void cpu_init(void) set_cpu_online(0, true); } -static void mem_region_add(struct mem_region *r) +static void arm_memregions_add_assumed(void) { - struct mem_region *r_next = mem_regions; - int i = 0; - - for (; r_next->end; ++r_next, ++i) - ; - assert(i < NR_INITIAL_MEM_REGIONS); - - *r_next = *r; -} - -static void mem_regions_add_dt_regions(void) -{ - struct dt_pbus_reg regs[MAX_DT_MEM_REGIONS]; - int nr_regs, i; - - nr_regs = dt_get_memory_params(regs, MAX_DT_MEM_REGIONS); - assert(nr_regs > 0); - - for (i = 0; i < nr_regs; ++i) { - mem_region_add(&(struct mem_region){ - .start = regs[i].addr, - .end = regs[i].addr + regs[i].size, - }); - } -} - -struct mem_region *mem_region_find(phys_addr_t paddr) -{ - struct mem_region *r; - - for (r = mem_regions; r->end; ++r) - if (paddr >= r->start && paddr < r->end) - return r; - return NULL; -} - -unsigned int mem_region_get_flags(phys_addr_t paddr) -{ - struct mem_region *r = mem_region_find(paddr); - return r ? r->flags : MR_F_UNKNOWN; -} - -static void mem_regions_add_assumed(void) -{ - phys_addr_t code_end = (phys_addr_t)(unsigned long)&_etext; - struct mem_region *r; - - r = mem_region_find(code_end - 1); - assert(r); + struct mem_region *code, *data; /* Split the region with the code into two regions; code and data */ - mem_region_add(&(struct mem_region){ - .start = code_end, - .end = r->end, - }); - *r = (struct mem_region){ - .start = r->start, - .end = code_end, - .flags = MR_F_CODE, - }; + memregions_split((unsigned long)&_etext, &code, &data); + assert(code); + code->flags |= MR_F_CODE; /* * mach-virt I/O regions: @@ -183,10 +129,10 @@ static void mem_regions_add_assumed(void) * - 512M at 256G (arm64, arm uses highmem=off) * - 512G at 512G (arm64, arm uses highmem=off) */ - mem_region_add(&(struct mem_region){ 0, (1ul << 30), MR_F_IO }); + memregions_add(&(struct mem_region){ 0, (1ul << 30), MR_F_IO }); #ifdef __aarch64__ - mem_region_add(&(struct mem_region){ (1ul << 38), (1ul << 38) | (1ul << 29), MR_F_IO }); - mem_region_add(&(struct mem_region){ (1ul << 39), (1ul << 40), MR_F_IO }); + memregions_add(&(struct mem_region){ (1ul << 38), (1ul << 38) | (1ul << 29), MR_F_IO }); + memregions_add(&(struct mem_region){ (1ul << 39), (1ul << 40), MR_F_IO }); #endif } @@ -197,7 +143,7 @@ static void mem_init(phys_addr_t freemem_start) .start = (phys_addr_t)-1, }; - freemem = mem_region_find(freemem_start); + freemem = memregions_find(freemem_start); assert(freemem && !(freemem->flags & (MR_F_IO | MR_F_CODE))); for (r = mem_regions; r->end; ++r) { @@ -212,9 +158,9 @@ static void mem_init(phys_addr_t freemem_start) mem.end &= PHYS_MASK; /* Check for holes */ - r = mem_region_find(mem.start); + r = memregions_find(mem.start); while (r && r->end != mem.end) - r = mem_region_find(r->end); + r = memregions_find(r->end); assert(r); /* Ensure our selected freemem range is somewhere in our full range */ @@ -263,8 +209,9 @@ void setup(const void *fdt, phys_addr_t freemem_start) freemem += initrd_size; } - mem_regions_add_dt_regions(); - mem_regions_add_assumed(); + memregions_init(arm_mem_regions, NR_MEM_REGIONS); + memregions_add_dt_regions(MAX_DT_MEM_REGIONS); + arm_memregions_add_assumed(); mem_init(PAGE_ALIGN((unsigned long)freemem)); psci_set_conduit(); @@ -371,7 +318,7 @@ static efi_status_t efi_mem_init(efi_bootinfo_t *efi_bootinfo) assert(edata <= r.end); r.flags = MR_F_CODE; r.end = data; - mem_region_add(&r); + memregions_add(&r); r.start = data; r.end = tmp; r.flags = 0; @@ -393,7 +340,7 @@ static efi_status_t efi_mem_init(efi_bootinfo_t *efi_bootinfo) if (r.end > __phys_end) __phys_end = r.end; } - mem_region_add(&r); + memregions_add(&r); } if (fdt) { /* Move the FDT to the base of free memory */ @@ -439,6 +386,8 @@ efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo) exceptions_init(); + memregions_init(arm_mem_regions, NR_MEM_REGIONS); + status = efi_mem_init(efi_bootinfo); if (status != EFI_SUCCESS) { printf("Failed to initialize memory: "); diff --git a/lib/memregions.c b/lib/memregions.c new file mode 100644 index 000000000000..96de86b27333 --- /dev/null +++ b/lib/memregions.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <libcflat.h> +#include <devicetree.h> +#include <memregions.h> + +static struct mem_region __initial_mem_regions[NR_INITIAL_MEM_REGIONS + 1]; +static size_t nr_regions = NR_INITIAL_MEM_REGIONS; + +struct mem_region *mem_regions = __initial_mem_regions; + +void memregions_init(struct mem_region regions[], size_t nr) +{ + mem_regions = regions; + nr_regions = nr; +} + +struct mem_region *memregions_add(struct mem_region *r) +{ + struct mem_region *r_next = mem_regions; + int i = 0; + + for (; r_next->end; ++r_next, ++i) + ; + assert(i < nr_regions); + + *r_next = *r; + + return r_next; +} + +struct mem_region *memregions_find(phys_addr_t paddr) +{ + struct mem_region *r; + + for (r = mem_regions; r->end; ++r) + if (paddr >= r->start && paddr < r->end) + return r; + return NULL; +} + +uint32_t memregions_get_flags(phys_addr_t paddr) +{ + struct mem_region *r = memregions_find(paddr); + + return r ? r->flags : MR_F_UNKNOWN; +} + +void memregions_split(phys_addr_t addr, struct mem_region **r1, struct mem_region **r2) +{ + *r1 = memregions_find(addr); + assert(*r1); + + if ((*r1)->start == addr) { + *r2 = *r1; + *r1 = NULL; + return; + } + + *r2 = memregions_add(&(struct mem_region){ + .start = addr, + .end = (*r1)->end, + .flags = (*r1)->flags, + }); + + (*r1)->end = addr; +} + +void memregions_add_dt_regions(size_t max_nr) +{ + struct dt_pbus_reg regs[max_nr]; + int nr_regs, i; + + nr_regs = dt_get_memory_params(regs, max_nr); + assert(nr_regs > 0); + + for (i = 0; i < nr_regs; ++i) { + memregions_add(&(struct mem_region){ + .start = regs[i].addr, + .end = regs[i].addr + regs[i].size, + }); + } +} diff --git a/lib/memregions.h b/lib/memregions.h new file mode 100644 index 000000000000..9a8e33182fe5 --- /dev/null +++ b/lib/memregions.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _MEMREGIONS_H_ +#define _MEMREGIONS_H_ +#include <libcflat.h> +#include <bitops.h> + +#define NR_INITIAL_MEM_REGIONS 8 + +#define MR_F_IO BIT(0) +#define MR_F_CODE BIT(1) +#define MR_F_RESERVED BIT(2) +#define MR_F_UNKNOWN BIT(31) + +struct mem_region { + phys_addr_t start; + phys_addr_t end; + uint32_t flags; +}; + +extern struct mem_region *mem_regions; + +void memregions_init(struct mem_region regions[], size_t nr); +struct mem_region *memregions_add(struct mem_region *r); +struct mem_region *memregions_find(phys_addr_t paddr); +uint32_t memregions_get_flags(phys_addr_t paddr); +void memregions_split(phys_addr_t addr, struct mem_region **r1, struct mem_region **r2); +void memregions_add_dt_regions(size_t max_nr); + +#endif /* _MEMREGIONS_H_ */ -- 2.43.0