diff options
Diffstat (limited to 'drivers/firmware/efi/efi.c')
-rw-r--r-- | drivers/firmware/efi/efi.c | 67 |
1 files changed, 36 insertions, 31 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 7dd2e2d37231..1ac199cd75e7 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/acpi.h> | 28 | #include <linux/acpi.h> |
29 | #include <linux/ucs2_string.h> | 29 | #include <linux/ucs2_string.h> |
30 | #include <linux/memblock.h> | ||
30 | 31 | ||
31 | #include <asm/early_ioremap.h> | 32 | #include <asm/early_ioremap.h> |
32 | 33 | ||
@@ -347,56 +348,31 @@ subsys_initcall(efisubsys_init); | |||
347 | 348 | ||
348 | /* | 349 | /* |
349 | * Find the efi memory descriptor for a given physical address. Given a | 350 | * Find the efi memory descriptor for a given physical address. Given a |
350 | * physicall address, determine if it exists within an EFI Memory Map entry, | 351 | * physical address, determine if it exists within an EFI Memory Map entry, |
351 | * and if so, populate the supplied memory descriptor with the appropriate | 352 | * and if so, populate the supplied memory descriptor with the appropriate |
352 | * data. | 353 | * data. |
353 | */ | 354 | */ |
354 | int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) | 355 | int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) |
355 | { | 356 | { |
356 | struct efi_memory_map *map = &efi.memmap; | 357 | efi_memory_desc_t *md; |
357 | phys_addr_t p, e; | ||
358 | 358 | ||
359 | if (!efi_enabled(EFI_MEMMAP)) { | 359 | if (!efi_enabled(EFI_MEMMAP)) { |
360 | pr_err_once("EFI_MEMMAP is not enabled.\n"); | 360 | pr_err_once("EFI_MEMMAP is not enabled.\n"); |
361 | return -EINVAL; | 361 | return -EINVAL; |
362 | } | 362 | } |
363 | 363 | ||
364 | if (!map) { | ||
365 | pr_err_once("efi.memmap is not set.\n"); | ||
366 | return -EINVAL; | ||
367 | } | ||
368 | if (!out_md) { | 364 | if (!out_md) { |
369 | pr_err_once("out_md is null.\n"); | 365 | pr_err_once("out_md is null.\n"); |
370 | return -EINVAL; | 366 | return -EINVAL; |
371 | } | 367 | } |
372 | if (WARN_ON_ONCE(!map->phys_map)) | ||
373 | return -EINVAL; | ||
374 | if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0)) | ||
375 | return -EINVAL; | ||
376 | 368 | ||
377 | e = map->phys_map + map->nr_map * map->desc_size; | 369 | for_each_efi_memory_desc(md) { |
378 | for (p = map->phys_map; p < e; p += map->desc_size) { | ||
379 | efi_memory_desc_t *md; | ||
380 | u64 size; | 370 | u64 size; |
381 | u64 end; | 371 | u64 end; |
382 | 372 | ||
383 | /* | ||
384 | * If a driver calls this after efi_free_boot_services, | ||
385 | * ->map will be NULL, and the target may also not be mapped. | ||
386 | * So just always get our own virtual map on the CPU. | ||
387 | * | ||
388 | */ | ||
389 | md = early_memremap(p, sizeof (*md)); | ||
390 | if (!md) { | ||
391 | pr_err_once("early_memremap(%pa, %zu) failed.\n", | ||
392 | &p, sizeof (*md)); | ||
393 | return -ENOMEM; | ||
394 | } | ||
395 | |||
396 | if (!(md->attribute & EFI_MEMORY_RUNTIME) && | 373 | if (!(md->attribute & EFI_MEMORY_RUNTIME) && |
397 | md->type != EFI_BOOT_SERVICES_DATA && | 374 | md->type != EFI_BOOT_SERVICES_DATA && |
398 | md->type != EFI_RUNTIME_SERVICES_DATA) { | 375 | md->type != EFI_RUNTIME_SERVICES_DATA) { |
399 | early_memunmap(md, sizeof (*md)); | ||
400 | continue; | 376 | continue; |
401 | } | 377 | } |
402 | 378 | ||
@@ -404,11 +380,8 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) | |||
404 | end = md->phys_addr + size; | 380 | end = md->phys_addr + size; |
405 | if (phys_addr >= md->phys_addr && phys_addr < end) { | 381 | if (phys_addr >= md->phys_addr && phys_addr < end) { |
406 | memcpy(out_md, md, sizeof(*out_md)); | 382 | memcpy(out_md, md, sizeof(*out_md)); |
407 | early_memunmap(md, sizeof (*md)); | ||
408 | return 0; | 383 | return 0; |
409 | } | 384 | } |
410 | |||
411 | early_memunmap(md, sizeof (*md)); | ||
412 | } | 385 | } |
413 | pr_err_once("requested map not found.\n"); | 386 | pr_err_once("requested map not found.\n"); |
414 | return -ENOENT; | 387 | return -ENOENT; |
@@ -424,6 +397,35 @@ u64 __init efi_mem_desc_end(efi_memory_desc_t *md) | |||
424 | return end; | 397 | return end; |
425 | } | 398 | } |
426 | 399 | ||
400 | void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {} | ||
401 | |||
402 | /** | ||
403 | * efi_mem_reserve - Reserve an EFI memory region | ||
404 | * @addr: Physical address to reserve | ||
405 | * @size: Size of reservation | ||
406 | * | ||
407 | * Mark a region as reserved from general kernel allocation and | ||
408 | * prevent it being released by efi_free_boot_services(). | ||
409 | * | ||
410 | * This function should be called drivers once they've parsed EFI | ||
411 | * configuration tables to figure out where their data lives, e.g. | ||
412 | * efi_esrt_init(). | ||
413 | */ | ||
414 | void __init efi_mem_reserve(phys_addr_t addr, u64 size) | ||
415 | { | ||
416 | if (!memblock_is_region_reserved(addr, size)) | ||
417 | memblock_reserve(addr, size); | ||
418 | |||
419 | /* | ||
420 | * Some architectures (x86) reserve all boot services ranges | ||
421 | * until efi_free_boot_services() because of buggy firmware | ||
422 | * implementations. This means the above memblock_reserve() is | ||
423 | * superfluous on x86 and instead what it needs to do is | ||
424 | * ensure the @start, @size is not freed. | ||
425 | */ | ||
426 | efi_arch_mem_reserve(addr, size); | ||
427 | } | ||
428 | |||
427 | static __initdata efi_config_table_type_t common_tables[] = { | 429 | static __initdata efi_config_table_type_t common_tables[] = { |
428 | {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, | 430 | {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, |
429 | {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, | 431 | {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, |
@@ -811,6 +813,9 @@ int efi_status_to_err(efi_status_t status) | |||
811 | case EFI_NOT_FOUND: | 813 | case EFI_NOT_FOUND: |
812 | err = -ENOENT; | 814 | err = -ENOENT; |
813 | break; | 815 | break; |
816 | case EFI_ABORTED: | ||
817 | err = -EINTR; | ||
818 | break; | ||
814 | default: | 819 | default: |
815 | err = -EINVAL; | 820 | err = -EINVAL; |
816 | } | 821 | } |