Commit 71e0940d authored by Ard Biesheuvel's avatar Ard Biesheuvel

efi: honour memory reservations passed via a linux specific config table

In order to allow the OS to reserve memory persistently across a
kexec, introduce a Linux-specific UEFI configuration table that
points to the head of a linked list in memory, allowing each kernel
to add list items describing memory regions that the next kernel
should treat as reserved.

This is useful, e.g., for GICv3 based ARM systems that cannot disable
DMA access to the LPI tables, forcing them to reuse the same memory
region again after a kexec reboot.
Tested-by: default avatarJeremy Linton <jeremy.linton@arm.com>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
parent 11da3a7f
...@@ -52,7 +52,8 @@ struct efi __read_mostly efi = { ...@@ -52,7 +52,8 @@ struct efi __read_mostly efi = {
.properties_table = EFI_INVALID_TABLE_ADDR, .properties_table = EFI_INVALID_TABLE_ADDR,
.mem_attr_table = EFI_INVALID_TABLE_ADDR, .mem_attr_table = EFI_INVALID_TABLE_ADDR,
.rng_seed = 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); EXPORT_SYMBOL(efi);
...@@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = { ...@@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
{LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
{NULL_GUID, NULL, NULL}, {NULL_GUID, NULL, NULL},
}; };
...@@ -591,6 +593,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, ...@@ -591,6 +593,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
early_memunmap(tbl, sizeof(*tbl)); 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; return 0;
} }
......
...@@ -672,6 +672,7 @@ void efi_native_runtime_setup(void); ...@@ -672,6 +672,7 @@ void efi_native_runtime_setup(void);
#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b) #define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
#define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa) #define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
typedef struct { typedef struct {
efi_guid_t guid; efi_guid_t guid;
...@@ -957,6 +958,7 @@ extern struct efi { ...@@ -957,6 +958,7 @@ extern struct efi {
unsigned long mem_attr_table; /* memory attributes table */ unsigned long mem_attr_table; /* memory attributes table */
unsigned long rng_seed; /* UEFI firmware random seed */ unsigned long rng_seed; /* UEFI firmware random seed */
unsigned long tpm_log; /* TPM2 Event Log table */ unsigned long tpm_log; /* TPM2 Event Log table */
unsigned long mem_reserve; /* Linux EFI memreserve table */
efi_get_time_t *get_time; efi_get_time_t *get_time;
efi_set_time_t *set_time; efi_set_time_t *set_time;
efi_get_wakeup_time_t *get_wakeup_time; efi_get_wakeup_time_t *get_wakeup_time;
...@@ -1662,4 +1664,10 @@ extern int efi_tpm_eventlog_init(void); ...@@ -1662,4 +1664,10 @@ extern int efi_tpm_eventlog_init(void);
/* Workqueue to queue EFI Runtime Services */ /* Workqueue to queue EFI Runtime Services */
extern struct workqueue_struct *efi_rts_wq; extern struct workqueue_struct *efi_rts_wq;
struct linux_efi_memreserve {
phys_addr_t next;
phys_addr_t base;
phys_addr_t size;
};
#endif /* _LINUX_EFI_H */ #endif /* _LINUX_EFI_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment