[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <tip-b84a64fad40637b1c9fa4f4dbf847a23e29e672b@git.kernel.org>
Date: Fri, 30 Nov 2018 01:55:02 -0800
From: tip-bot for Eric Snowberg <tipbot@...or.com>
To: linux-tip-commits@...r.kernel.org
Cc: natechancellor@...il.com, linux-kernel@...r.kernel.org,
torvalds@...ux-foundation.org, julien.thierry@....com,
tglx@...utronix.de, ard.biesheuvel@...aro.org,
jonathanh@...dia.com, arend.vanspriel@...adcom.com,
dave.hansen@...el.com, sedat.dilek@...il.com, hpa@...or.com,
mingo@...nel.org, peterz@...radead.org, zhuyifei1999@...il.com,
matt@...eblueprint.co.uk, eric.snowberg@...cle.com,
sai.praneeth.prakhya@...el.com, luto@...nel.org,
bhsharma@...hat.com, marc.zyngier@....com, hdegoede@...hat.com,
joe@...ches.com, bp@...en8.de, stable@...r.kernel.org
Subject: [tip:efi/core] x86/efi: Allocate e820 buffer before calling
efi_exit_boot_service
Commit-ID: b84a64fad40637b1c9fa4f4dbf847a23e29e672b
Gitweb: https://git.kernel.org/tip/b84a64fad40637b1c9fa4f4dbf847a23e29e672b
Author: Eric Snowberg <eric.snowberg@...cle.com>
AuthorDate: Thu, 29 Nov 2018 18:12:20 +0100
Committer: Ingo Molnar <mingo@...nel.org>
CommitDate: Fri, 30 Nov 2018 08:30:07 +0100
x86/efi: Allocate e820 buffer before calling efi_exit_boot_service
The following commit:
d64934019f6c ("x86/efi: Use efi_exit_boot_services()")
introduced a regression on systems with large memory maps causing them
to hang on boot. The first "goto get_map" that was removed from
exit_boot() ensured there was enough room for the memory map when
efi_call_early(exit_boot_services) was called. This happens when
(nr_desc > ARRAY_SIZE(params->e820_table).
Chain of events:
exit_boot()
efi_exit_boot_services()
efi_get_memory_map <- at this point the mm can't grow over 8 desc
priv_func()
exit_boot_func()
allocate_e820ext() <- new mm grows over 8 desc from e820 alloc
efi_call_early(exit_boot_services) <- mm key doesn't match so retry
efi_call_early(get_memory_map) <- not enough room for new mm
system hangs
This patch allocates the e820 buffer before calling efi_exit_boot_services()
and fixes the regression.
[ mingo: minor cleanliness edits. ]
Signed-off-by: Eric Snowberg <eric.snowberg@...cle.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@...aro.org>
Cc: <stable@...r.kernel.org>
Cc: Andy Lutomirski <luto@...nel.org>
Cc: Arend van Spriel <arend.vanspriel@...adcom.com>
Cc: Bhupesh Sharma <bhsharma@...hat.com>
Cc: Borislav Petkov <bp@...en8.de>
Cc: Dave Hansen <dave.hansen@...el.com>
Cc: Hans de Goede <hdegoede@...hat.com>
Cc: Joe Perches <joe@...ches.com>
Cc: Jon Hunter <jonathanh@...dia.com>
Cc: Julien Thierry <julien.thierry@....com>
Cc: Linus Torvalds <torvalds@...ux-foundation.org>
Cc: Marc Zyngier <marc.zyngier@....com>
Cc: Matt Fleming <matt@...eblueprint.co.uk>
Cc: Nathan Chancellor <natechancellor@...il.com>
Cc: Peter Zijlstra <peterz@...radead.org>
Cc: Sai Praneeth Prakhya <sai.praneeth.prakhya@...el.com>
Cc: Sedat Dilek <sedat.dilek@...il.com>
Cc: Thomas Gleixner <tglx@...utronix.de>
Cc: YiFei Zhu <zhuyifei1999@...il.com>
Cc: linux-efi@...r.kernel.org
Link: http://lkml.kernel.org/r/20181129171230.18699-2-ard.biesheuvel@linaro.org
Signed-off-by: Ingo Molnar <mingo@...nel.org>
---
arch/x86/boot/compressed/eboot.c | 65 +++++++++++++++++++++++++---------------
1 file changed, 41 insertions(+), 24 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 8b4c5e001157..544ac4fafd11 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -1,3 +1,4 @@
+
/* -----------------------------------------------------------------------
*
* Copyright 2011 Intel Corporation; author Matt Fleming
@@ -634,37 +635,54 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
return status;
}
+static efi_status_t allocate_e820(struct boot_params *params,
+ struct setup_data **e820ext,
+ u32 *e820ext_size)
+{
+ unsigned long map_size, desc_size, buff_size;
+ struct efi_boot_memmap boot_map;
+ efi_memory_desc_t *map;
+ efi_status_t status;
+ __u32 nr_desc;
+
+ boot_map.map = ↦
+ boot_map.map_size = &map_size;
+ boot_map.desc_size = &desc_size;
+ boot_map.desc_ver = NULL;
+ boot_map.key_ptr = NULL;
+ boot_map.buff_size = &buff_size;
+
+ status = efi_get_memory_map(sys_table, &boot_map);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ nr_desc = buff_size / desc_size;
+
+ if (nr_desc > ARRAY_SIZE(params->e820_table)) {
+ u32 nr_e820ext = nr_desc - ARRAY_SIZE(params->e820_table);
+
+ status = alloc_e820ext(nr_e820ext, e820ext, e820ext_size);
+ if (status != EFI_SUCCESS)
+ return status;
+ }
+
+ return EFI_SUCCESS;
+}
+
struct exit_boot_struct {
struct boot_params *boot_params;
struct efi_info *efi;
- struct setup_data *e820ext;
- __u32 e820ext_size;
};
static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
struct efi_boot_memmap *map,
void *priv)
{
- static bool first = true;
const char *signature;
__u32 nr_desc;
efi_status_t status;
struct exit_boot_struct *p = priv;
- if (first) {
- nr_desc = *map->buff_size / *map->desc_size;
- if (nr_desc > ARRAY_SIZE(p->boot_params->e820_table)) {
- u32 nr_e820ext = nr_desc -
- ARRAY_SIZE(p->boot_params->e820_table);
-
- status = alloc_e820ext(nr_e820ext, &p->e820ext,
- &p->e820ext_size);
- if (status != EFI_SUCCESS)
- return status;
- }
- first = false;
- }
-
signature = efi_is_64bit() ? EFI64_LOADER_SIGNATURE
: EFI32_LOADER_SIGNATURE;
memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
@@ -687,8 +705,8 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
{
unsigned long map_sz, key, desc_size, buff_size;
efi_memory_desc_t *mem_map;
- struct setup_data *e820ext;
- __u32 e820ext_size;
+ struct setup_data *e820ext = NULL;
+ __u32 e820ext_size = 0;
efi_status_t status;
__u32 desc_version;
struct efi_boot_memmap map;
@@ -702,8 +720,10 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
map.buff_size = &buff_size;
priv.boot_params = boot_params;
priv.efi = &boot_params->efi_info;
- priv.e820ext = NULL;
- priv.e820ext_size = 0;
+
+ status = allocate_e820(boot_params, &e820ext, &e820ext_size);
+ if (status != EFI_SUCCESS)
+ return status;
/* Might as well exit boot services now */
status = efi_exit_boot_services(sys_table, handle, &map, &priv,
@@ -711,9 +731,6 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
if (status != EFI_SUCCESS)
return status;
- e820ext = priv.e820ext;
- e820ext_size = priv.e820ext_size;
-
/* Historic? */
boot_params->alt_mem_k = 32 * 1024;
Powered by blists - more mailing lists