Re: [PATCH 12/16] x86/boot: Add EFI kernel extraction interface
From: Ard Biesheuvel
Date: Wed Oct 19 2022 - 03:27:58 EST
On Tue, 6 Sept 2022 at 12:42, Evgeniy Baskov <baskov@xxxxxxxxx> wrote:
>
> To enable extraction of kernel image from EFI stub code directly
> extraction code needs to have separate interface that avoid part
> of low level initialization logic, i.e. serial port setup.
>
> Add kernel extraction function callable from libstub as a part
> of preparation for extracting the kernel directly from EFI environment.
>
> Signed-off-by: Evgeniy Baskov <baskov@xxxxxxxxx>
> ---
> arch/x86/boot/compressed/head_32.S | 3 +-
> arch/x86/boot/compressed/head_64.S | 2 +-
> arch/x86/boot/compressed/misc.c | 85 +++++++++++++++++++++---------
> arch/x86/boot/compressed/misc.h | 2 +
> arch/x86/boot/compressed/putstr.c | 9 ++++
> 5 files changed, 73 insertions(+), 28 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
> index 3b354eb9516d..b46a1c4109cf 100644
> --- a/arch/x86/boot/compressed/head_32.S
> +++ b/arch/x86/boot/compressed/head_32.S
> @@ -217,8 +217,7 @@ SYM_DATA(image_offset, .long 0)
> */
> .bss
> .balign 4
> -boot_heap:
> - .fill BOOT_HEAP_SIZE, 1, 0
> +SYM_DATA(boot_heap, .fill BOOT_HEAP_SIZE, 1, 0)
> boot_stack:
> .fill BOOT_STACK_SIZE, 1, 0
> boot_stack_end:
> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index 889ca7176aa7..37ce094571b5 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/arch/x86/boot/compressed/head_64.S
> @@ -1007,7 +1007,7 @@ SYM_FUNC_END(startup32_check_sev_cbit)
> */
> .bss
> .balign 4
> -SYM_DATA_LOCAL(boot_heap, .fill BOOT_HEAP_SIZE, 1, 0)
> +SYM_DATA(boot_heap, .fill BOOT_HEAP_SIZE, 1, 0)
>
> SYM_DATA_START_LOCAL(boot_stack)
> .fill BOOT_STACK_SIZE, 1, 0
> diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
> index e2c0d05ac293..8016cc5c300e 100644
> --- a/arch/x86/boot/compressed/misc.c
> +++ b/arch/x86/boot/compressed/misc.c
> @@ -293,11 +293,11 @@ static void parse_elf(void *output, unsigned long output_len,
> * |-------uncompressed kernel image---------|
> *
> */
> -asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
> - unsigned char *input_data,
> - unsigned long input_len,
> - unsigned char *output,
> - unsigned long output_len)
> +static void *do_extract_kernel(void *rmode,
> + unsigned char *input_data,
> + unsigned long input_len,
> + unsigned char *output,
> + unsigned long output_len)
> {
> const unsigned long kernel_total_size = VO__end - VO__text;
> unsigned long virt_addr = LOAD_PHYSICAL_ADDR;
> @@ -311,18 +311,6 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
>
> sanitize_boot_params(boot_params);
>
> - init_default_io_ops();
> -
> - /*
> - * Detect TDX guest environment.
> - *
> - * It has to be done before console_init() in order to use
> - * paravirtualized port I/O operations if needed.
> - */
> - early_tdx_detect();
> -
> - init_bare_console();
> -
> /*
> * Save RSDP address for later use. Have this after console_init()
> * so that early debugging output from the RSDP parsing code can be
> @@ -330,11 +318,6 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
> */
> boot_params->acpi_rsdp_addr = get_rsdp_addr();
>
> - debug_putstr("early console in extract_kernel\n");
> -
> - free_mem_ptr = heap; /* Heap */
> - free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
> -
> /*
> * The memory hole needed for the kernel is the larger of either
> * the entire decompressed kernel plus relocation table, or the
> @@ -387,12 +370,12 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
> if (virt_addr & (MIN_KERNEL_ALIGN - 1))
> error("Destination virtual address inappropriately aligned");
> #ifdef CONFIG_X86_64
> - if (heap > 0x3fffffffffffUL)
> + if (phys_addr > 0x3fffffffffffUL)
> error("Destination address too large");
> if (virt_addr + max(output_len, kernel_total_size) > KERNEL_IMAGE_SIZE)
> error("Destination virtual address is beyond the kernel mapping area");
> #else
> - if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
> + if (phys_addr > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
> error("Destination address too large");
> #endif
> #ifndef CONFIG_RELOCATABLE
> @@ -406,12 +389,64 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
> parse_elf(output, output_len, virt_addr);
> debug_putstr("done.\nBooting the kernel.\n");
>
> + return output;
> +}
> +
> +asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
> + unsigned char *input_data,
> + unsigned long input_len,
> + unsigned char *output,
> + unsigned long output_len)
> +{
> + void *entry;
> +
> + init_default_io_ops();
> +
> + /*
> + * Detect TDX guest environment.
> + *
> + * It has to be done before console_init() in order to use
> + * paravirtualized port I/O operations if needed.
> + */
> + early_tdx_detect();
> +
> + init_bare_console();
> +
> + debug_putstr("early console in extract_kernel\n");
> +
> + free_mem_ptr = heap; /* Heap */
> + free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
> +
> + entry = do_extract_kernel(rmode, input_data,
> + input_len, output, output_len);
> +
> /* Disable exception handling before booting the kernel */
> cleanup_exception_handling();
>
> - return output;
> + return entry;
> }
>
> +void *efi_extract_kernel(struct boot_params *rmode,
> + struct efi_iofunc *iofunc,
> + unsigned char *input_data,
> + unsigned long input_len,
> + unsigned char *output,
> + unsigned long output_len)
> +{
> + extern char boot_heap[BOOT_HEAP_SIZE];
> +
> + free_mem_ptr = (unsigned long)boot_heap; /* Heap */
> + free_mem_end_ptr = (unsigned long)boot_heap + BOOT_HEAP_SIZE;
> +
> + init_efi_console(iofunc);
> +
> + return do_extract_kernel(rmode, input_data,
> + input_len, output, output_len);
> +}
> +
> +
> +
> +
> void fortify_panic(const char *name)
> {
> error("detected buffer overflow");
> diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
> index 39dc3de50268..b5aa0af6c59e 100644
> --- a/arch/x86/boot/compressed/misc.h
> +++ b/arch/x86/boot/compressed/misc.h
> @@ -26,6 +26,7 @@
> #include <asm/boot.h>
> #include <asm/bootparam.h>
> #include <asm/desc_defs.h>
> +#include <asm/shared/extract.h>
>
> #include "tdx.h"
>
> @@ -126,6 +127,7 @@ static inline void console_init(void)
>
> /* putstr.c */
> void init_bare_console(void);
> +void init_efi_console(struct efi_iofunc *iofunc);
>
> #ifdef CONFIG_AMD_MEM_ENCRYPT
> void sev_enable(struct boot_params *bp);
> diff --git a/arch/x86/boot/compressed/putstr.c b/arch/x86/boot/compressed/putstr.c
> index accba0de8be9..238d9677df61 100644
> --- a/arch/x86/boot/compressed/putstr.c
> +++ b/arch/x86/boot/compressed/putstr.c
> @@ -32,6 +32,15 @@ void init_bare_console(void)
> console_init();
> }
>
> +void init_efi_console(struct efi_iofunc *iofunc)
struct efi_iofunc does not exist yet
> +{
> + __putstr = iofunc->putstr;
> + __puthex = iofunc->puthex;
> +#ifdef CONFIG_X86_64
> + kernel_add_identity_map = iofunc->map_range;
> +#endif
> +}
> +
> static void scroll(void)
> {
> int i;
> --
> 2.35.1
>