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

Commit 81a0bc39 authored by Roy Franz's avatar Roy Franz Committed by ard
Browse files

ARM: add UEFI stub support



This patch adds EFI stub support for the ARM Linux kernel.

The EFI stub operates similarly to the x86 and arm64 stubs: it is a
shim between the EFI firmware and the normal zImage entry point, and
sets up the environment that the zImage is expecting. This includes
optionally loading the initrd and device tree from the system partition
based on the kernel command line.

Signed-off-by: default avatarRoy Franz <roy.franz@linaro.org>
Tested-by: default avatarRyan Harkin <ryan.harkin@linaro.org>
Reviewed-by: default avatarMatt Fleming <matt@codeblueprint.co.uk>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
parent da58fb65
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -2041,6 +2041,25 @@ config AUTO_ZRELADDR
	  0xf8000000. This assumes the zImage being placed in the first 128MB
	  from start of memory.

config EFI_STUB
	bool

config EFI
	bool "UEFI runtime support"
	depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR && !XIP_KERNEL
	select UCS2_STRING
	select EFI_PARAMS_FROM_FDT
	select EFI_STUB
	select EFI_ARMSTUB
	select EFI_RUNTIME_WRAPPERS
	---help---
	  This option provides support for runtime services provided
	  by UEFI firmware (such as non-volatile variables, realtime
	  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 for kernels that may run on systems that have
	  UEFI firmware.

endmenu

menu "CPU Power Management"
+3 −1
Original line number Diff line number Diff line
@@ -167,9 +167,11 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
	false; \
fi

efi-obj-$(CONFIG_EFI_STUB) := $(objtree)/drivers/firmware/efi/libstub/lib.a

$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
		$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
		$(bswapsdi2) FORCE
		$(bswapsdi2) $(efi-obj-y) FORCE
	@$(check_for_multiple_zreladdr)
	$(call if_changed,ld)
	@$(check_for_bad_syms)
+130 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013-2015 Linaro Ltd
 * Authors: Roy Franz <roy.franz@linaro.org>
 *          Ard Biesheuvel <ard.biesheuvel@linaro.org>
 *
 * 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.
 */

		.macro	__nop
#ifdef CONFIG_EFI_STUB
		@ This is almost but not quite a NOP, since it does clobber the
		@ condition flags. But it is the best we can do for EFI, since
		@ PE/COFF expects the magic string "MZ" at offset 0, while the
		@ ARM/Linux boot protocol expects an executable instruction
		@ there.
		.inst	'M' | ('Z' << 8) | (0x1310 << 16)   @ tstne r0, #0x4d000
#else
		mov	r0, r0
#endif
		.endm

		.macro	__EFI_HEADER
#ifdef CONFIG_EFI_STUB
		b	__efi_start

		.set	start_offset, __efi_start - start
		.org	start + 0x3c
		@
		@ The PE header can be anywhere in the file, but for
		@ simplicity we keep it together with the MSDOS header
		@ The offset to the PE/COFF header needs to be at offset
		@ 0x3C in the MSDOS header.
		@ The only 2 fields of the MSDOS header that are used are this
		@ PE/COFF offset, and the "MZ" bytes at offset 0x0.
		@
		.long	pe_header - start	@ Offset to the PE header.

pe_header:
		.ascii	"PE\0\0"

coff_header:
		.short	0x01c2			@ ARM or Thumb
		.short	2			@ nr_sections
		.long	0 			@ TimeDateStamp
		.long	0			@ PointerToSymbolTable
		.long	1			@ NumberOfSymbols
		.short	section_table - optional_header
						@ SizeOfOptionalHeader
		.short	0x306			@ Characteristics.
						@ IMAGE_FILE_32BIT_MACHINE |
						@ IMAGE_FILE_DEBUG_STRIPPED |
						@ IMAGE_FILE_EXECUTABLE_IMAGE |
						@ IMAGE_FILE_LINE_NUMS_STRIPPED

optional_header:
		.short	0x10b			@ PE32 format
		.byte	0x02			@ MajorLinkerVersion
		.byte	0x14			@ MinorLinkerVersion
		.long	_end - __efi_start	@ SizeOfCode
		.long	0			@ SizeOfInitializedData
		.long	0			@ SizeOfUninitializedData
		.long	efi_stub_entry - start	@ AddressOfEntryPoint
		.long	start_offset		@ BaseOfCode
		.long	0			@ data

extra_header_fields:
		.long	0			@ ImageBase
		.long	0x200			@ SectionAlignment
		.long	0x200			@ FileAlignment
		.short	0			@ MajorOperatingSystemVersion
		.short	0			@ MinorOperatingSystemVersion
		.short	0			@ MajorImageVersion
		.short	0			@ MinorImageVersion
		.short	0			@ MajorSubsystemVersion
		.short	0			@ MinorSubsystemVersion
		.long	0			@ Win32VersionValue

		.long	_end - start		@ SizeOfImage
		.long	start_offset		@ SizeOfHeaders
		.long	0			@ CheckSum
		.short	0xa			@ Subsystem (EFI application)
		.short	0			@ DllCharacteristics
		.long	0			@ SizeOfStackReserve
		.long	0			@ SizeOfStackCommit
		.long	0			@ SizeOfHeapReserve
		.long	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:
		@
		@ 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\0\0"
		.long	0			@ VirtualSize
		.long	0			@ VirtualAddress
		.long	0			@ SizeOfRawData
		.long	0			@ PointerToRawData
		.long	0			@ PointerToRelocations
		.long	0			@ PointerToLineNumbers
		.short	0			@ NumberOfRelocations
		.short	0			@ NumberOfLineNumbers
		.long	0x42100040		@ Characteristics

		.ascii	".text\0\0\0"
		.long	_end - __efi_start	@ VirtualSize
		.long	__efi_start		@ VirtualAddress
		.long	_edata - __efi_start	@ SizeOfRawData
		.long	__efi_start		@ PointerToRawData
		.long	0			@ PointerToRelocations
		.long	0			@ PointerToLineNumbers
		.short	0			@ NumberOfRelocations
		.short	0			@ NumberOfLineNumbers
		.long	0xe0500020		@ Characteristics

		.align	9
__efi_start:
#endif
		.endm
+52 −2
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@
#include <asm/assembler.h>
#include <asm/v7m.h>

#include "efi-header.S"

 AR_CLASS(	.arch	armv7-a	)
 M_CLASS(	.arch	armv7-m	)

@@ -126,7 +128,7 @@
start:
		.type	start,#function
		.rept	7
		mov	r0, r0
		__nop
		.endr
   ARM(		mov	r0, r0		)
   ARM(		b	1f		)
@@ -139,7 +141,8 @@ start:
		.word	0x04030201	@ endianness flag

 THUMB(		.thumb			)
1:
1:		__EFI_HEADER

 ARM_BE8(	setend	be		)	@ go BE8 if compiled for BE8
 AR_CLASS(	mrs	r9, cpsr	)
#ifdef CONFIG_ARM_VIRT_EXT
@@ -1353,6 +1356,53 @@ __enter_kernel:

reloc_code_end:

#ifdef CONFIG_EFI_STUB
		.align	2
_start:		.long	start - .

ENTRY(efi_stub_entry)
		@ allocate space on stack for passing current zImage address
		@ and for the EFI stub to return of new entry point of
		@ zImage, as EFI stub may copy the kernel. Pointer address
		@ is passed in r2. r0 and r1 are passed through from the
		@ EFI firmware to efi_entry
		adr	ip, _start
		ldr	r3, [ip]
		add	r3, r3, ip
		stmfd	sp!, {r3, lr}
		mov	r2, sp			@ pass zImage address in r2
		bl	efi_entry

		@ Check for error return from EFI stub. r0 has FDT address
		@ or error code.
		cmn	r0, #1
		beq	efi_load_fail

		@ Preserve return value of efi_entry() in r4
		mov	r4, r0
		bl	cache_clean_flush
		bl	cache_off

		@ Set parameters for booting zImage according to boot protocol
		@ put FDT address in r2, it was returned by efi_entry()
		@ r1 is the machine type, and r0 needs to be 0
		mov	r0, #0
		mov	r1, #0xFFFFFFFF
		mov	r2, r4

		@ Branch to (possibly) relocated zImage that is in [sp]
		ldr	lr, [sp]
		ldr	ip, =start_offset
		add	lr, lr, ip
		mov	pc, lr				@ no mode switch

efi_load_fail:
		@ Return EFI_LOAD_ERROR to EFI firmware on error.
		ldr	r0, =0x80000001
		ldmfd	sp!, {ip, pc}
ENDPROC(efi_stub_entry)
#endif

		.align
		.section ".stack", "aw", %nobits
.L_user_stack:	.space	4096
+7 −0
Original line number Diff line number Diff line
@@ -48,6 +48,13 @@ SECTIONS
    *(.rodata)
    *(.rodata.*)
  }
  .data : {
    /*
     * The EFI stub always executes from RAM, and runs strictly before the
     * decompressor, so we can make an exception for its r/w data, and keep it
     */
    *(.data.efistub)
  }
  .piggydata : {
    *(.piggydata)
  }
Loading