1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <libcflat.h> 3 #include <devicetree.h> 4 #include <memregions.h> 5 6 static struct mem_region __initial_mem_regions[NR_INITIAL_MEM_REGIONS + 1]; 7 static size_t nr_regions = NR_INITIAL_MEM_REGIONS; 8 9 struct mem_region *mem_regions = __initial_mem_regions; 10 11 void memregions_init(struct mem_region regions[], size_t nr) 12 { 13 mem_regions = regions; 14 nr_regions = nr; 15 } 16 17 struct mem_region *memregions_add(struct mem_region *r) 18 { 19 struct mem_region *r_next = mem_regions; 20 int i = 0; 21 22 for (; r_next->end; ++r_next, ++i) 23 ; 24 assert(i < nr_regions); 25 26 *r_next = *r; 27 28 return r_next; 29 } 30 31 struct mem_region *memregions_find(phys_addr_t paddr) 32 { 33 struct mem_region *r; 34 35 for (r = mem_regions; r->end; ++r) 36 if (paddr >= r->start && paddr < r->end) 37 return r; 38 return NULL; 39 } 40 41 uint32_t memregions_get_flags(phys_addr_t paddr) 42 { 43 struct mem_region *r = memregions_find(paddr); 44 45 return r ? r->flags : MR_F_UNKNOWN; 46 } 47 48 void memregions_split(phys_addr_t addr, struct mem_region **r1, struct mem_region **r2) 49 { 50 *r1 = memregions_find(addr); 51 assert(*r1); 52 53 if ((*r1)->start == addr) { 54 *r2 = *r1; 55 *r1 = NULL; 56 return; 57 } 58 59 *r2 = memregions_add(&(struct mem_region){ 60 .start = addr, 61 .end = (*r1)->end, 62 .flags = (*r1)->flags, 63 }); 64 65 (*r1)->end = addr; 66 } 67 68 void memregions_add_dt_regions(size_t max_nr) 69 { 70 struct dt_pbus_reg regs[max_nr]; 71 int nr_regs, i; 72 73 nr_regs = dt_get_memory_params(regs, max_nr); 74 assert(nr_regs > 0); 75 76 for (i = 0; i < nr_regs; ++i) { 77 memregions_add(&(struct mem_region){ 78 .start = regs[i].addr, 79 .end = regs[i].addr + regs[i].size, 80 }); 81 } 82 } 83 84 #ifdef CONFIG_EFI 85 /* 86 * Add memory regions based on the EFI memory map. Also set a pointer to the 87 * memory region which corresponds to the largest EFI_CONVENTIONAL_MEMORY 88 * region, as that region is the largest free, continuous region, making it 89 * a good choice for the memory allocator. 90 */ 91 void memregions_efi_init(struct efi_boot_memmap *mem_map, 92 struct mem_region **freemem) 93 { 94 u8 *buffer = (u8 *)*mem_map->map; 95 u64 freemem_pages = 0; 96 97 *freemem = NULL; 98 99 for (int i = 0; i < *mem_map->map_size; i += *mem_map->desc_size) { 100 efi_memory_desc_t *d = (efi_memory_desc_t *)&buffer[i]; 101 struct mem_region r = { 102 .start = d->phys_addr, 103 .end = d->phys_addr + d->num_pages * EFI_PAGE_SIZE, 104 .flags = 0, 105 }; 106 107 switch (d->type) { 108 case EFI_MEMORY_MAPPED_IO: 109 case EFI_MEMORY_MAPPED_IO_PORT_SPACE: 110 r.flags = MR_F_IO; 111 break; 112 case EFI_LOADER_CODE: 113 r.flags = MR_F_CODE; 114 break; 115 case EFI_LOADER_DATA: 116 case EFI_ACPI_RECLAIM_MEMORY: 117 break; 118 case EFI_PERSISTENT_MEMORY: 119 r.flags = MR_F_PERSISTENT; 120 break; 121 case EFI_CONVENTIONAL_MEMORY: 122 if (freemem_pages < d->num_pages) { 123 freemem_pages = d->num_pages; 124 *freemem = memregions_add(&r); 125 continue; 126 } 127 break; 128 default: 129 r.flags = MR_F_RESERVED; 130 break; 131 } 132 133 memregions_add(&r); 134 } 135 } 136 #endif /* CONFIG_EFI */ 137