xref: /kvm-unit-tests/lib/memregions.c (revision 611fe6dee79c5e9df560562163c085dbd4dfd387)
12479ae50SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only
22479ae50SAndrew Jones #include <libcflat.h>
32479ae50SAndrew Jones #include <devicetree.h>
42479ae50SAndrew Jones #include <memregions.h>
52479ae50SAndrew Jones 
62479ae50SAndrew Jones static struct mem_region __initial_mem_regions[NR_INITIAL_MEM_REGIONS + 1];
72479ae50SAndrew Jones static size_t nr_regions = NR_INITIAL_MEM_REGIONS;
82479ae50SAndrew Jones 
92479ae50SAndrew Jones struct mem_region *mem_regions = __initial_mem_regions;
102479ae50SAndrew Jones 
memregions_init(struct mem_region regions[],size_t nr)112479ae50SAndrew Jones void memregions_init(struct mem_region regions[], size_t nr)
122479ae50SAndrew Jones {
132479ae50SAndrew Jones 	mem_regions = regions;
142479ae50SAndrew Jones 	nr_regions = nr;
152479ae50SAndrew Jones }
162479ae50SAndrew Jones 
memregions_add(struct mem_region * r)172479ae50SAndrew Jones struct mem_region *memregions_add(struct mem_region *r)
182479ae50SAndrew Jones {
192479ae50SAndrew Jones 	struct mem_region *r_next = mem_regions;
202479ae50SAndrew Jones 	int i = 0;
212479ae50SAndrew Jones 
222479ae50SAndrew Jones 	for (; r_next->end; ++r_next, ++i)
232479ae50SAndrew Jones 		;
242479ae50SAndrew Jones 	assert(i < nr_regions);
252479ae50SAndrew Jones 
262479ae50SAndrew Jones 	*r_next = *r;
272479ae50SAndrew Jones 
282479ae50SAndrew Jones 	return r_next;
292479ae50SAndrew Jones }
302479ae50SAndrew Jones 
memregions_find(phys_addr_t paddr)312479ae50SAndrew Jones struct mem_region *memregions_find(phys_addr_t paddr)
322479ae50SAndrew Jones {
332479ae50SAndrew Jones 	struct mem_region *r;
342479ae50SAndrew Jones 
352479ae50SAndrew Jones 	for (r = mem_regions; r->end; ++r)
362479ae50SAndrew Jones 		if (paddr >= r->start && paddr < r->end)
372479ae50SAndrew Jones 			return r;
382479ae50SAndrew Jones 	return NULL;
392479ae50SAndrew Jones }
402479ae50SAndrew Jones 
memregions_get_flags(phys_addr_t paddr)412479ae50SAndrew Jones uint32_t memregions_get_flags(phys_addr_t paddr)
422479ae50SAndrew Jones {
432479ae50SAndrew Jones 	struct mem_region *r = memregions_find(paddr);
442479ae50SAndrew Jones 
452479ae50SAndrew Jones 	return r ? r->flags : MR_F_UNKNOWN;
462479ae50SAndrew Jones }
472479ae50SAndrew Jones 
memregions_split(phys_addr_t addr,struct mem_region ** r1,struct mem_region ** r2)482479ae50SAndrew Jones void memregions_split(phys_addr_t addr, struct mem_region **r1, struct mem_region **r2)
492479ae50SAndrew Jones {
502479ae50SAndrew Jones 	*r1 = memregions_find(addr);
512479ae50SAndrew Jones 	assert(*r1);
522479ae50SAndrew Jones 
532479ae50SAndrew Jones 	if ((*r1)->start == addr) {
542479ae50SAndrew Jones 		*r2 = *r1;
552479ae50SAndrew Jones 		*r1 = NULL;
562479ae50SAndrew Jones 		return;
572479ae50SAndrew Jones 	}
582479ae50SAndrew Jones 
592479ae50SAndrew Jones 	*r2 = memregions_add(&(struct mem_region){
602479ae50SAndrew Jones 		.start = addr,
612479ae50SAndrew Jones 		.end = (*r1)->end,
622479ae50SAndrew Jones 		.flags = (*r1)->flags,
632479ae50SAndrew Jones 	});
642479ae50SAndrew Jones 
652479ae50SAndrew Jones 	(*r1)->end = addr;
662479ae50SAndrew Jones }
672479ae50SAndrew Jones 
memregions_add_dt_regions(size_t max_nr)682479ae50SAndrew Jones void memregions_add_dt_regions(size_t max_nr)
692479ae50SAndrew Jones {
702479ae50SAndrew Jones 	struct dt_pbus_reg regs[max_nr];
712479ae50SAndrew Jones 	int nr_regs, i;
722479ae50SAndrew Jones 
732479ae50SAndrew Jones 	nr_regs = dt_get_memory_params(regs, max_nr);
742479ae50SAndrew Jones 	assert(nr_regs > 0);
752479ae50SAndrew Jones 
762479ae50SAndrew Jones 	for (i = 0; i < nr_regs; ++i) {
772479ae50SAndrew Jones 		memregions_add(&(struct mem_region){
782479ae50SAndrew Jones 			.start = regs[i].addr,
792479ae50SAndrew Jones 			.end = regs[i].addr + regs[i].size,
802479ae50SAndrew Jones 		});
812479ae50SAndrew Jones 	}
822479ae50SAndrew Jones }
83fa8e5d67SAndrew Jones 
84fa8e5d67SAndrew Jones #ifdef CONFIG_EFI
85fa8e5d67SAndrew Jones /*
86fa8e5d67SAndrew Jones  * Add memory regions based on the EFI memory map. Also set a pointer to the
87fa8e5d67SAndrew Jones  * memory region which corresponds to the largest EFI_CONVENTIONAL_MEMORY
88fa8e5d67SAndrew Jones  * region, as that region is the largest free, continuous region, making it
89fa8e5d67SAndrew Jones  * a good choice for the memory allocator.
90fa8e5d67SAndrew Jones  */
memregions_efi_init(struct efi_boot_memmap * mem_map,struct mem_region ** freemem)91fa8e5d67SAndrew Jones void memregions_efi_init(struct efi_boot_memmap *mem_map,
92fa8e5d67SAndrew Jones 			 struct mem_region **freemem)
93fa8e5d67SAndrew Jones {
94fa8e5d67SAndrew Jones 	u8 *buffer = (u8 *)*mem_map->map;
95fa8e5d67SAndrew Jones 	u64 freemem_pages = 0;
96fa8e5d67SAndrew Jones 
97fa8e5d67SAndrew Jones 	*freemem = NULL;
98fa8e5d67SAndrew Jones 
99fa8e5d67SAndrew Jones 	for (int i = 0; i < *mem_map->map_size; i += *mem_map->desc_size) {
100fa8e5d67SAndrew Jones 		efi_memory_desc_t *d = (efi_memory_desc_t *)&buffer[i];
101fa8e5d67SAndrew Jones 		struct mem_region r = {
102fa8e5d67SAndrew Jones 			.start = d->phys_addr,
103fa8e5d67SAndrew Jones 			.end = d->phys_addr + d->num_pages * EFI_PAGE_SIZE,
104fa8e5d67SAndrew Jones 			.flags = 0,
105fa8e5d67SAndrew Jones 		};
106fa8e5d67SAndrew Jones 
107fa8e5d67SAndrew Jones 		switch (d->type) {
108fa8e5d67SAndrew Jones 		case EFI_MEMORY_MAPPED_IO:
109fa8e5d67SAndrew Jones 		case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
110fa8e5d67SAndrew Jones 			r.flags = MR_F_IO;
111fa8e5d67SAndrew Jones 			break;
112fa8e5d67SAndrew Jones 		case EFI_LOADER_CODE:
113fa8e5d67SAndrew Jones 			r.flags = MR_F_CODE;
114fa8e5d67SAndrew Jones 			break;
115*6182cb91SAndrew Jones 		case EFI_LOADER_DATA:
116*6182cb91SAndrew Jones 		case EFI_ACPI_RECLAIM_MEMORY:
117*6182cb91SAndrew Jones 			break;
118fa8e5d67SAndrew Jones 		case EFI_PERSISTENT_MEMORY:
119fa8e5d67SAndrew Jones 			r.flags = MR_F_PERSISTENT;
120fa8e5d67SAndrew Jones 			break;
121fa8e5d67SAndrew Jones 		case EFI_CONVENTIONAL_MEMORY:
122fa8e5d67SAndrew Jones 			if (freemem_pages < d->num_pages) {
123fa8e5d67SAndrew Jones 				freemem_pages = d->num_pages;
124fa8e5d67SAndrew Jones 				*freemem = memregions_add(&r);
125fa8e5d67SAndrew Jones 				continue;
126fa8e5d67SAndrew Jones 			}
127fa8e5d67SAndrew Jones 			break;
128fa8e5d67SAndrew Jones 		default:
129fa8e5d67SAndrew Jones 			r.flags = MR_F_RESERVED;
130fa8e5d67SAndrew Jones 			break;
131fa8e5d67SAndrew Jones 		}
132fa8e5d67SAndrew Jones 
133fa8e5d67SAndrew Jones 		memregions_add(&r);
134fa8e5d67SAndrew Jones 	}
135fa8e5d67SAndrew Jones }
136fa8e5d67SAndrew Jones #endif /* CONFIG_EFI */
137