Add kernel plumbing to reserve memory regions persistently on a EFI
system by adding entries to the MEMRESERVE linked list.

Signed-off-by: Ard Biesheuvel <[email protected]>
---
 drivers/firmware/efi/efi.c | 32 ++++++++++++++++++++
 include/linux/efi.h        |  1 +
 2 files changed, 33 insertions(+)

diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 688132ac8a0a..249eb70691b0 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -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)
diff --git a/include/linux/efi.h b/include/linux/efi.h
index c72599b8b344..c753d8530da6 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -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);
-- 
2.17.1

Reply via email to