Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f70e084a authored by Mark Salter's avatar Mark Salter Committed by Joonwoo Park
Browse files

arm64: efi: add EFI stub



This patch adds PE/COFF header fields to the start of the kernel
Image so that it appears as an EFI application to UEFI firmware.
An EFI stub is included to allow direct booting of the kernel
Image.

Signed-off-by: default avatarMark Salter <msalter@redhat.com>
[Add support in PE/COFF header for signed images]
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarLeif Lindholm <leif.lindholm@linaro.org>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git


Git-commit: 3c7f255039a2ad6ee1e3890505caf0d029b22e29
Signed-off-by: default avatarJoonwoo Park <joonwoop@codeaurora.org>
parent cccb7991
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -505,8 +505,9 @@ config EFI
	help
	  This option provides support for runtime services provided
	  by UEFI firmware (such as non-volatile variables, realtime
          clock, and platform reset). This is only useful on systems
	  that have UEFI firmware.
          clock, and platform reset). A UEFI stub is also provided to
	  allow the kernel to be booted as an EFI application. This
	  is only useful on systems that have UEFI firmware.

endmenu

+3 −1
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@

CPPFLAGS_vmlinux.lds	:= -DTEXT_OFFSET=$(TEXT_OFFSET)
AFLAGS_head.o		:= -DTEXT_OFFSET=$(TEXT_OFFSET)
CFLAGS_efi-stub.o 	:= -DTEXT_OFFSET=$(TEXT_OFFSET) \
			   -I$(src)/../../../scripts/dtc/libfdt

CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_insn.o = -pg
@@ -29,7 +31,7 @@ arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
arm64-obj-$(CONFIG_KGDB)		+= kgdb.o
arm64-obj-$(CONFIG_EFI)			+= efi.o
arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o

obj-$(CONFIG_SWP_EMULATE)	+= swp_emulate.o

+109 −0
Original line number Diff line number Diff line
/*
 * EFI entry point.
 *
 * Copyright (C) 2013, 2014 Red Hat, Inc.
 * Author: Mark Salter <msalter@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */
#include <linux/linkage.h>
#include <linux/init.h>

#include <asm/assembler.h>

#define EFI_LOAD_ERROR 0x8000000000000001

	__INIT

	/*
	 * We arrive here from the EFI boot manager with:
	 *
	 *    * CPU in little-endian mode
	 *    * MMU on with identity-mapped RAM
	 *    * Icache and Dcache on
	 *
	 * We will most likely be running from some place other than where
	 * we want to be. The kernel image wants to be placed at TEXT_OFFSET
	 * from start of RAM.
	 */
