1*60863c0dSMatt Fleming /* 2*60863c0dSMatt Fleming * Common EFI memory map functions. 3*60863c0dSMatt Fleming */ 4*60863c0dSMatt Fleming 5*60863c0dSMatt Fleming #define pr_fmt(fmt) "efi: " fmt 6*60863c0dSMatt Fleming 7*60863c0dSMatt Fleming #include <linux/init.h> 8*60863c0dSMatt Fleming #include <linux/kernel.h> 9*60863c0dSMatt Fleming #include <linux/efi.h> 10*60863c0dSMatt Fleming #include <linux/io.h> 11*60863c0dSMatt Fleming #include <asm/early_ioremap.h> 12*60863c0dSMatt Fleming 13*60863c0dSMatt Fleming /** 14*60863c0dSMatt Fleming * __efi_memmap_init - Common code for mapping the EFI memory map 15*60863c0dSMatt Fleming * @data: EFI memory map data 16*60863c0dSMatt Fleming * @late: Use early or late mapping function? 17*60863c0dSMatt Fleming * 18*60863c0dSMatt Fleming * This function takes care of figuring out which function to use to 19*60863c0dSMatt Fleming * map the EFI memory map in efi.memmap based on how far into the boot 20*60863c0dSMatt Fleming * we are. 21*60863c0dSMatt Fleming * 22*60863c0dSMatt Fleming * During bootup @late should be %false since we only have access to 23*60863c0dSMatt Fleming * the early_memremap*() functions as the vmalloc space isn't setup. 24*60863c0dSMatt Fleming * Once the kernel is fully booted we can fallback to the more robust 25*60863c0dSMatt Fleming * memremap*() API. 26*60863c0dSMatt Fleming * 27*60863c0dSMatt Fleming * Returns zero on success, a negative error code on failure. 28*60863c0dSMatt Fleming */ 29*60863c0dSMatt Fleming static int __init 30*60863c0dSMatt Fleming __efi_memmap_init(struct efi_memory_map_data *data, bool late) 31*60863c0dSMatt Fleming { 32*60863c0dSMatt Fleming struct efi_memory_map map; 33*60863c0dSMatt Fleming phys_addr_t phys_map; 34*60863c0dSMatt Fleming 35*60863c0dSMatt Fleming if (efi_enabled(EFI_PARAVIRT)) 36*60863c0dSMatt Fleming return 0; 37*60863c0dSMatt Fleming 38*60863c0dSMatt Fleming phys_map = data->phys_map; 39*60863c0dSMatt Fleming 40*60863c0dSMatt Fleming if (late) 41*60863c0dSMatt Fleming map.map = memremap(phys_map, data->size, MEMREMAP_WB); 42*60863c0dSMatt Fleming else 43*60863c0dSMatt Fleming map.map = early_memremap(phys_map, data->size); 44*60863c0dSMatt Fleming 45*60863c0dSMatt Fleming if (!map.map) { 46*60863c0dSMatt Fleming pr_err("Could not map the memory map!\n"); 47*60863c0dSMatt Fleming return -ENOMEM; 48*60863c0dSMatt Fleming } 49*60863c0dSMatt Fleming 50*60863c0dSMatt Fleming map.phys_map = data->phys_map; 51*60863c0dSMatt Fleming map.nr_map = data->size / data->desc_size; 52*60863c0dSMatt Fleming map.map_end = map.map + data->size; 53*60863c0dSMatt Fleming 54*60863c0dSMatt Fleming map.desc_version = data->desc_version; 55*60863c0dSMatt Fleming map.desc_size = data->desc_size; 56*60863c0dSMatt Fleming map.late = late; 57*60863c0dSMatt Fleming 58*60863c0dSMatt Fleming set_bit(EFI_MEMMAP, &efi.flags); 59*60863c0dSMatt Fleming 60*60863c0dSMatt Fleming efi.memmap = map; 61*60863c0dSMatt Fleming 62*60863c0dSMatt Fleming return 0; 63*60863c0dSMatt Fleming } 64*60863c0dSMatt Fleming 65*60863c0dSMatt Fleming /** 66*60863c0dSMatt Fleming * efi_memmap_init_early - Map the EFI memory map data structure 67*60863c0dSMatt Fleming * @data: EFI memory map data 68*60863c0dSMatt Fleming * 69*60863c0dSMatt Fleming * Use early_memremap() to map the passed in EFI memory map and assign 70*60863c0dSMatt Fleming * it to efi.memmap. 71*60863c0dSMatt Fleming */ 72*60863c0dSMatt Fleming int __init efi_memmap_init_early(struct efi_memory_map_data *data) 73*60863c0dSMatt Fleming { 74*60863c0dSMatt Fleming /* Cannot go backwards */ 75*60863c0dSMatt Fleming WARN_ON(efi.memmap.late); 76*60863c0dSMatt Fleming 77*60863c0dSMatt Fleming return __efi_memmap_init(data, false); 78*60863c0dSMatt Fleming } 79*60863c0dSMatt Fleming 80*60863c0dSMatt Fleming void __init efi_memmap_unmap(void) 81*60863c0dSMatt Fleming { 82*60863c0dSMatt Fleming if (!efi.memmap.late) { 83*60863c0dSMatt Fleming unsigned long size; 84*60863c0dSMatt Fleming 85*60863c0dSMatt Fleming size = efi.memmap.desc_size * efi.memmap.nr_map; 86*60863c0dSMatt Fleming early_memunmap(efi.memmap.map, size); 87*60863c0dSMatt Fleming } else { 88*60863c0dSMatt Fleming memunmap(efi.memmap.map); 89*60863c0dSMatt Fleming } 90*60863c0dSMatt Fleming 91*60863c0dSMatt Fleming efi.memmap.map = NULL; 92*60863c0dSMatt Fleming clear_bit(EFI_MEMMAP, &efi.flags); 93*60863c0dSMatt Fleming } 94*60863c0dSMatt Fleming 95*60863c0dSMatt Fleming /** 96*60863c0dSMatt Fleming * efi_memmap_init_late - Map efi.memmap with memremap() 97*60863c0dSMatt Fleming * @phys_addr: Physical address of the new EFI memory map 98*60863c0dSMatt Fleming * @size: Size in bytes of the new EFI memory map 99*60863c0dSMatt Fleming * 100*60863c0dSMatt Fleming * Setup a mapping of the EFI memory map using ioremap_cache(). This 101*60863c0dSMatt Fleming * function should only be called once the vmalloc space has been 102*60863c0dSMatt Fleming * setup and is therefore not suitable for calling during early EFI 103*60863c0dSMatt Fleming * initialise, e.g. in efi_init(). Additionally, it expects 104*60863c0dSMatt Fleming * efi_memmap_init_early() to have already been called. 105*60863c0dSMatt Fleming * 106*60863c0dSMatt Fleming * The reason there are two EFI memmap initialisation 107*60863c0dSMatt Fleming * (efi_memmap_init_early() and this late version) is because the 108*60863c0dSMatt Fleming * early EFI memmap should be explicitly unmapped once EFI 109*60863c0dSMatt Fleming * initialisation is complete as the fixmap space used to map the EFI 110*60863c0dSMatt Fleming * memmap (via early_memremap()) is a scarce resource. 111*60863c0dSMatt Fleming * 112*60863c0dSMatt Fleming * This late mapping is intended to persist for the duration of 113*60863c0dSMatt Fleming * runtime so that things like efi_mem_desc_lookup() and 114*60863c0dSMatt Fleming * efi_mem_attributes() always work. 115*60863c0dSMatt Fleming * 116*60863c0dSMatt Fleming * Returns zero on success, a negative error code on failure. 117*60863c0dSMatt Fleming */ 118*60863c0dSMatt Fleming int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size) 119*60863c0dSMatt Fleming { 120*60863c0dSMatt Fleming struct efi_memory_map_data data = { 121*60863c0dSMatt Fleming .phys_map = addr, 122*60863c0dSMatt Fleming .size = size, 123*60863c0dSMatt Fleming }; 124*60863c0dSMatt Fleming 125*60863c0dSMatt Fleming /* Did we forget to unmap the early EFI memmap? */ 126*60863c0dSMatt Fleming WARN_ON(efi.memmap.map); 127*60863c0dSMatt Fleming 128*60863c0dSMatt Fleming /* Were we already called? */ 129*60863c0dSMatt Fleming WARN_ON(efi.memmap.late); 130*60863c0dSMatt Fleming 131*60863c0dSMatt Fleming /* 132*60863c0dSMatt Fleming * It makes no sense to allow callers to register different 133*60863c0dSMatt Fleming * values for the following fields. Copy them out of the 134*60863c0dSMatt Fleming * existing early EFI memmap. 135*60863c0dSMatt Fleming */ 136*60863c0dSMatt Fleming data.desc_version = efi.memmap.desc_version; 137*60863c0dSMatt Fleming data.desc_size = efi.memmap.desc_size; 138*60863c0dSMatt Fleming 139*60863c0dSMatt Fleming return __efi_memmap_init(&data, true); 140*60863c0dSMatt Fleming } 141*60863c0dSMatt Fleming 142*60863c0dSMatt Fleming /** 143*60863c0dSMatt Fleming * efi_memmap_split_count - Count number of additional EFI memmap entries 144*60863c0dSMatt Fleming * @md: EFI memory descriptor to split 145*60863c0dSMatt Fleming * @range: Address range (start, end) to split around 146*60863c0dSMatt Fleming * 147*60863c0dSMatt Fleming * Returns the number of additional EFI memmap entries required to 148*60863c0dSMatt Fleming * accomodate @range. 149*60863c0dSMatt Fleming */ 150*60863c0dSMatt Fleming int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range) 151*60863c0dSMatt Fleming { 152*60863c0dSMatt Fleming u64 m_start, m_end; 153*60863c0dSMatt Fleming u64 start, end; 154*60863c0dSMatt Fleming int count = 0; 155*60863c0dSMatt Fleming 156*60863c0dSMatt Fleming start = md->phys_addr; 157*60863c0dSMatt Fleming end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1; 158*60863c0dSMatt Fleming 159*60863c0dSMatt Fleming /* modifying range */ 160*60863c0dSMatt Fleming m_start = range->start; 161*60863c0dSMatt Fleming m_end = range->end; 162*60863c0dSMatt Fleming 163*60863c0dSMatt Fleming if (m_start <= start) { 164*60863c0dSMatt Fleming /* split into 2 parts */ 165*60863c0dSMatt Fleming if (start < m_end && m_end < end) 166*60863c0dSMatt Fleming count++; 167*60863c0dSMatt Fleming } 168*60863c0dSMatt Fleming 169*60863c0dSMatt Fleming if (start < m_start && m_start < end) { 170*60863c0dSMatt Fleming /* split into 3 parts */ 171*60863c0dSMatt Fleming if (m_end < end) 172*60863c0dSMatt Fleming count += 2; 173*60863c0dSMatt Fleming /* split into 2 parts */ 174*60863c0dSMatt Fleming if (end <= m_end) 175*60863c0dSMatt Fleming count++; 176*60863c0dSMatt Fleming } 177*60863c0dSMatt Fleming 178*60863c0dSMatt Fleming return count; 179*60863c0dSMatt Fleming } 180*60863c0dSMatt Fleming 181*60863c0dSMatt Fleming /** 182*60863c0dSMatt Fleming * efi_memmap_insert - Insert a memory region in an EFI memmap 183*60863c0dSMatt Fleming * @old_memmap: The existing EFI memory map structure 184*60863c0dSMatt Fleming * @buf: Address of buffer to store new map 185*60863c0dSMatt Fleming * @mem: Memory map entry to insert 186*60863c0dSMatt Fleming * 187*60863c0dSMatt Fleming * It is suggested that you call efi_memmap_split_count() first 188*60863c0dSMatt Fleming * to see how large @buf needs to be. 189*60863c0dSMatt Fleming */ 190*60863c0dSMatt Fleming void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf, 191*60863c0dSMatt Fleming struct efi_mem_range *mem) 192*60863c0dSMatt Fleming { 193*60863c0dSMatt Fleming u64 m_start, m_end, m_attr; 194*60863c0dSMatt Fleming efi_memory_desc_t *md; 195*60863c0dSMatt Fleming u64 start, end; 196*60863c0dSMatt Fleming void *old, *new; 197*60863c0dSMatt Fleming 198*60863c0dSMatt Fleming /* modifying range */ 199*60863c0dSMatt Fleming m_start = mem->range.start; 200*60863c0dSMatt Fleming m_end = mem->range.end; 201*60863c0dSMatt Fleming m_attr = mem->attribute; 202*60863c0dSMatt Fleming 203*60863c0dSMatt Fleming for (old = old_memmap->map, new = buf; 204*60863c0dSMatt Fleming old < old_memmap->map_end; 205*60863c0dSMatt Fleming old += old_memmap->desc_size, new += old_memmap->desc_size) { 206*60863c0dSMatt Fleming 207*60863c0dSMatt Fleming /* copy original EFI memory descriptor */ 208*60863c0dSMatt Fleming memcpy(new, old, old_memmap->desc_size); 209*60863c0dSMatt Fleming md = new; 210*60863c0dSMatt Fleming start = md->phys_addr; 211*60863c0dSMatt Fleming end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; 212*60863c0dSMatt Fleming 213*60863c0dSMatt Fleming if (m_start <= start && end <= m_end) 214*60863c0dSMatt Fleming md->attribute |= m_attr; 215*60863c0dSMatt Fleming 216*60863c0dSMatt Fleming if (m_start <= start && 217*60863c0dSMatt Fleming (start < m_end && m_end < end)) { 218*60863c0dSMatt Fleming /* first part */ 219*60863c0dSMatt Fleming md->attribute |= m_attr; 220*60863c0dSMatt Fleming md->num_pages = (m_end - md->phys_addr + 1) >> 221*60863c0dSMatt Fleming EFI_PAGE_SHIFT; 222*60863c0dSMatt Fleming /* latter part */ 223*60863c0dSMatt Fleming new += old_memmap->desc_size; 224*60863c0dSMatt Fleming memcpy(new, old, old_memmap->desc_size); 225*60863c0dSMatt Fleming md = new; 226*60863c0dSMatt Fleming md->phys_addr = m_end + 1; 227*60863c0dSMatt Fleming md->num_pages = (end - md->phys_addr + 1) >> 228*60863c0dSMatt Fleming EFI_PAGE_SHIFT; 229*60863c0dSMatt Fleming } 230*60863c0dSMatt Fleming 231*60863c0dSMatt Fleming if ((start < m_start && m_start < end) && m_end < end) { 232*60863c0dSMatt Fleming /* first part */ 233*60863c0dSMatt Fleming md->num_pages = (m_start - md->phys_addr) >> 234*60863c0dSMatt Fleming EFI_PAGE_SHIFT; 235*60863c0dSMatt Fleming /* middle part */ 236*60863c0dSMatt Fleming new += old_memmap->desc_size; 237*60863c0dSMatt Fleming memcpy(new, old, old_memmap->desc_size); 238*60863c0dSMatt Fleming md = new; 239*60863c0dSMatt Fleming md->attribute |= m_attr; 240*60863c0dSMatt Fleming md->phys_addr = m_start; 241*60863c0dSMatt Fleming md->num_pages = (m_end - m_start + 1) >> 242*60863c0dSMatt Fleming EFI_PAGE_SHIFT; 243*60863c0dSMatt Fleming /* last part */ 244*60863c0dSMatt Fleming new += old_memmap->desc_size; 245*60863c0dSMatt Fleming memcpy(new, old, old_memmap->desc_size); 246*60863c0dSMatt Fleming md = new; 247*60863c0dSMatt Fleming md->phys_addr = m_end + 1; 248*60863c0dSMatt Fleming md->num_pages = (end - m_end) >> 249*60863c0dSMatt Fleming EFI_PAGE_SHIFT; 250*60863c0dSMatt Fleming } 251*60863c0dSMatt Fleming 252*60863c0dSMatt Fleming if ((start < m_start && m_start < end) && 253*60863c0dSMatt Fleming (end <= m_end)) { 254*60863c0dSMatt Fleming /* first part */ 255*60863c0dSMatt Fleming md->num_pages = (m_start - md->phys_addr) >> 256*60863c0dSMatt Fleming EFI_PAGE_SHIFT; 257*60863c0dSMatt Fleming /* latter part */ 258*60863c0dSMatt Fleming new += old_memmap->desc_size; 259*60863c0dSMatt Fleming memcpy(new, old, old_memmap->desc_size); 260*60863c0dSMatt Fleming md = new; 261*60863c0dSMatt Fleming md->phys_addr = m_start; 262*60863c0dSMatt Fleming md->num_pages = (end - md->phys_addr + 1) >> 263*60863c0dSMatt Fleming EFI_PAGE_SHIFT; 264*60863c0dSMatt Fleming md->attribute |= m_attr; 265*60863c0dSMatt Fleming } 266*60863c0dSMatt Fleming } 267*60863c0dSMatt Fleming } 268