Hardware-poisoned page frames are tracked only in the running kernel's data structures, so a kexec loses them and the next kernel doesn't have this information, thus, tripping into them again. Add an EFI configuration table to carry that information across kexec. It is a bitmap with one bit per EFI_POISON_UNIT_SIZE (2MiB) of physical memory, modeled on the LINUX_EFI_UNACCEPTED_MEMORY table, and it rides the EFI system table to every kernel in the chain. Suggested-by: Kiryl Shutsemau Signed-off-by: Breno Leitao --- drivers/firmware/efi/Kconfig | 10 ++++++++++ drivers/firmware/efi/efi.c | 6 ++++++ include/linux/efi.h | 13 +++++++++++++ 3 files changed, 29 insertions(+) diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 29e0729299f5b..69c0dc02bc112 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -263,6 +263,16 @@ config EFI_COCO_SECRET virt/coco/efi_secret module to access the secrets, which in turn allows userspace programs to access the injected secrets. +config EFI_POISONED_MEMORY + bool "Carry hardware-poisoned pages across kexec" + depends on EFI_STUB && MEMORY_FAILURE && 64BIT + help + Record page frames that are hardware-poisoned while this kernel runs + into an EFI configuration table, and honor that table early on the + next kernel so a kexec does not hand known-bad RAM back out. + + If unsure, say N. + config OVMF_DEBUG_LOG bool "Expose OVMF firmware debug log via sysfs" depends on EFI diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 0327a39d31fa5..111e60479211a 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -55,6 +55,9 @@ struct efi __read_mostly efi = { #ifdef CONFIG_UNACCEPTED_MEMORY .unaccepted = EFI_INVALID_TABLE_ADDR, #endif +#ifdef CONFIG_EFI_POISONED_MEMORY + .poisoned_memory = EFI_INVALID_TABLE_ADDR, +#endif }; EXPORT_SYMBOL(efi); @@ -646,6 +649,9 @@ static const efi_config_table_type_t common_tables[] __initconst = { #ifdef CONFIG_UNACCEPTED_MEMORY {LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID, &efi.unaccepted, "Unaccepted" }, #endif +#ifdef CONFIG_EFI_POISONED_MEMORY + {LINUX_EFI_POISONED_MEMORY_TABLE_GUID, &efi.poisoned_memory, "POISON" }, +#endif #ifdef CONFIG_EFI_GENERIC_STUB {LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID, &primary_display_table }, #endif diff --git a/include/linux/efi.h b/include/linux/efi.h index b3c83516593d1..ce0980a5bb81b 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -422,6 +423,7 @@ void efi_native_runtime_setup(void); #define LINUX_EFI_COCO_SECRET_AREA_GUID EFI_GUID(0xadf956ad, 0xe98c, 0x484c, 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47) #define LINUX_EFI_BOOT_MEMMAP_GUID EFI_GUID(0x800f683f, 0xd08b, 0x423a, 0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4) #define LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID EFI_GUID(0xd5d1de3c, 0x105c, 0x44f9, 0x9e, 0xa9, 0xbc, 0xef, 0x98, 0x12, 0x00, 0x31) +#define LINUX_EFI_POISONED_MEMORY_TABLE_GUID EFI_GUID(0x78a5bf07, 0x7d2a, 0x2889, 0x16, 0x31, 0x63, 0xd4, 0x56, 0xf2, 0x83, 0x50) #define RISCV_EFI_BOOT_PROTOCOL_GUID EFI_GUID(0xccd15fec, 0x6f73, 0x4eec, 0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf) @@ -650,6 +652,7 @@ extern struct efi { unsigned long mokvar_table; /* MOK variable config table */ unsigned long coco_secret; /* Confidential computing secret table */ unsigned long unaccepted; /* Unaccepted memory table */ + unsigned long poisoned_memory; /* Hardware-poisoned memory table */ efi_get_time_t *get_time; efi_set_time_t *set_time; @@ -1271,6 +1274,16 @@ struct linux_efi_memreserve { #define EFI_MEMRESERVE_COUNT(size) (((size) - sizeof(struct linux_efi_memreserve)) \ / sizeof_field(struct linux_efi_memreserve, entry[0])) +struct linux_efi_poisoned_memory { + u32 version; + u32 unit_size; /* bytes of phys space per bitmap bit */ + u64 phys_base; /* phys address covered by bit 0 */ + u64 size; /* bitmap size in bytes */ + unsigned long bitmap[]; +}; + +#define EFI_POISON_UNIT_SIZE SZ_2M + void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size); /* -- 2.53.0-Meta