Memory hotplug in secure environments requires the unaccepted memory bitmap to grow as new memory is added. Currently, the bitmap is implemented as a flexible array member at the end of struct efi_unaccepted_memory, which is reserved by memblock at boot and cannot be resized without reallocating the entire structure. Replace the flexible array member with a pointer. This allows the bitmap to be allocated and managed independently from the unaccepted memory table, enabling dynamic growth to support memory hotplug. Signed-off-by: Pratik R. Sampat --- arch/x86/boot/compressed/efi.h | 2 +- arch/x86/include/asm/unaccepted_memory.h | 9 +++++++++ .../firmware/efi/libstub/unaccepted_memory.c | 11 ++++++++++- drivers/firmware/efi/unaccepted_memory.c | 19 ++++++++++++++----- include/linux/efi.h | 2 +- 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/arch/x86/boot/compressed/efi.h b/arch/x86/boot/compressed/efi.h index b22300970f97..4f7027f33def 100644 --- a/arch/x86/boot/compressed/efi.h +++ b/arch/x86/boot/compressed/efi.h @@ -102,7 +102,7 @@ struct efi_unaccepted_memory { u32 unit_size; u64 phys_base; u64 size; - unsigned long bitmap[]; + unsigned long *bitmap; }; static inline int efi_guidcmp (efi_guid_t left, efi_guid_t right) diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h index f5937e9866ac..5da80e68d718 100644 --- a/arch/x86/include/asm/unaccepted_memory.h +++ b/arch/x86/include/asm/unaccepted_memory.h @@ -24,4 +24,13 @@ static inline struct efi_unaccepted_memory *efi_get_unaccepted_table(void) return NULL; return __va(efi.unaccepted); } + +static inline unsigned long *efi_get_unaccepted_bitmap(void) +{ + struct efi_unaccepted_memory *unaccepted = efi_get_unaccepted_table(); + + if (!unaccepted) + return NULL; + return __va(unaccepted->bitmap); +} #endif diff --git a/drivers/firmware/efi/libstub/unaccepted_memory.c b/drivers/firmware/efi/libstub/unaccepted_memory.c index 757dbe734a47..c1370fc14555 100644 --- a/drivers/firmware/efi/libstub/unaccepted_memory.c +++ b/drivers/firmware/efi/libstub/unaccepted_memory.c @@ -63,13 +63,22 @@ efi_status_t allocate_unaccepted_bitmap(__u32 nr_desc, EFI_UNACCEPTED_UNIT_SIZE * BITS_PER_BYTE); status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, - sizeof(*unaccepted_table) + bitmap_size, + sizeof(*unaccepted_table), (void **)&unaccepted_table); if (status != EFI_SUCCESS) { efi_err("Failed to allocate unaccepted memory config table\n"); return status; } + status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, + bitmap_size, + (void **)&unaccepted_table->bitmap); + if (status != EFI_SUCCESS) { + efi_bs_call(free_pool, unaccepted_table); + efi_err("Failed to allocate unaccepted memory bitmap\n"); + return status; + } + unaccepted_table->version = 1; unaccepted_table->unit_size = EFI_UNACCEPTED_UNIT_SIZE; unaccepted_table->phys_base = unaccepted_start; diff --git a/drivers/firmware/efi/unaccepted_memory.c b/drivers/firmware/efi/unaccepted_memory.c index c2c067eff634..4479aad258f8 100644 --- a/drivers/firmware/efi/unaccepted_memory.c +++ b/drivers/firmware/efi/unaccepted_memory.c @@ -36,7 +36,7 @@ void accept_memory(phys_addr_t start, unsigned long size) unsigned long range_start, range_end; struct accept_range range, *entry; phys_addr_t end = start + size; - unsigned long flags; + unsigned long flags, *bitmap; u64 unit_size; unaccepted = efi_get_unaccepted_table(); @@ -124,8 +124,12 @@ void accept_memory(phys_addr_t start, unsigned long size) list_add(&range.list, &accepting_list); range_start = range.start; - for_each_set_bitrange_from(range_start, range_end, unaccepted->bitmap, - range.end) { + + bitmap = efi_get_unaccepted_bitmap(); + if (!bitmap) + return; + + for_each_set_bitrange_from(range_start, range_end, bitmap, range.end) { unsigned long phys_start, phys_end; unsigned long len = range_end - range_start; @@ -147,7 +151,7 @@ void accept_memory(phys_addr_t start, unsigned long size) arch_accept_memory(phys_start, phys_end); spin_lock(&unaccepted_memory_lock); - bitmap_clear(unaccepted->bitmap, range_start, len); + bitmap_clear(bitmap, range_start, len); } list_del(&range.list); @@ -197,7 +201,12 @@ bool range_contains_unaccepted_memory(phys_addr_t start, unsigned long size) spin_lock_irqsave(&unaccepted_memory_lock, flags); while (start < end) { - if (test_bit(start / unit_size, unaccepted->bitmap)) { + unsigned long *bitmap = efi_get_unaccepted_bitmap(); + + if (!bitmap) + break; + + if (test_bit(start / unit_size, bitmap)) { ret = true; break; } diff --git a/include/linux/efi.h b/include/linux/efi.h index a98cc39e7aaa..a74b393c54d8 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -545,7 +545,7 @@ struct efi_unaccepted_memory { u32 unit_size; u64 phys_base; u64 size; - unsigned long bitmap[]; + unsigned long *bitmap; }; /* -- 2.51.1