[PATCH v2 0/5] Minimize the need to move the kernel in the EFI stub

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This series adds the ability to use the entire PE image space for
decompression, provides the preferred address to the PE loader via the
header, and finally restricts efi_relocate_kernel to cases where we
really need it rather than whenever we were loaded at something other
than preferred address.

Based on tip:efi/core + the cleanup series [1]
[1] https://lore.kernel.org/linux-efi/20200301230436.2246909-1-nivedita@xxxxxxxxxxxx/

Changes from v1
- clarify a few comments
- cleanups to code formatting

Arvind Sankar (5):
  x86/boot/compressed/32: Save the output address instead of
    recalculating it
  efi/x86: Decompress at start of PE image load address
  efi/x86: Add kernel preferred address to PE header
  efi/x86: Remove extra headroom for setup block
  efi/x86: Don't relocate the kernel unless necessary

 arch/x86/boot/compressed/head_32.S      | 42 +++++++++++++++-------
 arch/x86/boot/compressed/head_64.S      | 42 ++++++++++++++++++++--
 arch/x86/boot/header.S                  |  6 ++--
 arch/x86/boot/tools/build.c             | 44 ++++++++++++++++-------
 drivers/firmware/efi/libstub/x86-stub.c | 48 ++++++++++++++++++++++---
 5 files changed, 147 insertions(+), 35 deletions(-)

Range-diff against v1:
1:  0cdb6bf27a24 ! 1:  2ecbf60b9ecd x86/boot/compressed/32: Save the output address instead of recalculating it
    @@ Metadata
      ## Commit message ##
         x86/boot/compressed/32: Save the output address instead of recalculating it
     
    -    In preparation for being able to decompress starting at a different
    -    address than startup_32, save the calculated output address instead of
    -    recalculating it later.
    +    In preparation for being able to decompress into a buffer starting at a
    +    different address than startup_32, save the calculated output address
    +    instead of recalculating it later.
     
         We now keep track of three addresses:
                 %edx: startup_32 as we were loaded by bootloader
2:  d4df840752ac ! 2:  e2bdbe6cb692 efi/x86: Decompress at start of PE image load address
    @@ arch/x86/boot/compressed/head_64.S: SYM_FUNC_START(efi32_pe_entry)
      	movl	-4(%ebp), %esi			// loaded_image
      	movl	LI32_image_base(%esi), %esi	// loaded_image->image_base
      	movl	%ebx, %ebp			// startup_32 for efi32_pe_stub_entry
    ++	/*
    ++	 * We need to set the image_offset variable here since startup_32 will
    ++	 * use it before we get to the 64-bit efi_pe_entry in C code.
    ++	 */
     +	subl	%esi, %ebx
     +	movl	%ebx, image_offset(%ebp)	// save image_offset
      	jmp	efi32_pe_stub_entry
    @@ drivers/firmware/efi/libstub/x86-stub.c: unsigned long efi_main(efi_handle_t han
      			efi_printk("efi_relocate_kernel() failed!\n");
      			goto fail;
      		}
    ++		/*
    ++		 * Now that we've copied the kernel elsewhere, we no longer
    ++		 * have a setup block before startup_32, so reset image_offset
    ++		 * to zero in case it was set earlier.
    ++		 */
     +		image_offset = 0;
      	}
      
