[kvm-unit-tests PATCH 16/24] arm/arm64: Share memregions

Andrew Jones
2024-01-24T07:19:01Z

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@linux.dev>
---
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