[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