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 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 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 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 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 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 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 */ 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; 118*6182cb91SAndrew Jones case EFI_BOOT_SERVICES_DATA: 119*6182cb91SAndrew Jones /* 120*6182cb91SAndrew Jones * FIXME: This would ideally be MR_F_RESERVED, but the 121*6182cb91SAndrew Jones * primary stack is in a region of this EFI type. 122*6182cb91SAndrew Jones */ 123*6182cb91SAndrew Jones break; 124fa8e5d67SAndrew Jones case EFI_PERSISTENT_MEMORY: 125fa8e5d67SAndrew Jones r.flags = MR_F_PERSISTENT; 126fa8e5d67SAndrew Jones break; 127fa8e5d67SAndrew Jones case EFI_CONVENTIONAL_MEMORY: 128fa8e5d67SAndrew Jones if (freemem_pages < d->num_pages) { 129fa8e5d67SAndrew Jones freemem_pages = d->num_pages; 130fa8e5d67SAndrew Jones *freemem = memregions_add(&r); 131fa8e5d67SAndrew Jones continue; 132fa8e5d67SAndrew Jones } 133fa8e5d67SAndrew Jones break; 134fa8e5d67SAndrew Jones default: 135fa8e5d67SAndrew Jones r.flags = MR_F_RESERVED; 136fa8e5d67SAndrew Jones break; 137fa8e5d67SAndrew Jones } 138fa8e5d67SAndrew Jones 139fa8e5d67SAndrew Jones memregions_add(&r); 140fa8e5d67SAndrew Jones } 141fa8e5d67SAndrew Jones } 142fa8e5d67SAndrew Jones #endif /* CONFIG_EFI */ 143