Commit 5ff3e2c3c3eebe13967d81ad1f23b9468fefea81
Committed by
Ingo Molnar
1 parent
d0de0f685d
x86/boot: Rework reserve_real_mode() to allow multiple tries
If reserve_real_mode() fails, panicing immediately means we're doomed. Make it safe to try more than once to allocate the trampoline: - Degrade a failure from panic() to pr_info(). (If we make it to setup_real_mode() without reserving the trampoline, we'll panic them.) - Factor out helpers so that platform code can supply a specific address to try. - Warn if reserve_real_mode() is called after we're done with the memblock allocator. If that were to happen, we would behave unpredictably. Signed-off-by: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mario Limonciello <mario_limonciello@dell.com> Cc: Matt Fleming <mfleming@suse.de> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/876e383038f3e9971aa72fd20a4f5da05f9d193d.1470821230.git.luto@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Showing 2 changed files with 30 additions and 8 deletions Side-by-side Diff
arch/x86/include/asm/realmode.h
... | ... | @@ -58,6 +58,15 @@ |
58 | 58 | extern unsigned char secondary_startup_64[]; |
59 | 59 | #endif |
60 | 60 | |
61 | +static inline size_t real_mode_size_needed(void) | |
62 | +{ | |
63 | + if (real_mode_header) | |
64 | + return 0; /* already allocated. */ | |
65 | + | |
66 | + return ALIGN(real_mode_blob_end - real_mode_blob, PAGE_SIZE); | |
67 | +} | |
68 | + | |
69 | +void set_real_mode_mem(phys_addr_t mem, size_t size); | |
61 | 70 | void reserve_real_mode(void); |
62 | 71 | |
63 | 72 | #endif /* _ARCH_X86_REALMODE_H */ |
arch/x86/realmode/init.c
1 | 1 | #include <linux/io.h> |
2 | +#include <linux/slab.h> | |
2 | 3 | #include <linux/memblock.h> |
3 | 4 | |
4 | 5 | #include <asm/cacheflush.h> |
5 | 6 | |
6 | 7 | |
7 | 8 | |
8 | 9 | |
9 | 10 | |
... | ... | @@ -12,22 +13,34 @@ |
12 | 13 | /* Hold the pgd entry used on booting additional CPUs */ |
13 | 14 | pgd_t trampoline_pgd_entry; |
14 | 15 | |
16 | +void __init set_real_mode_mem(phys_addr_t mem, size_t size) | |
17 | +{ | |
18 | + void *base = __va(mem); | |
19 | + | |
20 | + real_mode_header = (struct real_mode_header *) base; | |
21 | + printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", | |
22 | + base, (unsigned long long)mem, size); | |
23 | +} | |
24 | + | |
15 | 25 | void __init reserve_real_mode(void) |
16 | 26 | { |
17 | 27 | phys_addr_t mem; |
18 | - unsigned char *base; | |
19 | - size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); | |
28 | + size_t size = real_mode_size_needed(); | |
20 | 29 | |
30 | + if (!size) | |
31 | + return; | |
32 | + | |
33 | + WARN_ON(slab_is_available()); | |
34 | + | |
21 | 35 | /* Has to be under 1M so we can execute real-mode AP code. */ |
22 | 36 | mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); |
23 | - if (!mem) | |
24 | - panic("Cannot allocate trampoline\n"); | |
37 | + if (!mem) { | |
38 | + pr_info("No sub-1M memory is available for the trampoline\n"); | |
39 | + return; | |
40 | + } | |
25 | 41 | |
26 | - base = __va(mem); | |
27 | 42 | memblock_reserve(mem, size); |
28 | - real_mode_header = (struct real_mode_header *) base; | |
29 | - printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", | |
30 | - base, (unsigned long long)mem, size); | |
43 | + set_real_mode_mem(mem, size); | |
31 | 44 | } |
32 | 45 | |
33 | 46 | static void __init setup_real_mode(void) |