1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * fake_mem.c 4 * 5 * Copyright (C) 2015 FUJITSU LIMITED 6 * Author: Taku Izumi <izumi.taku@jp.fujitsu.com> 7 * 8 * This code introduces new boot option named "efi_fake_mem" 9 * By specifying this parameter, you can add arbitrary attribute to 10 * specific memory range by updating original (firmware provided) EFI 11 * memmap. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/efi.h> 16 #include <linux/init.h> 17 #include <linux/memblock.h> 18 #include <linux/types.h> 19 #include <linux/sort.h> 20 #include <asm/e820/api.h> 21 #include <asm/efi.h> 22 23 #define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM 24 25 static struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM]; 26 static int nr_fake_mem; 27 28 static int __init cmp_fake_mem(const void *x1, const void *x2) 29 { 30 const struct efi_mem_range *m1 = x1; 31 const struct efi_mem_range *m2 = x2; 32 33 if (m1->range.start < m2->range.start) 34 return -1; 35 if (m1->range.start > m2->range.start) 36 return 1; 37 return 0; 38 } 39 40 static void __init efi_fake_range(struct efi_mem_range *efi_range) 41 { 42 struct efi_memory_map_data data = { 0 }; 43 int new_nr_map = efi.memmap.nr_map; 44 efi_memory_desc_t *md; 45 void *new_memmap; 46 47 /* count up the number of EFI memory descriptor */ 48 for_each_efi_memory_desc(md) 49 new_nr_map += efi_memmap_split_count(md, &efi_range->range); 50 51 /* allocate memory for new EFI memmap */ 52 if (efi_memmap_alloc(new_nr_map, &data) != 0) 53 return; 54 55 /* create new EFI memmap */ 56 new_memmap = early_memremap(data.phys_map, data.size); 57 if (!new_memmap) { 58 __efi_memmap_free(data.phys_map, data.size, data.flags); 59 return; 60 } 61 62 efi_memmap_insert(&efi.memmap, new_memmap, efi_range); 63 64 /* swap into new EFI memmap */ 65 early_memunmap(new_memmap, data.size); 66 67 efi_memmap_install(&data); 68 } 69 70 void __init efi_fake_memmap(void) 71 { 72 int i; 73 74 if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem) 75 return; 76 77 for (i = 0; i < nr_fake_mem; i++) 78 efi_fake_range(&efi_fake_mems[i]); 79 80 /* print new EFI memmap */ 81 efi_print_memmap(); 82 } 83 84 static int __init setup_fake_mem(char *p) 85 { 86 u64 start = 0, mem_size = 0, attribute = 0; 87 int i; 88 89 if (!p) 90 return -EINVAL; 91 92 while (*p != '\0') { 93 mem_size = memparse(p, &p); 94 if (*p == '@') 95 start = memparse(p+1, &p); 96 else 97 break; 98 99 if (*p == ':') 100 attribute = simple_strtoull(p+1, &p, 0); 101 else 102 break; 103 104 if (nr_fake_mem >= EFI_MAX_FAKEMEM) 105 break; 106 107 efi_fake_mems[nr_fake_mem].range.start = start; 108 efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1; 109 efi_fake_mems[nr_fake_mem].attribute = attribute; 110 nr_fake_mem++; 111 112 if (*p == ',') 113 p++; 114 } 115 116 sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range), 117 cmp_fake_mem, NULL); 118 119 for (i = 0; i < nr_fake_mem; i++) 120 pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]", 121 efi_fake_mems[i].attribute, efi_fake_mems[i].range.start, 122 efi_fake_mems[i].range.end); 123 124 return *p == '\0' ? 0 : -EINVAL; 125 } 126 127 early_param("efi_fake_mem", setup_fake_mem); 128 129 void __init efi_fake_memmap_early(void) 130 { 131 int i; 132 133 /* 134 * The late efi_fake_mem() call can handle all requests if 135 * EFI_MEMORY_SP support is disabled. 136 */ 137 if (!efi_soft_reserve_enabled()) 138 return; 139 140 if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem) 141 return; 142 143 /* 144 * Given that efi_fake_memmap() needs to perform memblock 145 * allocations it needs to run after e820__memblock_setup(). 146 * However, if efi_fake_mem specifies EFI_MEMORY_SP for a given 147 * address range that potentially needs to mark the memory as 148 * reserved prior to e820__memblock_setup(). Update e820 149 * directly if EFI_MEMORY_SP is specified for an 150 * EFI_CONVENTIONAL_MEMORY descriptor. 151 */ 152 for (i = 0; i < nr_fake_mem; i++) { 153 struct efi_mem_range *mem = &efi_fake_mems[i]; 154 efi_memory_desc_t *md; 155 u64 m_start, m_end; 156 157 if ((mem->attribute & EFI_MEMORY_SP) == 0) 158 continue; 159 160 m_start = mem->range.start; 161 m_end = mem->range.end; 162 for_each_efi_memory_desc(md) { 163 u64 start, end, size; 164 165 if (md->type != EFI_CONVENTIONAL_MEMORY) 166 continue; 167 168 start = md->phys_addr; 169 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; 170 171 if (m_start <= end && m_end >= start) 172 /* fake range overlaps descriptor */; 173 else 174 continue; 175 176 /* 177 * Trim the boundary of the e820 update to the 178 * descriptor in case the fake range overlaps 179 * !EFI_CONVENTIONAL_MEMORY 180 */ 181 start = max(start, m_start); 182 end = min(end, m_end); 183 size = end - start + 1; 184 185 if (end <= start) 186 continue; 187 188 /* 189 * Ensure each efi_fake_mem instance results in 190 * a unique e820 resource 191 */ 192 e820__range_remove(start, size, E820_TYPE_RAM, 1); 193 e820__range_add(start, size, E820_TYPE_SOFT_RESERVED); 194 e820__update_table(e820_table); 195 } 196 } 197 } 198