ENTRY(efi_stub_entry)
	/*
	 * Create a stack frame to save FP/LR with extra space
	 * for image_addr variable passed to efi_entry().
	 */
	stp	x29, x30, [sp, #-32]!

	/*
	 * Call efi_entry to do the real work.
	 * x0 and x1 are already set up by firmware. Current runtime
	 * address of image is calculated and passed via *image_addr.
	 *
	 * unsigned long efi_entry(void *handle,
	 *                         efi_system_table_t *sys_table,
	 *                         unsigned long *image_addr) ;
	 */
	adrp	x8, _text
	add	x8, x8, #:lo12:_text
	add	x2, sp, 16
	str	x8, [x2]
	bl	efi_entry
	cmn	x0, #1
	b.eq	efi_load_fail

	/*
	 * efi_entry() will have relocated the kernel image if necessary
	 * and we return here with device tree address in x0 and the kernel
	 * entry point stored at *image_addr. Save those values in registers
	 * which are callee preserved.
	 */
	mov	x20, x0		// DTB address
	ldr	x0, [sp, #16]	// relocated _text address
	mov	x21, x0

	/*
	 * Flush dcache covering current runtime addresses
	 * of kernel text/data. Then flush all of icache.
	 */
	adrp	x1, _text
	add	x1, x1, #:lo12:_text
	adrp	x2, _edata
	add	x2, x2, #:lo12:_edata
	sub	x1, x2, x1

	bl	__flush_dcache_area
	ic	ialluis

	/* Turn off Dcache and MMU */
	mrs	x0, CurrentEL
	cmp	x0, #PSR_MODE_EL2t
	ccmp	x0, #PSR_MODE_EL2h, #0x4, ne
	b.ne	1f
	mrs	x0, sctlr_el2
	bic	x0, x0, #1 << 0	// clear SCTLR.M
	bic	x0, x0, #1 << 2	// clear SCTLR.C
	msr	sctlr_el2, x0
	isb
	b	2f
1:
	mrs	x0, sctlr_el1
	bic	x0, x0, #1 << 0	// clear SCTLR.M
	bic	x0, x0, #1 << 2	// clear SCTLR.C
	msr	sctlr_el1, x0
	isb
2:
	/* Jump to kernel entry point */
	mov	x0, x20
	mov	x1, xzr
	mov	x2, xzr
	mov	x3, xzr
	br	x21

efi_load_fail:
	mov	x0, #EFI_LOAD_ERROR
	ldp	x29, x30, [sp], #32
	ret

ENDPROC(efi_stub_entry)
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013, 2014 Linaro Ltd;  <roy.franz@linaro.org>
 *
 * This file implements the EFI boot stub for the arm64 kernel.
 * Adapted from ARM version by Mark Salter <msalter@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */
#include <linux/efi.h>
#include <linux/libfdt.h>
#include <asm/sections.h>
#include <generated/compile.h>
#include <generated/utsrelease.h>

/*
 * AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
 * start of kernel and may not cross a 2MiB boundary. We set alignment to
 * 2MiB so we know it won't cross a 2MiB boundary.
 */
#define EFI_FDT_ALIGN	SZ_2M   /* used by allocate_new_fdt_and_exit_boot() */
#define MAX_FDT_OFFSET	SZ_512M

#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)

static void efi_char16_printk(efi_system_table_t *sys_table_arg,
			      efi_char16_t *str);

static efi_status_t efi_open_volume(efi_system_table_t *sys_table,
				    void *__image, void **__fh);
static efi_status_t efi_file_close(void *handle);

static efi_status_t
efi_file_read(void *handle, unsigned long *size, void *addr);

static efi_status_t
efi_file_size(efi_system_table_t *sys_table, void *__fh,
	      efi_char16_t *filename_16, void **handle, u64 *file_sz);

/* Include shared EFI stub code */
#include "../../../drivers/firmware/efi/efi-stub-helper.c"
#include "../../../drivers/firmware/efi/fdt.c"
#include "../../../drivers/firmware/efi/arm-stub.c"


static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
					unsigned long *image_addr,
					unsigned long *image_size,
					unsigned long *reserve_addr,
					unsigned long *reserve_size,
					unsigned long dram_base,
					efi_loaded_image_t *image)
{
	efi_status_t status;
	unsigned long kernel_size, kernel_memsize = 0;

	/* Relocate the image, if required. */
	kernel_size = _edata - _text;
	if (*image_addr != (dram_base + TEXT_OFFSET)) {
		kernel_memsize = kernel_size + (_end - _edata);
		status = efi_relocate_kernel(sys_table, image_addr,
					     kernel_size, kernel_memsize,
					     dram_base + TEXT_OFFSET,
					     PAGE_SIZE);
		if (status != EFI_SUCCESS) {
			pr_efi_err(sys_table, "Failed to relocate kernel\n");
			return status;
		}
		if (*image_addr != (dram_base + TEXT_OFFSET)) {
			pr_efi_err(sys_table, "Failed to alloc kernel memory\n");
			efi_free(sys_table, kernel_memsize, *image_addr);
			return EFI_ERROR;
		}
		*image_size = kernel_memsize;
	}


	return EFI_SUCCESS;
}
+112 −0
Original line number Diff line number Diff line
@@ -108,8 +108,18 @@
	/*
	 * DO NOT MODIFY. Image header expected by Linux boot-loaders.
	 */
#ifdef CONFIG_EFI
efi_head:
	/*
	 * This add instruction has no meaningful effect except that
	 * its opcode forms the magic "MZ" signature required by UEFI.
	 */
	add	x13, x18, #0x16
	b	stext
#else
	b	stext				// branch to kernel start, magic
	.long	0				// reserved
#endif
	.quad	TEXT_OFFSET			// Image load offset from start of RAM
	.quad	0				// reserved
	.quad	0				// reserved
@@ -120,7 +130,109 @@
	.byte	0x52
	.byte	0x4d
	.byte	0x64
#ifdef CONFIG_EFI
	.long	pe_header - efi_head		// Offset to the PE header.
#else
	.word	0				// reserved
#endif

#ifdef CONFIG_EFI
	.align 3
pe_header:
	.ascii	"PE"
	.short 	0
coff_header:
	.short	0xaa64				// AArch64
	.short	2				// nr_sections
	.long	0 				// TimeDateStamp
	.long	0				// PointerToSymbolTable
	.long	1				// NumberOfSymbols
	.short	section_table - optional_header	// SizeOfOptionalHeader
	.short	0x206				// Characteristics.
						// IMAGE_FILE_DEBUG_STRIPPED |
						// IMAGE_FILE_EXECUTABLE_IMAGE |
						// IMAGE_FILE_LINE_NUMS_STRIPPED
optional_header:
	.short	0x20b				// PE32+ format
	.byte	0x02				// MajorLinkerVersion
	.byte	0x14				// MinorLinkerVersion
	.long	_edata - stext			// SizeOfCode
	.long	0				// SizeOfInitializedData
	.long	0				// SizeOfUninitializedData
	.long	efi_stub_entry - efi_head	// AddressOfEntryPoint
	.long	stext - efi_head		// BaseOfCode

extra_header_fields:
	.quad	0				// ImageBase
	.long	0x20				// SectionAlignment
	.long	0x8				// FileAlignment
	.short	0				// MajorOperatingSystemVersion
	.short	0				// MinorOperatingSystemVersion
	.short	0				// MajorImageVersion
	.short	0				// MinorImageVersion
	.short	0				// MajorSubsystemVersion
	.short	0				// MinorSubsystemVersion
	.long	0				// Win32VersionValue

	.long	_edata - efi_head		// SizeOfImage

	// Everything before the kernel image is considered part of the header
	.long	stext - efi_head		// SizeOfHeaders
	.long	0				// CheckSum
	.short	0xa				// Subsystem (EFI application)
	.short	0				// DllCharacteristics
	.quad	0				// SizeOfStackReserve
	.quad	0				// SizeOfStackCommit
	.quad	0				// SizeOfHeapReserve
	.quad	0				// SizeOfHeapCommit
	.long	0				// LoaderFlags
	.long	0x6				// NumberOfRvaAndSizes

	.quad	0				// ExportTable
	.quad	0				// ImportTable
	.quad	0				// ResourceTable
	.quad	0				// ExceptionTable
	.quad	0				// CertificationTable
	.quad	0				// BaseRelocationTable

	// Section table
section_table:

	/*
	 * The EFI application loader requires a relocation section
	 * because EFI applications must be relocatable.  This is a
	 * dummy section as far as we are concerned.
	 */
	.ascii	".reloc"
	.byte	0
	.byte	0			// end of 0 padding of section name
	.long	0
	.long	0
	.long	0			// SizeOfRawData
	.long	0			// PointerToRawData
	.long	0			// PointerToRelocations
	.long	0			// PointerToLineNumbers
	.short	0			// NumberOfRelocations
	.short	0			// NumberOfLineNumbers
	.long	0x42100040		// Characteristics (section flags)


	.ascii	".text"
	.byte	0
	.byte	0
	.byte	0        		// end of 0 padding of section name
	.long	_edata - stext		// VirtualSize
	.long	stext - efi_head	// VirtualAddress
	.long	_edata - stext		// SizeOfRawData
	.long	stext - efi_head	// PointerToRawData

	.long	0		// PointerToRelocations (0 for executables)
	.long	0		// PointerToLineNumbers (0 for executables)
	.short	0		// NumberOfRelocations  (0 for executables)
	.short	0		// NumberOfLineNumbers  (0 for executables)
	.long	0xe0500020	// Characteristics (section flags)
	.align 5
#endif

ENTRY(stext)
	mov	x21, x0				// x21=FDT
Loading