Message ID | 20230518231434.26080-5-kirill.shutemov@linux.intel.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | mm, x86/cc, efi: Implement support for unaccepted memory | expand |
On Fri, May 19, 2023 at 02:14:29AM +0300, Kirill A. Shutemov wrote: > diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c > index 67594fcb11d9..87372b96d613 100644 > --- a/arch/x86/boot/compressed/mem.c > +++ b/arch/x86/boot/compressed/mem.c > @@ -1,9 +1,32 @@ > // SPDX-License-Identifier: GPL-2.0-only > > #include "error.h" > +#include "misc.h" > > void arch_accept_memory(phys_addr_t start, phys_addr_t end) > { > /* Platform-specific memory-acceptance call goes here */ > error("Cannot accept memory"); > } > + > +void init_unaccepted_memory(void) > +{ > + guid_t guid = LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID; > + struct efi_unaccepted_memory *unaccepted_table; > + unsigned long cfg_table_pa; > + unsigned int cfg_table_len; > + int ret; > + > + ret = efi_get_conf_table(boot_params, &cfg_table_pa, &cfg_table_len); > + if (ret) > + error("EFI config table not found."); > + > + unaccepted_table = (void *)efi_find_vendor_table(boot_params, > + cfg_table_pa, > + cfg_table_len, > + guid); > + if (unaccepted_table->version != 1) > + error("Unknown version of unaccepted memory table\n"); > + > + set_unaccepted_table(unaccepted_table); > +} 0-day reported boot failure outdise TDX guest with CONFIG_INTEL_TDX_GUEST=y. The fixup: diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c index 0108c97399a5..8df3d988ae69 100644 --- a/arch/x86/boot/compressed/mem.c +++ b/arch/x86/boot/compressed/mem.c @@ -56,6 +56,9 @@ void init_unaccepted_memory(void) cfg_table_pa, cfg_table_len, guid); + if (!unaccepted_table) + return; + if (unaccepted_table->version != 1) error("Unknown version of unaccepted memory table\n");
On Fri, May 19, 2023 at 01:16:41PM +0300, Kirill A. Shutemov wrote: > On Fri, May 19, 2023 at 02:14:29AM +0300, Kirill A. Shutemov wrote: > > diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c > > index 67594fcb11d9..87372b96d613 100644 > > --- a/arch/x86/boot/compressed/mem.c > > +++ b/arch/x86/boot/compressed/mem.c > > @@ -1,9 +1,32 @@ > > // SPDX-License-Identifier: GPL-2.0-only > > > > #include "error.h" > > +#include "misc.h" > > > > void arch_accept_memory(phys_addr_t start, phys_addr_t end) > > { > > /* Platform-specific memory-acceptance call goes here */ > > error("Cannot accept memory"); > > } > > + > > +void init_unaccepted_memory(void) > > +{ > > + guid_t guid = LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID; > > + struct efi_unaccepted_memory *unaccepted_table; > > + unsigned long cfg_table_pa; > > + unsigned int cfg_table_len; > > + int ret; > > + > > + ret = efi_get_conf_table(boot_params, &cfg_table_pa, &cfg_table_len); > > + if (ret) > > + error("EFI config table not found."); > > + > > + unaccepted_table = (void *)efi_find_vendor_table(boot_params, > > + cfg_table_pa, > > + cfg_table_len, > > + guid); > > + if (unaccepted_table->version != 1) > > + error("Unknown version of unaccepted memory table\n"); > > + > > + set_unaccepted_table(unaccepted_table); > > +} > > 0-day reported boot failure outdise TDX guest with CONFIG_INTEL_TDX_GUEST=y. 0-day folks reported one more issue: booting on non-EFI system fail. Updated fixup: diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c index 0108c97399a5..e7f7ef31e581 100644 --- a/arch/x86/boot/compressed/mem.c +++ b/arch/x86/boot/compressed/mem.c @@ -46,8 +46,13 @@ void init_unaccepted_memory(void) struct efi_unaccepted_memory *unaccepted_table; unsigned long cfg_table_pa; unsigned int cfg_table_len; + enum efi_type et; int ret; + et = efi_get_type(boot_params); + if (et == EFI_TYPE_NONE) + return; + ret = efi_get_conf_table(boot_params, &cfg_table_pa, &cfg_table_len); if (ret) error("EFI config table not found."); @@ -56,6 +61,9 @@ void init_unaccepted_memory(void) cfg_table_pa, cfg_table_len, guid); + if (!unaccepted_table) + return; + if (unaccepted_table->version != 1) error("Unknown version of unaccepted memory table\n");
On Mon, 22 May 2023 at 13:01, Kirill A. Shutemov <kirill@shutemov.name> wrote: > > On Fri, May 19, 2023 at 01:16:41PM +0300, Kirill A. Shutemov wrote: > > On Fri, May 19, 2023 at 02:14:29AM +0300, Kirill A. Shutemov wrote: > > > diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c > > > index 67594fcb11d9..87372b96d613 100644 > > > --- a/arch/x86/boot/compressed/mem.c > > > +++ b/arch/x86/boot/compressed/mem.c > > > @@ -1,9 +1,32 @@ > > > // SPDX-License-Identifier: GPL-2.0-only > > > > > > #include "error.h" > > > +#include "misc.h" > > > > > > void arch_accept_memory(phys_addr_t start, phys_addr_t end) > > > { > > > /* Platform-specific memory-acceptance call goes here */ > > > error("Cannot accept memory"); > > > } > > > + > > > +void init_unaccepted_memory(void) > > > +{ > > > + guid_t guid = LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID; > > > + struct efi_unaccepted_memory *unaccepted_table; > > > + unsigned long cfg_table_pa; > > > + unsigned int cfg_table_len; > > > + int ret; > > > + > > > + ret = efi_get_conf_table(boot_params, &cfg_table_pa, &cfg_table_len); > > > + if (ret) > > > + error("EFI config table not found."); > > > + > > > + unaccepted_table = (void *)efi_find_vendor_table(boot_params, > > > + cfg_table_pa, > > > + cfg_table_len, > > > + guid); > > > + if (unaccepted_table->version != 1) > > > + error("Unknown version of unaccepted memory table\n"); > > > + > > > + set_unaccepted_table(unaccepted_table); > > > +} > > > > 0-day reported boot failure outdise TDX guest with CONFIG_INTEL_TDX_GUEST=y. > > 0-day folks reported one more issue: booting on non-EFI system fail. > > Updated fixup: > > diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c > index 0108c97399a5..e7f7ef31e581 100644 > --- a/arch/x86/boot/compressed/mem.c > +++ b/arch/x86/boot/compressed/mem.c > @@ -46,8 +46,13 @@ void init_unaccepted_memory(void) > struct efi_unaccepted_memory *unaccepted_table; > unsigned long cfg_table_pa; > unsigned int cfg_table_len; > + enum efi_type et; > int ret; > > + et = efi_get_type(boot_params); > + if (et == EFI_TYPE_NONE) > + return; > + > ret = efi_get_conf_table(boot_params, &cfg_table_pa, &cfg_table_len); > if (ret) > error("EFI config table not found."); > @@ -56,6 +61,9 @@ void init_unaccepted_memory(void) > cfg_table_pa, > cfg_table_len, > guid); > + if (!unaccepted_table) > + return; > + > if (unaccepted_table->version != 1) > error("Unknown version of unaccepted memory table\n"); > With these changes applied, Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
diff --git a/arch/x86/boot/compressed/efi.h b/arch/x86/boot/compressed/efi.h index 7db2f41b54cd..866c0af8b5b9 100644 --- a/arch/x86/boot/compressed/efi.h +++ b/arch/x86/boot/compressed/efi.h @@ -16,6 +16,7 @@ typedef guid_t efi_guid_t __aligned(__alignof__(u32)); #define ACPI_TABLE_GUID EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) #define ACPI_20_TABLE_GUID EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81) #define EFI_CC_BLOB_GUID EFI_GUID(0x067b1f5f, 0xcf26, 0x44c5, 0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42) +#define LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID EFI_GUID(0xd5d1de3c, 0x105c, 0x44f9, 0x9e, 0xa9, 0xbc, 0xef, 0x98, 0x12, 0x00, 0x31) #define EFI32_LOADER_SIGNATURE "EL32" #define EFI64_LOADER_SIGNATURE "EL64" @@ -32,6 +33,7 @@ typedef struct { } efi_table_hdr_t; #define EFI_CONVENTIONAL_MEMORY 7 +#define EFI_UNACCEPTED_MEMORY 15 #define EFI_MEMORY_MORE_RELIABLE \ ((u64)0x0000000000010000ULL) /* higher reliability */ @@ -104,6 +106,14 @@ struct efi_setup_data { u64 reserved[8]; }; +struct efi_unaccepted_memory { + u32 version; + u32 unit_size; + u64 phys_base; + u64 size; + unsigned long bitmap[]; +}; + static inline int efi_guidcmp (efi_guid_t left, efi_guid_t right) { return memcmp(&left, &right, sizeof (efi_guid_t)); diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 454757fbdfe5..749f0fe7e446 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -672,6 +672,28 @@ static bool process_mem_region(struct mem_vector *region, } #ifdef CONFIG_EFI + +/* + * Only EFI_CONVENTIONAL_MEMORY and EFI_UNACCEPTED_MEMORY (if supported) are + * guaranteed to be free. + * + * It is more conservative in picking free memory than the EFI spec allows: + * + * According to the spec, EFI_BOOT_SERVICES_{CODE|DATA} are also free memory + * and thus available to place the kernel image into, but in practice there's + * firmware where using that memory leads to crashes. + */ +static inline bool memory_type_is_free(efi_memory_desc_t *md) +{ + if (md->type == EFI_CONVENTIONAL_MEMORY) + return true; + + if (md->type == EFI_UNACCEPTED_MEMORY) + return IS_ENABLED(CONFIG_UNACCEPTED_MEMORY); + + return false; +} + /* * Returns true if we processed the EFI memmap, which we prefer over the E820 * table if it is available. @@ -716,18 +738,7 @@ process_efi_entries(unsigned long minimum, unsigned long image_size) for (i = 0; i < nr_desc; i++) { md = efi_early_memdesc_ptr(pmap, e->efi_memdesc_size, i); - /* - * Here we are more conservative in picking free memory than - * the EFI spec allows: - * - * According to the spec, EFI_BOOT_SERVICES_{CODE|DATA} are also - * free memory and thus available to place the kernel image into, - * but in practice there's firmware where using that memory leads - * to crashes. - * - * Only EFI_CONVENTIONAL_MEMORY is guaranteed to be free. - */ - if (md->type != EFI_CONVENTIONAL_MEMORY) + if (!memory_type_is_free(md)) continue; if (efi_soft_reserve_enabled() && diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c index 67594fcb11d9..87372b96d613 100644 --- a/arch/x86/boot/compressed/mem.c +++ b/arch/x86/boot/compressed/mem.c @@ -1,9 +1,32 @@ // SPDX-License-Identifier: GPL-2.0-only #include "error.h" +#include "misc.h" void arch_accept_memory(phys_addr_t start, phys_addr_t end) { /* Platform-specific memory-acceptance call goes here */ error("Cannot accept memory"); } + +void init_unaccepted_memory(void) +{ + guid_t guid = LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID; + struct efi_unaccepted_memory *unaccepted_table; + unsigned long cfg_table_pa; + unsigned int cfg_table_len; + int ret; + + ret = efi_get_conf_table(boot_params, &cfg_table_pa, &cfg_table_len); + if (ret) + error("EFI config table not found."); + + unaccepted_table = (void *)efi_find_vendor_table(boot_params, + cfg_table_pa, + cfg_table_len, + guid); + if (unaccepted_table->version != 1) + error("Unknown version of unaccepted memory table\n"); + + set_unaccepted_table(unaccepted_table); +} diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 014ff222bf4b..36535a3753f5 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -455,6 +455,13 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, #endif debug_putstr("\nDecompressing Linux... "); + + if (IS_ENABLED(CONFIG_UNACCEPTED_MEMORY)) { + debug_putstr("Accepting memory... "); + init_unaccepted_memory(); + accept_memory(__pa(output), __pa(output) + needed_size); + } + __decompress(input_data, input_len, NULL, NULL, output, output_len, NULL, error); entry_offset = parse_elf(output); diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 2f155a0e3041..e1a0b49e0ed2 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -247,4 +247,10 @@ static inline unsigned long efi_find_vendor_table(struct boot_params *bp, } #endif /* CONFIG_EFI */ +void init_unaccepted_memory(void); + +/* Implemented in EFI stub */ +void set_unaccepted_table(struct efi_unaccepted_memory *table); +void accept_memory(phys_addr_t start, phys_addr_t end); + #endif /* BOOT_COMPRESSED_MISC_H */