efi: add API to reserve memory persistently across kexec reboot
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Fri, 21 Sep 2018 16:32:46 +0000 (09:32 -0700)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 26 Sep 2018 10:03:57 +0000 (12:03 +0200)
Add kernel plumbing to reserve memory regions persistently on a EFI
system by adding entries to the MEMRESERVE linked list.

Tested-by: Jeremy Linton <jeremy.linton@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
drivers/firmware/efi/efi.c
include/linux/efi.h

index 688132ac8a0a10549bdc284a18ff7031d6121da0..249eb70691b0f5e7567cf4fc3bbb8dda9df571cf 100644 (file)
@@ -962,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)
index a5cb580472c50a71557e61100dda6ea0064789a8..22e4de9d370004bd5a65f56ab9d2084ac56f79dc 100644 (file)
@@ -1043,6 +1043,7 @@ extern int __init efi_uart_console_only (void);
 extern u64 efi_mem_desc_end(efi_memory_desc_t *md);
 extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md);
 extern void efi_mem_reserve(phys_addr_t addr, u64 size);
+extern int efi_mem_reserve_persistent(phys_addr_t addr, u64 size);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
                struct resource *data_resource, struct resource *bss_resource);
 extern void efi_reserve_boot_services(void);