[PATCH 086/112] ARM64: add optional EFI stub
Ahmad Fatoum
a.fatoum at pengutronix.de
Wed Jan 3 10:12:46 PST 2024
While very recent binutils releases have dedicated efi-*-aarch targets,
we may want to support older toolchains. For this reason, we import
the kernel's EFI stub PE fakery, so the same barebox-dt-2nd.img may be
loaded as if it were a "normal" or an EFI-stubbed kernel.
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
Makefile | 6 +-
arch/arm/Kconfig | 1 +
arch/arm/cpu/Kconfig | 1 +
arch/arm/cpu/board-dt-2nd-aarch64.S | 8 +-
arch/arm/cpu/cpu.c | 6 ++
arch/arm/cpu/efi-header-aarch64.S | 122 ++++++++++++++++++++++++++++
arch/arm/cpu/entry.c | 3 +
arch/arm/cpu/interrupts_64.c | 6 +-
arch/arm/cpu/mmu-common.c | 4 +
arch/arm/cpu/start.c | 16 ++--
arch/arm/include/asm/pci.h | 4 +-
arch/arm/lib/pbl.lds.S | 13 +++
arch/arm/lib64/armlinux.c | 4 +
arch/x86/Kconfig | 1 +
efi/Kconfig | 13 ++-
efi/payload/Makefile | 2 +
efi/payload/boarddata.c | 45 ++++++++++
efi/payload/entry-multi.c | 45 ++++++++++
include/pbl.h | 4 +
test/self/mmu.c | 7 ++
20 files changed, 299 insertions(+), 12 deletions(-)
create mode 100644 arch/arm/cpu/efi-header-aarch64.S
create mode 100644 efi/payload/boarddata.c
create mode 100644 efi/payload/entry-multi.c
diff --git a/Makefile b/Makefile
index c5c627bb6a8c..a49b3c62d2bf 100644
--- a/Makefile
+++ b/Makefile
@@ -734,7 +734,11 @@ images: barebox.bin FORCE
images/%.s: barebox.bin FORCE
$(Q)$(MAKE) $(build)=images $@
-ifdef CONFIG_PBL_IMAGE
+ifdef CONFIG_EFI_STUB
+all: barebox.bin images barebox.efi
+barebox.efi: FORCE
+ $(Q)ln -fsn images/barebox-dt-2nd.img $@
+else ifdef CONFIG_PBL_IMAGE
all: barebox.bin images
else
all: barebox-flash-image barebox-flash-images
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ee3914620ecd..186e045d3512 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -9,6 +9,7 @@ config ARM
select HAVE_ARCH_KASAN
select ARCH_HAS_SJLJ
select ARM_OPTIMZED_STRING_FUNCTIONS if KASAN
+ select HAVE_EFI_STUB
default y
config ARM_LINUX
diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig
index 40dd35833a63..e69acaacdf2f 100644
--- a/arch/arm/cpu/Kconfig
+++ b/arch/arm/cpu/Kconfig
@@ -21,6 +21,7 @@ config CPU_64
select HAS_DMA
select ARCH_WANT_FRAME_POINTERS
select ARCH_HAS_ZERO_PAGE
+ select HAVE_EFI_PAYLOAD
# Select CPU types depending on the architecture selected. This selects
# which CPUs we support in the kernel image, and the compiler instruction
diff --git a/arch/arm/cpu/board-dt-2nd-aarch64.S b/arch/arm/cpu/board-dt-2nd-aarch64.S
index d2c9f132cef6..030366c1cbf5 100644
--- a/arch/arm/cpu/board-dt-2nd-aarch64.S
+++ b/arch/arm/cpu/board-dt-2nd-aarch64.S
@@ -2,6 +2,7 @@
#include <linux/linkage.h>
#include <asm/barebox-arm64.h>
#include <asm/image.h>
+#include "efi-header-aarch64.S"
#define IMAGE_FLAGS \
(ARM64_IMAGE_FLAG_PAGE_SIZE_4K << ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT) | \
@@ -9,7 +10,7 @@
.section .text_head_entry_start_dt_2nd
ENTRY("start_dt_2nd")
- adr x1, 0 /* code0 */
+ efi_signature_nop /* code0 */
b 2f /* code1 */
.xword 0x80000 /* Image load offset */
.xword _barebox_image_size /* Effective Image size */
@@ -18,12 +19,15 @@ ENTRY("start_dt_2nd")
.xword 0 /* reserved */
.xword 0 /* reserved */
.ascii ARM64_IMAGE_MAGIC /* magic number */
- .int 0 /* reserved (PE-COFF offset) */
+ .int .Lpe_header_offset /* reserved (PE-COFF offset) */
.asciz "barebox" /* unused for now */
2:
+ adr x1, 0
mov sp, x1
/* Stack now grows into the 0x80000 image load offset specified
* above. This is more than enough until FDT /memory is decoded.
*/
b dt_2nd_aarch64
+
+ __EFI_PE_HEADER
ENTRY_PROC_END(start_dt_2nd)
diff --git a/arch/arm/cpu/cpu.c b/arch/arm/cpu/cpu.c
index cacd442b28da..5f1ffe9a3c76 100644
--- a/arch/arm/cpu/cpu.c
+++ b/arch/arm/cpu/cpu.c
@@ -17,6 +17,7 @@
#include <asm/cputype.h>
#include <asm/cache.h>
#include <asm/ptrace.h>
+#include <efi/efi-mode.h>
/**
* Enable processor's instruction cache
@@ -82,6 +83,8 @@ static void disable_interrupts(void)
*/
static void arch_shutdown(void)
{
+ if (efi_is_payload())
+ return;
#ifdef CONFIG_MMU
mmu_disable();
@@ -96,6 +99,9 @@ extern unsigned long arm_stack_top;
static int arm_request_stack(void)
{
+ if (efi_is_payload())
+ return 0;
+
if (!request_sdram_region("stack", arm_stack_top - STACK_SIZE, STACK_SIZE))
pr_err("Error: Cannot request SDRAM region for stack\n");
diff --git a/arch/arm/cpu/efi-header-aarch64.S b/arch/arm/cpu/efi-header-aarch64.S
new file mode 100644
index 000000000000..941d0d8fdcaa
--- /dev/null
+++ b/arch/arm/cpu/efi-header-aarch64.S
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2017 Linaro, Ltd.
+ * Copyright (C) 2013, 2014 Red Hat, Inc.
+ */
+
+#include <linux/pe.h>
+#include <linux/sizes.h>
+#include <asm/memory.h>
+
+ .macro efi_signature_nop
+#ifdef CONFIG_EFI_STUB
+.L_head:
+ /*
+ * This ccmp instruction has no meaningful effect except that
+ * its opcode forms the magic "MZ" signature required by UEFI.
+ */
+ ccmp x18, #0, #0xd, pl
+#else
+ /*
+ * Bootloaders may inspect the opcode at the start of the kernel
+ * image to decide if the kernel is capable of booting via UEFI.
+ * So put an ordinary NOP here, not the "MZ.." pseudo-nop above.
+ */
+ nop
+#endif
+ .endm
+
+ .macro __EFI_PE_HEADER
+#ifdef CONFIG_EFI_STUB
+ .set .Lpe_header_offset, . - .L_head
+ .long PE_MAGIC
+ .short IMAGE_FILE_MACHINE_ARM64 // Machine
+ .short .Lsection_count // NumberOfSections
+ .long 0 // TimeDateStamp
+ .long 0 // PointerToSymbolTable
+ .long 0 // NumberOfSymbols
+ .short .Lsection_table - .Loptional_header // SizeOfOptionalHeader
+ .short IMAGE_FILE_DEBUG_STRIPPED | \
+ IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED // Characteristics
+
+.Loptional_header:
+ .short PE_OPT_MAGIC_PE32PLUS // PE32+ format
+ .byte 0x02 // MajorLinkerVersion
+ .byte 0x14 // MinorLinkerVersion
+ .long _sdata - .Lefi_header_end // SizeOfCode
+ .long __pecoff_data_size // SizeOfInitializedData
+ .long 0 // SizeOfUninitializedData
+ .long __efistub_efi_pe_entry - .L_head // AddressOfEntryPoint
+ .long .Lefi_header_end - .L_head // BaseOfCode
+
+ .quad 0 // ImageBase
+ .long PBL_SEGMENT_ALIGN // SectionAlignment
+ .long PECOFF_FILE_ALIGNMENT // FileAlignment
+ .short 0 // MajorOperatingSystemVersion
+ .short 0 // MinorOperatingSystemVersion
+ .short LINUX_EFISTUB_MAJOR_VERSION // MajorImageVersion
+ .short LINUX_EFISTUB_MINOR_VERSION // MinorImageVersion
+ .short 0 // MajorSubsystemVersion
+ .short 0 // MinorSubsystemVersion
+ .long 0 // Win32VersionValue
+
+ .long __image_end - .L_head // SizeOfImage
+
+ // Everything before the kernel image is considered part of the header
+ .long .Lefi_header_end - .L_head // SizeOfHeaders
+ .long 0 // CheckSum
+ .short IMAGE_SUBSYSTEM_EFI_APPLICATION // Subsystem
+ .short 0 // DllCharacteristics
+ .quad 0 // SizeOfStackReserve
+ .quad 0 // SizeOfStackCommit
+ .quad 0 // SizeOfHeapReserve
+ .quad 0 // SizeOfHeapCommit
+ .long 0 // LoaderFlags
+ .long (.Lsection_table - .) / 8 // NumberOfRvaAndSizes
+
+ .quad 0 // ExportTable
+ .quad 0 // ImportTable
+ .quad 0 // ResourceTable
+ .quad 0 // ExceptionTable
+ .quad 0 // CertificationTable
+ .quad 0 // BaseRelocationTable
+
+ // Section table
+.Lsection_table:
+ .ascii ".text\0\0\0"
+ .long _sdata - .Lefi_header_end // VirtualSize
+ .long .Lefi_header_end - .L_head // VirtualAddress
+ .long _sdata - .Lefi_header_end // SizeOfRawData
+ .long .Lefi_header_end - .L_head // PointerToRawData
+
+ .long 0 // PointerToRelocations
+ .long 0 // PointerToLineNumbers
+ .short 0 // NumberOfRelocations
+ .short 0 // NumberOfLineNumbers
+ .long IMAGE_SCN_CNT_CODE | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_EXECUTE // Characteristics
+
+ .ascii ".data\0\0\0"
+ .long __pecoff_data_size // VirtualSize
+ .long _sdata - .L_head // VirtualAddress
+ .long __pecoff_data_rawsize // SizeOfRawData
+ .long _sdata - .L_head // PointerToRawData
+
+ .long 0 // PointerToRelocations
+ .long 0 // PointerToLineNumbers
+ .short 0 // NumberOfRelocations
+ .short 0 // NumberOfLineNumbers
+ .long IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_WRITE // Characteristics
+
+ .set .Lsection_count, (. - .Lsection_table) / 40
+
+ .balign PBL_SEGMENT_ALIGN
+.Lefi_header_end:
+#else
+ .set .Lpe_header_offset, 0x0
+#endif
+ .endm
diff --git a/arch/arm/cpu/entry.c b/arch/arm/cpu/entry.c
index dc264c877117..cc08d0ff7e42 100644
--- a/arch/arm/cpu/entry.c
+++ b/arch/arm/cpu/entry.c
@@ -42,3 +42,6 @@ void NAKED __noreturn barebox_arm_entry(unsigned long membase,
__barebox_arm_entry(membase, memsize, boarddata,
arm_mem_stack_top(membase + memsize));
}
+
+void __noreturn barebox_pbl_entry(ulong, ulong, void *)
+ __alias(barebox_arm_entry);
diff --git a/arch/arm/cpu/interrupts_64.c b/arch/arm/cpu/interrupts_64.c
index b3e7da179756..6262ba8872db 100644
--- a/arch/arm/cpu/interrupts_64.c
+++ b/arch/arm/cpu/interrupts_64.c
@@ -11,6 +11,7 @@
#include <init.h>
#include <asm/system.h>
#include <asm/esr.h>
+#include <efi/efi-mode.h>
/* Avoid missing prototype warning, called from assembly */
void do_bad_sync (struct pt_regs *pt_regs);
@@ -204,6 +205,9 @@ static int aarch64_init_vectors(void)
{
unsigned int el;
+ if (efi_is_payload())
+ return 0;
+
el = current_el();
switch (el) {
case 3:
@@ -221,4 +225,4 @@ static int aarch64_init_vectors(void)
return 0;
}
-pure_initcall(aarch64_init_vectors);
+core_initcall(aarch64_init_vectors);
diff --git a/arch/arm/cpu/mmu-common.c b/arch/arm/cpu/mmu-common.c
index acd4a9d35413..aeaf6c269df6 100644
--- a/arch/arm/cpu/mmu-common.c
+++ b/arch/arm/cpu/mmu-common.c
@@ -13,6 +13,7 @@
#include <memory.h>
#include <zero_page.h>
#include "mmu-common.h"
+#include <efi/efi-mode.h>
void arch_sync_dma_for_cpu(void *vaddr, size_t size,
enum dma_data_direction dir)
@@ -67,6 +68,9 @@ void zero_page_faulting(void)
static int mmu_init(void)
{
+ if (efi_is_payload())
+ return 0;
+
if (list_empty(&memory_banks)) {
resource_size_t start;
int ret;
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index 9f4cdfe67fbf..0351dcb9278d 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -43,14 +43,18 @@ static bool blob_is_arm_boarddata(const void *blob)
return bd->magic == BAREBOX_ARM_BOARDDATA_MAGIC;
}
+const struct barebox_boarddata *barebox_get_boarddata(void)
+{
+ if (!barebox_boarddata || !blob_is_arm_boarddata(barebox_boarddata))
+ return NULL;
+
+ return barebox_boarddata;
+}
+
u32 barebox_arm_machine(void)
{
- if (barebox_boarddata && blob_is_arm_boarddata(barebox_boarddata)) {
- const struct barebox_arm_boarddata *bd = barebox_boarddata;
- return bd->machine;
- } else {
- return 0;
- }
+ const struct barebox_boarddata *bd = barebox_get_boarddata();
+ return bd ? bd->machine : 0;
}
void *barebox_arm_boot_dtb(void)
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index d7419cabe7ef..7c834f110111 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -2,6 +2,8 @@
#ifndef __ASM_PCI_H
#define __ASM_PCI_H
-#define pcibios_assign_all_busses() 1
+#include <efi/efi-mode.h>
+
+#define pcibios_assign_all_busses() (!efi_is_payload())
#endif
diff --git a/arch/arm/lib/pbl.lds.S b/arch/arm/lib/pbl.lds.S
index 95929d7558bc..ec7296f0fb34 100644
--- a/arch/arm/lib/pbl.lds.S
+++ b/arch/arm/lib/pbl.lds.S
@@ -3,6 +3,7 @@
#include <linux/sizes.h>
#include <asm/barebox.lds.h>
+#include <asm/memory.h>
#include <asm-generic/memory_layout.h>
#include <asm-generic/pointer.h>
#include <asm/memory.h>
@@ -80,7 +81,9 @@ SECTIONS
.barebox_imd : { BAREBOX_IMD }
+ . = ALIGN(PBL_SEGMENT_ALIGN);
_etext = .; /* End of text and rodata section */
+ _sdata = .;
. = ALIGN(4);
.data : { *(.data*) }
@@ -127,6 +130,16 @@ SECTIONS
}
__pblext_end = .;
+ PECOFF_EDATA_PADDING
+
+ __pecoff_data_rawsize = ABSOLUTE(. - _etext);
+
+ /* .bss is dwarfed by piggydata size, so we just handle .bss
+ * as normal PE data
+ */
+
+ __pecoff_data_size = ABSOLUTE(. - _etext);
+
.image_end : { KEEP(*(.__image_end)) }
pbl_image_size = . - BASE;
diff --git a/arch/arm/lib64/armlinux.c b/arch/arm/lib64/armlinux.c
index 40fea37f53a7..4628c8ab5693 100644
--- a/arch/arm/lib64/armlinux.c
+++ b/arch/arm/lib64/armlinux.c
@@ -5,6 +5,7 @@
#include <memory.h>
#include <init.h>
#include <bootm.h>
+#include <efi/efi-mode.h>
static int do_bootm_linux(struct image_data *data)
{
@@ -89,6 +90,9 @@ static struct image_handler aarch64_barebox_handler = {
static int aarch64_register_image_handler(void)
{
+ if (efi_is_payload())
+ return 0;
+
register_image_handler(&aarch64_linux_efi_handler);
register_image_handler(&aarch64_linux_handler);
register_image_handler(&aarch64_barebox_handler);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 8b00a674a688..5b4982455385 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -5,6 +5,7 @@ config X86
select HAS_KALLSYMS
select HAS_DMA
select GENERIC_FIND_NEXT_BIT
+ select HAVE_EFI_PAYLOAD
default y
config ARCH_TEXT_BASE
diff --git a/efi/Kconfig b/efi/Kconfig
index 971d58a7a9c0..35a57a3a42de 100644
--- a/efi/Kconfig
+++ b/efi/Kconfig
@@ -2,8 +2,12 @@
menu "EFI (Extensible Firmware Interface) Support"
-config EFI_PAYLOAD
+config HAVE_EFI_PAYLOAD
bool
+
+config EFI_PAYLOAD
+ bool "Build as EFI payload" if COMPILE_TEST
+ depends on HAVE_EFI_PAYLOAD
select EFI
select EFI_GUID
select EFI_DEVICEPATH
@@ -16,6 +20,13 @@ config EFI_PAYLOAD
config EFI
bool
+config HAVE_EFI_STUB
+ bool
+
+config EFI_STUB
+ def_bool EFI_PAYLOAD
+ depends on HAVE_EFI_STUB
+
config EFI_GUID
bool
help
diff --git a/efi/payload/Makefile b/efi/payload/Makefile
index 71305bee7006..a4a0332a8288 100644
--- a/efi/payload/Makefile
+++ b/efi/payload/Makefile
@@ -7,3 +7,5 @@ bbenv-y += env-efi
obj-$(CONFIG_CMD_IOMEM) += iomem.o
obj-pbl-$(CONFIG_EFI_PAYLOAD) += early-mem.o
obj-$(CONFIG_EFI_PAYLOAD) += entry-single.o
+pbl-$(CONFIG_EFI_STUB) += entry-multi.o
+obj-$(CONFIG_EFI_STUB) += boarddata.o
diff --git a/efi/payload/boarddata.c b/efi/payload/boarddata.c
new file mode 100644
index 000000000000..3260e31c7bf7
--- /dev/null
+++ b/efi/payload/boarddata.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "efi-boarddata: " fmt
+
+#ifdef CONFIG_DEBUG_INITCALLS
+#define DEBUG
+#endif
+
+#include <efi/efi-payload.h>
+#include <efi.h>
+#include <boarddata.h>
+#include <memory.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <debug_ll.h>
+#include <init.h>
+
+static int handle_efi_boarddata(void)
+{
+ const struct barebox_boarddata *bd = barebox_get_boarddata();
+ efi_status_t efiret;
+
+ if (!barebox_boarddata_is_machine(bd, BAREBOX_MACH_TYPE_EFI))
+ return 0;
+
+ barebox_add_memory_bank("ram0", mem_malloc_start(), mem_malloc_size());
+
+ efi_parent_image = bd->image;
+ efi_sys_table = bd->sys_table;
+ BS = efi_sys_table->boottime;
+ RT = efi_sys_table->runtime;
+
+ pr_debug("parent_image = %p, sys_table = %p\n",
+ efi_parent_image, efi_sys_table);
+
+ efiret = BS->open_protocol(efi_parent_image, &efi_loaded_image_protocol_guid,
+ (void **)&efi_loaded_image,
+ efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!EFI_ERROR(efiret))
+ BS->handle_protocol(efi_loaded_image->device_handle,
+ &efi_device_path_protocol_guid, (void **)&efi_device_path);
+
+ return 0;
+}
+pure_initcall(handle_efi_boarddata);
diff --git a/efi/payload/entry-multi.c b/efi/payload/entry-multi.c
new file mode 100644
index 000000000000..f929ab01ec7b
--- /dev/null
+++ b/efi/payload/entry-multi.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/kernel.h>
+#include <linux/linkage.h>
+#include <linux/sizes.h>
+#include <boarddata.h>
+#include <stdio.h>
+#include <efi.h>
+#include <asm/common.h>
+#include <efi/efi-util.h>
+#include <efi/efi-payload.h>
+#include <pbl.h>
+
+static struct barebox_boarddata boarddata = {
+ .magic = BAREBOX_BOARDDATA_MAGIC,
+ .machine = BAREBOX_MACH_TYPE_EFI,
+};
+
+asmlinkage void __efistub_efi_pe_entry(void *image, struct efi_system_table *sys_table);
+
+static void efi_putc(void *ctx, int ch)
+{
+ struct efi_system_table *sys_table = ctx;
+ wchar_t ws[2] = { ch, L'\0' };
+
+ sys_table->con_out->output_string(sys_table->con_out, ws);
+}
+
+void __efistub_efi_pe_entry(void *image, struct efi_system_table *sys_table)
+{
+ size_t memsize;
+ efi_physical_addr_t mem;
+
+#ifdef DEBUG
+ sys_table->con_out->output_string(sys_table->con_out, L"\nbarebox\n");
+#endif
+ pbl_set_putc(efi_putc, sys_table);
+
+ boarddata.image = image;
+ boarddata.sys_table = sys_table;
+
+ mem = efi_earlymem_alloc(sys_table, &memsize);
+
+ barebox_pbl_entry(mem, memsize, &boarddata);
+}
diff --git a/include/pbl.h b/include/pbl.h
index 44957f59784e..0633e340bef3 100644
--- a/include/pbl.h
+++ b/include/pbl.h
@@ -15,6 +15,7 @@
#ifndef __ASSEMBLY__
#include <linux/types.h>
+#include <linux/compiler.h>
extern unsigned long free_mem_ptr;
extern unsigned long free_mem_end_ptr;
@@ -36,4 +37,7 @@ int pbl_barebox_verify(const void *compressed_start, unsigned int len,
const void *hash, unsigned int hash_len);
#endif
+void __noreturn barebox_pbl_entry(ulong, ulong, void *);
+
+
#endif /* __PBL_H__ */
diff --git a/test/self/mmu.c b/test/self/mmu.c
index dbe5004550a8..60bc9b38e84a 100644
--- a/test/self/mmu.c
+++ b/test/self/mmu.c
@@ -9,6 +9,7 @@
#include <abort.h>
#include <zero_page.h>
#include <linux/sizes.h>
+#include <efi/efi-mode.h>
#include <memory.h>
#define TEST_BUFFER_SIZE SZ_1M
@@ -258,6 +259,12 @@ static void test_zero_page(void)
static void test_mmu(void)
{
+ if (efi_is_payload()) {
+ pr_info("MMU was not initialized by us\n");
+ skipped_tests += 23;
+ return;
+ }
+
test_zero_page();
test_remap();
}
--
2.39.2
More information about the barebox
mailing list