3:  4bae68f25b90 ! 3:  ea840f78f138 efi/x86: Add kernel preferred address to PE header
    @@ arch/x86/boot/header.S: optional_header:
      
      extra_header_fields:
     +	# PE specification requires ImageBase to be 64k-aligned
    -+	.set	ImageBase, (LOAD_PHYSICAL_ADDR+0xffff) & ~0xffff
    ++	.set	image_base, (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff
      #ifdef CONFIG_X86_32
     -	.long	0				# ImageBase
    -+	.long	ImageBase			# ImageBase
    ++	.long	image_base			# ImageBase
      #else
     -	.quad	0				# ImageBase
    -+	.quad	ImageBase			# ImageBase
    ++	.quad	image_base			# ImageBase
      #endif
      	.long	0x20				# SectionAlignment
      	.long	0x20				# FileAlignment
4:  2330a25c6b0f ! 4:  c25a9b507d6d efi/x86: Remove extra headroom for setup block
    @@ Commit message
         account for setup block") added headroom to the PE image to account for
         the setup block, which wasn't used for the decompression buffer.
     
    -    Now that we decompress from the start of the image, this is no longer
    -    required.
    +    Now that the decompression buffer is located at the start of the image,
    +    and includes the setup block, this is no longer required.
     
         Add a check to make sure that the head section of the compressed kernel
         won't overwrite itself while relocating. This is only for
5:  2081f91cbe75 ! 5:  d3dc3af1c7b8 efi/x86: Don't relocate the kernel unless necessary
    @@ arch/x86/boot/tools/build.c: static void update_pecoff_text(unsigned int text_st
      	 * Size of code: Subtract the size of the first sector (512 bytes)
     
      ## drivers/firmware/efi/libstub/x86-stub.c ##
    +@@
    + 
    + #include "efistub.h"
    + 
    ++/* Maximum physical address for 64-bit kernel with 4-level paging */
    ++#define MAXMEM_X86_64_4LEVEL (1ull << 46)
    ++
    + static efi_system_table_t *sys_table;
    + extern const bool efi_is64;
    + extern u32 image_offset;
     @@ drivers/firmware/efi/libstub/x86-stub.c: unsigned long efi_main(efi_handle_t handle,
      			     struct boot_params *boot_params)
      {
    @@ drivers/firmware/efi/libstub/x86-stub.c: unsigned long efi_main(efi_handle_t han
     -	 * address, relocate it.
     +	 * If the kernel isn't already loaded at a suitable address,
     +	 * relocate it.
    ++	 *
     +	 * It must be loaded above LOAD_PHYSICAL_ADDR.
    -+	 * The maximum address for 64-bit is 1 << 46 for 4-level paging.
    ++	 *
    ++	 * The maximum address for 64-bit is 1 << 46 for 4-level paging. This
    ++	 * is defined as the macro MAXMEM, but unfortunately that is not a
    ++	 * compile-time constant if 5-level paging is configured, so we instead
    ++	 * define our own macro for use here.
    ++	 *
     +	 * For 32-bit, the maximum address is complicated to figure out, for
     +	 * now use KERNEL_IMAGE_SIZE, which will be 512MiB, the same as what
     +	 * KASLR uses.
    ++	 *
     +	 * Also relocate it if image_offset is zero, i.e. we weren't loaded by
     +	 * LoadImage, but we are not aligned correctly.
      	 */
     -	if (bzimage_addr - image_offset != hdr->pref_address) {
    ++
     +	buffer_start = ALIGN(bzimage_addr - image_offset,
     +			     hdr->kernel_alignment);
     +	buffer_end = buffer_start + hdr->init_size;
     +
    -+	if (buffer_start < LOAD_PHYSICAL_ADDR
    -+	    || IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE
    -+	    || IS_ENABLED(CONFIG_X86_64) && buffer_end > 1ull << 46
    -+	    || image_offset == 0 && !IS_ALIGNED(bzimage_addr,
    -+						hdr->kernel_alignment)) {
    ++	if ((buffer_start < LOAD_PHYSICAL_ADDR)				     ||
    ++	    (IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE)    ||
    ++	    (IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) ||
    ++	    (image_offset == 0 && !IS_ALIGNED(bzimage_addr,
    ++					      hdr->kernel_alignment))) {
      		status = efi_relocate_kernel(&bzimage_addr,
      					     hdr->init_size, hdr->init_size,
      					     hdr->pref_address,
-- 
2.24.1




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux