[kvm-unit-tests PATCH v2 16/24] arm/arm64: Share memregions
Eric Auger
eric.auger at redhat.com
Thu Feb 1 04:03:54 PST 2024
Hi Drew,
On 1/26/24 15:23, Andrew Jones wrote:
> 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 at linux.dev>
> Acked-by: Thomas Huth <thuth at redhat.com>
> ---
> 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;
I think this would deserve to be split into several patches, esp. this
change in the implementation of
mem_regions_add_assumed and the init changes. At the moment this is pretty difficult to review
Eric
>
> /*
> * 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_ */
More information about the kvm-riscv
mailing list