aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/platform/efi/quirks.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/platform/efi/quirks.c')
-rw-r--r--arch/x86/platform/efi/quirks.c127
1 files changed, 114 insertions, 13 deletions
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 89d1146f5a6f..10aca63a50d7 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -164,6 +164,75 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size,
164EXPORT_SYMBOL_GPL(efi_query_variable_store); 164EXPORT_SYMBOL_GPL(efi_query_variable_store);
165 165
166/* 166/*
167 * The UEFI specification makes it clear that the operating system is
168 * free to do whatever it wants with boot services code after
169 * ExitBootServices() has been called. Ignoring this recommendation a
170 * significant bunch of EFI implementations continue calling into boot
171 * services code (SetVirtualAddressMap). In order to work around such
172 * buggy implementations we reserve boot services region during EFI
173 * init and make sure it stays executable. Then, after
174 * SetVirtualAddressMap(), it is discarded.
175 *
176 * However, some boot services regions contain data that is required
177 * by drivers, so we need to track which memory ranges can never be
178 * freed. This is done by tagging those regions with the
179 * EFI_MEMORY_RUNTIME attribute.
180 *
181 * Any driver that wants to mark a region as reserved must use
182 * efi_mem_reserve() which will insert a new EFI memory descriptor
183 * into efi.memmap (splitting existing regions if necessary) and tag
184 * it with EFI_MEMORY_RUNTIME.
185 */
186void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
187{
188 phys_addr_t new_phys, new_size;
189 struct efi_mem_range mr;
190 efi_memory_desc_t md;
191 int num_entries;
192 void *new;
193
194 if (efi_mem_desc_lookup(addr, &md)) {
195 pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr);
196 return;
197 }
198
199 if (addr + size > md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT)) {
200 pr_err("Region spans EFI memory descriptors, %pa\n", &addr);
201 return;
202 }
203
204 size += addr % EFI_PAGE_SIZE;
205 size = round_up(size, EFI_PAGE_SIZE);
206 addr = round_down(addr, EFI_PAGE_SIZE);
207
208 mr.range.start = addr;
209 mr.range.end = addr + size - 1;
210 mr.attribute = md.attribute | EFI_MEMORY_RUNTIME;
211
212 num_entries = efi_memmap_split_count(&md, &mr.range);
213 num_entries += efi.memmap.nr_map;
214
215 new_size = efi.memmap.desc_size * num_entries;
216
217 new_phys = memblock_alloc(new_size, 0);
218 if (!new_phys) {
219 pr_err("Could not allocate boot services memmap\n");
220 return;
221 }
222
223 new = early_memremap(new_phys, new_size);
224 if (!new) {
225 pr_err("Failed to map new boot services memmap\n");
226 return;
227 }
228
229 efi_memmap_insert(&efi.memmap, new, &mr);
230 early_memunmap(new, new_size);
231
232 efi_memmap_install(new_phys, num_entries);
233}
234
235/*
167 * Helper function for efi_reserve_boot_services() to figure out if we 236 * Helper function for efi_reserve_boot_services() to figure out if we
168 * can free regions in efi_free_boot_services(). 237 * can free regions in efi_free_boot_services().
169 * 238 *
@@ -184,15 +253,6 @@ static bool can_free_region(u64 start, u64 size)
184 return true; 253 return true;
185} 254}
186 255
187/*
188 * The UEFI specification makes it clear that the operating system is free to do
189 * whatever it wants with boot services code after ExitBootServices() has been
190 * called. Ignoring this recommendation a significant bunch of EFI implementations
191 * continue calling into boot services code (SetVirtualAddressMap). In order to
192 * work around such buggy implementations we reserve boot services region during
193 * EFI init and make sure it stays executable. Then, after SetVirtualAddressMap(), it
194* is discarded.
195*/
196void __init efi_reserve_boot_services(void) 256void __init efi_reserve_boot_services(void)
197{ 257{
198 efi_memory_desc_t *md; 258 efi_memory_desc_t *md;
@@ -249,7 +309,10 @@ void __init efi_reserve_boot_services(void)
249 309
250void __init efi_free_boot_services(void) 310void __init efi_free_boot_services(void)
251{ 311{
312 phys_addr_t new_phys, new_size;
252 efi_memory_desc_t *md; 313 efi_memory_desc_t *md;
314 int num_entries = 0;
315 void *new, *new_md;
253 316
254 for_each_efi_memory_desc(md) { 317 for_each_efi_memory_desc(md) {
255 unsigned long long start = md->phys_addr; 318 unsigned long long start = md->phys_addr;
@@ -257,12 +320,16 @@ void __init efi_free_boot_services(void)
257 size_t rm_size; 320 size_t rm_size;
258 321
259 if (md->type != EFI_BOOT_SERVICES_CODE && 322 if (md->type != EFI_BOOT_SERVICES_CODE &&
260 md->type != EFI_BOOT_SERVICES_DATA) 323 md->type != EFI_BOOT_SERVICES_DATA) {
324 num_entries++;
261 continue; 325 continue;
326 }
262 327
263 /* Do not free, someone else owns it: */ 328 /* Do not free, someone else owns it: */
264 if (md->attribute & EFI_MEMORY_RUNTIME) 329 if (md->attribute & EFI_MEMORY_RUNTIME) {
330 num_entries++;
265 continue; 331 continue;
332 }
266 333
267 /* 334 /*
268 * Nasty quirk: if all sub-1MB memory is used for boot 335 * Nasty quirk: if all sub-1MB memory is used for boot
@@ -287,7 +354,41 @@ void __init efi_free_boot_services(void)
287 free_bootmem_late(start, size); 354 free_bootmem_late(start, size);
288 } 355 }
289 356
290 efi_unmap_memmap(); 357 new_size = efi.memmap.desc_size * num_entries;
358 new_phys = memblock_alloc(new_size, 0);
359 if (!new_phys) {
360 pr_err("Failed to allocate new EFI memmap\n");
361 return;
362 }
363
364 new = memremap(new_phys, new_size, MEMREMAP_WB);
365 if (!new) {
366 pr_err("Failed to map new EFI memmap\n");
367 return;
368 }
369
370 /*
371 * Build a new EFI memmap that excludes any boot services
372 * regions that are not tagged EFI_MEMORY_RUNTIME, since those
373 * regions have now been freed.
374 */
375 new_md = new;
376 for_each_efi_memory_desc(md) {
377 if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
378 (md->type == EFI_BOOT_SERVICES_CODE ||
379 md->type == EFI_BOOT_SERVICES_DATA))
380 continue;
381
382 memcpy(new_md, md, efi.memmap.desc_size);
383 new_md += efi.memmap.desc_size;
384 }
385
386 memunmap(new);
387
388 if (efi_memmap_install(new_phys, num_entries)) {
389 pr_err("Could not install new EFI memmap\n");
390 return;
391 }
291} 392}
292 393
293/* 394/*
@@ -365,7 +466,7 @@ void __init efi_apply_memmap_quirks(void)
365 */ 466 */
366 if (!efi_runtime_supported()) { 467 if (!efi_runtime_supported()) {
367 pr_info("Setup done, disabling due to 32/64-bit mismatch\n"); 468 pr_info("Setup done, disabling due to 32/64-bit mismatch\n");
368 efi_unmap_memmap(); 469 efi_memmap_unmap();
369 } 470 }
370 471
371 /* UV2+ BIOS has a fix for this issue. UV1 still needs the quirk. */ 472 /* UV2+ BIOS has a fix for this issue. UV1 still needs the quirk. */