diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/boot/compressed/misc.c | 6 | ||||
-rw-r--r-- | arch/x86/boot/compressed/pgtable.h | 11 | ||||
-rw-r--r-- | arch/x86/boot/compressed/pgtable_64.c | 34 |
3 files changed, 51 insertions, 0 deletions
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index b50c42455e25..8e4b55dd5df9 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -14,6 +14,7 @@ #include "misc.h" #include "error.h" +#include "pgtable.h" #include "../string.h" #include "../voffset.h" @@ -372,6 +373,11 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, debug_putaddr(output_len); debug_putaddr(kernel_total_size); +#ifdef CONFIG_X86_64 + /* Report address of 32-bit trampoline */ + debug_putaddr(trampoline_32bit); +#endif + /* * The memory hole needed for the kernel is the larger of either * the entire decompressed kernel plus relocation table, or the diff --git a/arch/x86/boot/compressed/pgtable.h b/arch/x86/boot/compressed/pgtable.h new file mode 100644 index 000000000000..57722a2fe2a0 --- /dev/null +++ b/arch/x86/boot/compressed/pgtable.h @@ -0,0 +1,11 @@ +#ifndef BOOT_COMPRESSED_PAGETABLE_H +#define BOOT_COMPRESSED_PAGETABLE_H + +#define TRAMPOLINE_32BIT_SIZE (2 * PAGE_SIZE) + +#ifndef __ASSEMBLER__ + +extern unsigned long *trampoline_32bit; + +#endif /* __ASSEMBLER__ */ +#endif /* BOOT_COMPRESSED_PAGETABLE_H */ diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c index 45c76eff2718..21d5cc1cd5fa 100644 --- a/arch/x86/boot/compressed/pgtable_64.c +++ b/arch/x86/boot/compressed/pgtable_64.c @@ -1,4 +1,5 @@ #include <asm/processor.h> +#include "pgtable.h" /* * __force_order is used by special_insns.h asm code to force instruction @@ -9,14 +10,27 @@ */ unsigned long __force_order; +#define BIOS_START_MIN 0x20000U /* 128K, less than this is insane */ +#define BIOS_START_MAX 0x9f000U /* 640K, absolute maximum */ + struct paging_config { unsigned long trampoline_start; unsigned long l5_required; }; +/* + * Trampoline address will be printed by extract_kernel() for debugging + * purposes. + * + * Avoid putting the pointer into .bss as it will be cleared between + * paging_prepare() and extract_kernel(). + */ +unsigned long *trampoline_32bit __section(.data); + struct paging_config paging_prepare(void) { struct paging_config paging_config = {}; + unsigned long bios_start, ebda_start; /* * Check if LA57 is desired and supported. @@ -35,5 +49,25 @@ struct paging_config paging_prepare(void) paging_config.l5_required = 1; } + /* + * Find a suitable spot for the trampoline. + * This code is based on reserve_bios_regions(). + */ + + ebda_start = *(unsigned short *)0x40e << 4; + bios_start = *(unsigned short *)0x413 << 10; + + if (bios_start < BIOS_START_MIN || bios_start > BIOS_START_MAX) + bios_start = BIOS_START_MAX; + + if (ebda_start > BIOS_START_MIN && ebda_start < bios_start) + bios_start = ebda_start; + + /* Place the trampoline just below the end of low memory, aligned to 4k */ + paging_config.trampoline_start = bios_start - TRAMPOLINE_32BIT_SIZE; + paging_config.trampoline_start = round_down(paging_config.trampoline_start, PAGE_SIZE); + + trampoline_32bit = (unsigned long *)paging_config.trampoline_start; + return paging_config; } |