Skip to content

Commit

Permalink
efi/zboot: arm64: Grab code size from ELF symbol in payload
Browse files Browse the repository at this point in the history
Instead of relying on a dodgy dd hack to copy the image code size from
the uncompressed image's PE header to the end of the compressed image,
let's grab the code size from the symbol that is injected into the ELF
object by the Kbuild rules that generate the compressed payload.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
  • Loading branch information
Ard Biesheuvel committed Apr 26, 2023
1 parent 45dd403 commit 026b857
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 30 deletions.
14 changes: 3 additions & 11 deletions drivers/firmware/efi/libstub/Makefile.zboot
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,13 @@ comp-type-$(CONFIG_KERNEL_ZSTD) := zstd22
# causing the original tools to complain when checking image integrity.
# So disregard it when calculating the payload size in the zimage header.
zboot-method-y := $(comp-type-y)_with_size
zboot-size-len-y := 12
zboot-size-len-y := 4

zboot-method-$(CONFIG_KERNEL_GZIP) := gzip
zboot-size-len-$(CONFIG_KERNEL_GZIP) := 8

# Copy the SizeOfHeaders and SizeOfCode fields from the payload to the end of
# the compressed image. Note that this presupposes a PE header offset of 64
# bytes, which is what arm64, RISC-V and LoongArch use.
quiet_cmd_compwithsize = $(quiet_cmd_$(zboot-method-y))
cmd_compwithsize = $(cmd_$(zboot-method-y)) && ( \
dd status=none if=$< bs=4 count=1 skip=37 ; \
dd status=none if=$< bs=4 count=1 skip=23 ) >> $@
zboot-size-len-$(CONFIG_KERNEL_GZIP) := 0

$(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE
$(call if_changed,compwithsize)
$(call if_changed,$(zboot-method-y))

OBJCOPYFLAGS_vmlinuz.o := -I binary -O $(EFI_ZBOOT_BFD_TARGET) $(EFI_ZBOOT_OBJCOPY_FLAGS) \
--rename-section .data=.gzdata,load,alloc,readonly,contents
Expand Down
19 changes: 13 additions & 6 deletions drivers/firmware/efi/libstub/arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <linux/efi.h>
#include <asm/efi.h>
#include <asm/image.h>
#include <asm/memory.h>
#include <asm/sysreg.h>

Expand Down Expand Up @@ -88,26 +89,32 @@ efi_status_t check_platform_features(void)
#define DCTYPE "cvau"
#endif

u32 __weak code_size;

void efi_cache_sync_image(unsigned long image_base,
unsigned long alloc_size,
unsigned long code_size)
unsigned long alloc_size)
{
u32 ctr = read_cpuid_effective_cachetype();
u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr,
CTR_EL0_DminLine_SHIFT);

/* only perform the cache maintenance if needed for I/D coherency */
if (!(ctr & BIT(CTR_EL0_IDC_SHIFT))) {
unsigned long base = image_base;
unsigned long size = code_size;

do {
asm("dc " DCTYPE ", %0" :: "r"(image_base));
image_base += lsize;
code_size -= lsize;
} while (code_size >= lsize);
asm("dc " DCTYPE ", %0" :: "r"(base));
base += lsize;
size -= lsize;
} while (size >= lsize);
}

asm("ic ialluis");
dsb(ish);
isb();

efi_remap_image(image_base, alloc_size, code_size);
}

unsigned long __weak primary_entry_offset(void)
Expand Down
3 changes: 1 addition & 2 deletions drivers/firmware/efi/libstub/efistub.h
Original file line number Diff line number Diff line change
Expand Up @@ -1066,8 +1066,7 @@ struct screen_info *__alloc_screen_info(void);
void free_screen_info(struct screen_info *si);

void efi_cache_sync_image(unsigned long image_base,
unsigned long alloc_size,
unsigned long code_size);
unsigned long alloc_size);

struct efi_smbios_record {
u8 type;
Expand Down
15 changes: 4 additions & 11 deletions drivers/firmware/efi/libstub/zboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ static unsigned long alloc_preferred_address(unsigned long alloc_size)
}

void __weak efi_cache_sync_image(unsigned long image_base,
unsigned long alloc_size,
unsigned long code_size)
unsigned long alloc_size)
{
// Provided by the arch to perform the cache maintenance necessary for
// executable code loaded into memory to be safe for execution.
Expand All @@ -66,7 +65,7 @@ asmlinkage efi_status_t __efiapi
efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
{
unsigned long compressed_size = _gzdata_end - _gzdata_start;
unsigned long image_base, alloc_size, code_size;
unsigned long image_base, alloc_size;
efi_loaded_image_t *image;
efi_status_t status;
char *cmdline_ptr;
Expand All @@ -91,13 +90,9 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
efi_info("Decompressing Linux Kernel...\n");

// SizeOfImage from the compressee's PE/COFF header
alloc_size = round_up(get_unaligned_le32(_gzdata_end - 12),
alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4),
EFI_ALLOC_ALIGN);

// SizeOfHeaders and SizeOfCode from the compressee's PE/COFF header
code_size = get_unaligned_le32(_gzdata_end - 4) +
get_unaligned_le32(_gzdata_end - 8);

// If the architecture has a preferred address for the image,
// try that first.
image_base = alloc_preferred_address(alloc_size);
Expand Down Expand Up @@ -140,9 +135,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
goto free_image;
}

efi_cache_sync_image(image_base, alloc_size, code_size);

efi_remap_image(image_base, alloc_size, code_size);
efi_cache_sync_image(image_base, alloc_size);

status = efi_stub_common(handle, image, image_base, cmdline_ptr);

Expand Down

0 comments on commit 026b857

Please sign in to comment.