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 } 83*fa8e5d67SAndrew Jones 84*fa8e5d67SAndrew Jones #ifdef CONFIG_EFI 85*fa8e5d67SAndrew Jones /* 86*fa8e5d67SAndrew Jones * Add memory regions based on the EFI memory map. Also set a pointer to the 87*fa8e5d67SAndrew Jones * memory region which corresponds to the largest EFI_CONVENTIONAL_MEMORY 88*fa8e5d67SAndrew Jones * region, as that region is the largest free, continuous region, making it 89*fa8e5d67SAndrew Jones * a good choice for the memory allocator. 90*fa8e5d67SAndrew Jones */ 91*fa8e5d67SAndrew Jones void memregions_efi_init(struct efi_boot_memmap *mem_map, 92*fa8e5d67SAndrew Jones struct mem_region **freemem) 93*fa8e5d67SAndrew Jones { 94*fa8e5d67SAndrew Jones u8 *buffer = (u8 *)*mem_map->map; 95*fa8e5d67SAndrew Jones u64 freemem_pages = 0; 96*fa8e5d67SAndrew Jones 97*fa8e5d67SAndrew Jones *freemem = NULL; 98*fa8e5d67SAndrew Jones 99*fa8e5d67SAndrew Jones for (int i = 0; i < *mem_map->map_size; i += *mem_map->desc_size) { 100*fa8e5d67SAndrew Jones efi_memory_desc_t *d = (efi_memory_desc_t *)&buffer[i]; 101*fa8e5d67SAndrew Jones struct mem_region r = { 102*fa8e5d67SAndrew Jones .start = d->phys_addr, 103*fa8e5d67SAndrew Jones .end = d->phys_addr + d->num_pages * EFI_PAGE_SIZE, 104*fa8e5d67SAndrew Jones .flags = 0, 105*fa8e5d67SAndrew Jones }; 106*fa8e5d67SAndrew Jones 107*fa8e5d67SAndrew Jones switch (d->type) { 108*fa8e5d67SAndrew Jones case EFI_MEMORY_MAPPED_IO: 109*fa8e5d67SAndrew Jones case EFI_MEMORY_MAPPED_IO_PORT_SPACE: 110*fa8e5d67SAndrew Jones r.flags = MR_F_IO; 111*fa8e5d67SAndrew Jones break; 112*fa8e5d67SAndrew Jones case EFI_LOADER_CODE: 113*fa8e5d67SAndrew Jones r.flags = MR_F_CODE; 114*fa8e5d67SAndrew Jones break; 115*fa8e5d67SAndrew Jones case EFI_PERSISTENT_MEMORY: 116*fa8e5d67SAndrew Jones r.flags = MR_F_PERSISTENT; 117*fa8e5d67SAndrew Jones break; 118*fa8e5d67SAndrew Jones case EFI_CONVENTIONAL_MEMORY: 119*fa8e5d67SAndrew Jones if (freemem_pages < d->num_pages) { 120*fa8e5d67SAndrew Jones freemem_pages = d->num_pages; 121*fa8e5d67SAndrew Jones *freemem = memregions_add(&r); 122*fa8e5d67SAndrew Jones continue; 123*fa8e5d67SAndrew Jones } 124*fa8e5d67SAndrew Jones break; 125*fa8e5d67SAndrew Jones default: 126*fa8e5d67SAndrew Jones r.flags = MR_F_RESERVED; 127*fa8e5d67SAndrew Jones break; 128*fa8e5d67SAndrew Jones } 129*fa8e5d67SAndrew Jones 130*fa8e5d67SAndrew Jones memregions_add(&r); 131*fa8e5d67SAndrew Jones } 132*fa8e5d67SAndrew Jones } 133*fa8e5d67SAndrew Jones #endif /* CONFIG_EFI */ 134