diff options
Diffstat (limited to 'drivers/firmware/efi/efi.c')
-rw-r--r-- | drivers/firmware/efi/efi.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 2a29dd9c986d..249eb70691b0 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -52,7 +52,8 @@ struct efi __read_mostly efi = { .properties_table = EFI_INVALID_TABLE_ADDR, .mem_attr_table = EFI_INVALID_TABLE_ADDR, .rng_seed = EFI_INVALID_TABLE_ADDR, - .tpm_log = EFI_INVALID_TABLE_ADDR + .tpm_log = EFI_INVALID_TABLE_ADDR, + .mem_reserve = EFI_INVALID_TABLE_ADDR, }; EXPORT_SYMBOL(efi); @@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = { {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, + {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve}, {NULL_GUID, NULL, NULL}, }; @@ -591,6 +593,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, early_memunmap(tbl, sizeof(*tbl)); } + if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) { + unsigned long prsv = efi.mem_reserve; + + while (prsv) { + struct linux_efi_memreserve *rsv; + + /* reserve the entry itself */ + memblock_reserve(prsv, sizeof(*rsv)); + + rsv = early_memremap(prsv, sizeof(*rsv)); + if (rsv == NULL) { + pr_err("Could not map UEFI memreserve entry!\n"); + return -ENOMEM; + } + + if (rsv->size) + memblock_reserve(rsv->base, rsv->size); + + prsv = rsv->next; + early_memunmap(rsv, sizeof(*rsv)); + } + } + return 0; } @@ -937,6 +962,38 @@ bool efi_is_table_address(unsigned long phys_addr) return false; } +static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock); + +int efi_mem_reserve_persistent(phys_addr_t addr, u64 size) +{ + struct linux_efi_memreserve *rsv, *parent; + + if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR) + return -ENODEV; + + rsv = kmalloc(sizeof(*rsv), GFP_KERNEL); + if (!rsv) + return -ENOMEM; + + parent = memremap(efi.mem_reserve, sizeof(*rsv), MEMREMAP_WB); + if (!parent) { + kfree(rsv); + return -ENOMEM; + } + + rsv->base = addr; + rsv->size = size; + + spin_lock(&efi_mem_reserve_persistent_lock); + rsv->next = parent->next; + parent->next = __pa(rsv); + spin_unlock(&efi_mem_reserve_persistent_lock); + + memunmap(parent); + + return 0; +} + #ifdef CONFIG_KEXEC static int update_efi_random_seed(struct notifier_block *nb, unsigned long code, void *unused) |