diff options
author | andrew <andrew@FreeBSD.org> | 2015-04-06 15:50:20 +0000 |
---|---|---|
committer | andrew <andrew@FreeBSD.org> | 2015-04-06 15:50:20 +0000 |
commit | 1b7f9d2b451da796fa328eaf44d7483ebd82c027 (patch) | |
tree | 6dea3e5f774b16e4cfd91d174934942ee4372c05 /sys/boot | |
parent | 42eded17aa6c8b6fa27c7f83e5326e6b006396dd (diff) | |
download | FreeBSD-src-1b7f9d2b451da796fa328eaf44d7483ebd82c027.zip FreeBSD-src-1b7f9d2b451da796fa328eaf44d7483ebd82c027.tar.gz |
Add support to the efi boot1 and loader for 32-bit ARM. This will be used
by the future qemu virt support.
Differential Revision: https://reviews.freebsd.org/D2238
Reviewed by: emaste
Diffstat (limited to 'sys/boot')
-rw-r--r-- | sys/boot/efi/Makefile | 2 | ||||
-rw-r--r-- | sys/boot/efi/boot1/Makefile | 16 | ||||
-rw-r--r-- | sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu (renamed from sys/boot/efi/boot1/fat.tmpl.bz2.uu) | 2 | ||||
-rw-r--r-- | sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu | 26 | ||||
-rwxr-xr-x | sys/boot/efi/boot1/generate-fat.sh | 14 | ||||
-rw-r--r-- | sys/boot/efi/include/arm/efibind.h | 165 | ||||
-rw-r--r-- | sys/boot/efi/loader/Makefile | 4 | ||||
-rw-r--r-- | sys/boot/efi/loader/arch/arm/Makefile.inc | 5 | ||||
-rw-r--r-- | sys/boot/efi/loader/arch/arm/exec.c | 107 | ||||
-rw-r--r-- | sys/boot/efi/loader/arch/arm/ldscript.arm | 86 | ||||
-rw-r--r-- | sys/boot/efi/loader/arch/arm/reloc.c | 83 | ||||
-rw-r--r-- | sys/boot/efi/loader/arch/arm/start.S | 190 | ||||
-rw-r--r-- | sys/boot/efi/loader/bootinfo.c | 34 | ||||
-rw-r--r-- | sys/boot/efi/loader/copy.c | 12 |
14 files changed, 734 insertions, 12 deletions
diff --git a/sys/boot/efi/Makefile b/sys/boot/efi/Makefile index d729733..e92e03e 100644 --- a/sys/boot/efi/Makefile +++ b/sys/boot/efi/Makefile @@ -10,7 +10,7 @@ SUBDIR+= fdt .endif .endif -.if ${MACHINE_CPUARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "arm" SUBDIR+= loader boot1 .endif diff --git a/sys/boot/efi/boot1/Makefile b/sys/boot/efi/boot1/Makefile index 4be85f4..72537eb 100644 --- a/sys/boot/efi/boot1/Makefile +++ b/sys/boot/efi/boot1/Makefile @@ -36,6 +36,14 @@ LDFLAGS= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared LDFLAGS+= -Wl,-znocombreloc .endif +.if ${MACHINE_CPUARCH} == "arm" +# +# Add libstand for the __aeabi_* functions used by the compiler +# +DPADD+= ${LIBSTAND} +LDADD+= -lstand +.endif + ${PROG}: ${LDSCRIPT} OBJCOPY?= objcopy @@ -45,6 +53,8 @@ OBJDUMP?= objdump EFI_TARGET= efi-app-x86_64 .elif ${MACHINE_CPUARCH} == "i386" EFI_TARGET= efi-app-ia32 +.else +EFI_TARGET= binary .endif boot1.efi: loader.sym @@ -52,7 +62,7 @@ boot1.efi: loader.sym ${OBJDUMP} -t ${.ALLSRC} | fgrep '*UND*'; \ exit 1; \ fi - ${OBJCOPY} -j .text -j .sdata -j .data \ + ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel.dyn \ -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} @@ -66,8 +76,8 @@ boot1.o: ${.CURDIR}/../../common/ufsread.c boot1.efifat: boot1.efi echo ${.OBJDIR} - uudecode ${.CURDIR}/fat.tmpl.bz2.uu - mv fat.tmpl.bz2 ${.TARGET}.bz2 + uudecode ${.CURDIR}/fat-${MACHINE_CPUARCH}.tmpl.bz2.uu + mv fat-${MACHINE_CPUARCH}.tmpl.bz2 ${.TARGET}.bz2 bzip2 -f -d ${.TARGET}.bz2 dd if=boot1.efi of=${.TARGET} seek=${BOOT1_OFFSET} conv=notrunc diff --git a/sys/boot/efi/boot1/fat.tmpl.bz2.uu b/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu index c9044ee..d8a44b7 100644 --- a/sys/boot/efi/boot1/fat.tmpl.bz2.uu +++ b/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu @@ -1,7 +1,7 @@ FAT template boot filesystem created by generate-fat.sh DO NOT EDIT $FreeBSD$ -begin 644 fat.tmpl.bz2 +begin 644 fat-amd64.tmpl.bz2 M0EIH.3%!629362AK*D(`&I+____[ZZKJZ_^N_ZO^Z_Z_OJ[L`4`!7I0$#&$" M0$!$3&(<P`(;J*C:0E0E#30&AH`T````9#0```9````#)ZF0:,-3U/409,`) M@`"8`C3",````$R:8F@P`C`````"24U,D>I-DTU,)ZAZ0VA-!M0T'J`>H#"9 diff --git a/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu b/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu new file mode 100644 index 0000000..15b59d8 --- /dev/null +++ b/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu @@ -0,0 +1,26 @@ +FAT template boot filesystem created by generate-fat.sh +DO NOT EDIT +$FreeBSD$ +begin 644 fat-arm.tmpl.bz2 +M0EIH.3%!629365NH-?4`&T!_____ZZ[J[_ZN_ZO^J_Z[OJ_^J^J[^KZNKNNJ +MZNKNZOJ^P`+\#$``0`&AD:,@TTTT-&C30#$R&FF1H:!B&)D&F@```-&AB::# +M1HP0-,AD`T8F(TTP2JII&?^I5/]4`@TTT-&(T8FAB:&@T:8F(Q!@!`9,1DR9 +M`-,$:,FC)B&FC"8"#3"#(-,0`&AD:,@TTTT-&C30#$R&FF1H:!B&)D&F@``` +M-&AB::#1HP0-,AD`T8F(TTP*HI)D\DFDVC0AIIH]3(:-``80>HTTR!IH::#$ +M-`Q`:`/2:::&)IDP"/0$T:>IFD]$R8---3HUK2<PNK%<6\J]BA",-*(A%:0B +M(B#G5%F8B$$(68C_:!`A#OL<HAB+JZ6UHRRU>*K9].C:!IWS-2UK9M<WC]W[ +M+]QW,9%V2,?<"ZEO9B("$,I.0ZFE66K/,<N6+8ITS$J3))F2I4HJ5*E2I74J +M:$J5*E2I4JE5*I*I-2I4J5.;84I4J5*E2I6ZU4Q*E2I4J5+X<SOK,65E965D +MT:($(0A"$(0A"$(0C>.3@8,&#!@P8(0A"$(0@0A"$(0[;_L-&C1HT:-&B+YP +M,&#!@P8,$"$(0A"-?NW$*YY:V9IQ,:B93+AX^A7B),5HN_4JV=2\Y,:-+W'Q +MKQKVU7KA+YR'.:*V#48N-"7<`%:TT4D`/;N;SZM9X,V(@!D'=P==+O)9*\H8 +MI8W<L9:.AU[N;G"QEHLZBWB/2B.SKCGRM):%ZK3-2U3ZV1;%MUZX:^?X_Y@N +MM=0SN1R7Z\&PN,I8VVWKMS$1-X41%"V)-;+V9:MI5;.+M*TMZ]K7HQ-ALY1\ +M4LG)\#5/I7#7-D_1<KUPE\OW)<YEW=.GMJ%$MUF)TE9N)8[M[6LIEXF@H6?S +MW%U89M5M+:LW6(\?7Z6I:U4F>IM*Q<2E)KFG;%M&U;INV]<)Q%^P'*<]T6R; +M^7`P.+I+N(HA%=#(^Q0WVV0]=$2=5)>-XWKW7!95E7$<5QW)<IS6"PF@7&+H +M&<ETI.`9F48V7/E&??ROG%<9FU^Y#E.8W+GL%]#L7+U=^CY91Q\+`K'-WPF4 +M.2S[EM@S38.8YKG.@P6_83I,-<G1DPY84N-)VMWK,/!;AIJ&3E%&7B`0A,`& +3'65I7J6`B^?^+N2*<*$@MU!KZ@`` +` +end diff --git a/sys/boot/efi/boot1/generate-fat.sh b/sys/boot/efi/boot1/generate-fat.sh index 2688da3..de42339 100755 --- a/sys/boot/efi/boot1/generate-fat.sh +++ b/sys/boot/efi/boot1/generate-fat.sh @@ -17,18 +17,20 @@ BOOT1_SIZE=128k # # Known filenames -# amd64: BOOTx64.efi -# arm64: BOOTaa64.efi +# amd64: BOOTx64.efi +# aarch64: BOOTaa64.efi +# arm: BOOTarm.efi # -if [ -z "$1" ]; then - echo "Usage: $0 filename" +if [ -z "$2" ]; then + echo "Usage: $0 arch boot-filename" exit 1 fi -FILENAME=$1 +ARCH=$1 +FILENAME=$2 # Generate 800K FAT image -OUTPUT_FILE=fat.tmpl +OUTPUT_FILE=fat-${ARCH}.tmpl dd if=/dev/zero of=$OUTPUT_FILE bs=512 count=$FAT_SIZE DEVICE=`mdconfig -a -f $OUTPUT_FILE` diff --git a/sys/boot/efi/include/arm/efibind.h b/sys/boot/efi/include/arm/efibind.h new file mode 100644 index 0000000..85537ad --- /dev/null +++ b/sys/boot/efi/include/arm/efibind.h @@ -0,0 +1,165 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiBind.h + +Abstract: + + Processor or Compiler specific defines and types for IA-32. + We are using the ANSI C 2000 _t type definitions for basic types. + This it technically a violation of the coding standard, but they + are used to make EfiTypes.h portable. Code other than EfiTypes.h + should never use any ANSI C 2000 _t integer types. + +--*/ + +#ifndef _EFI_BIND_H_ +#define _EFI_BIND_H_ + + +#define EFI_DRIVER_ENTRY_POINT(InitFunction) +#define EFI_APPLICATION_ENTRY_POINT EFI_DRIVER_ENTRY_POINT + + +// +// Make sure we are useing the correct packing rules per EFI specification +// +#ifndef __GNUC__ +#pragma pack() +#endif + + +#ifdef __FreeBSD__ +#include <sys/stdint.h> +#else +// +// Assume standard IA-32 alignment. +// BugBug: Need to check portability of long long +// +typedef unsigned long long uint64_t; +typedef long long int64_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned char uint8_t; +typedef signed char int8_t; +#endif + +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint32_t UINT32; +typedef int32_t INT32; +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; + +#undef VOID +#define VOID void + +// +// Native integer size in stdint.h +// +typedef uint32_t UINTN; +typedef int32_t INTN; + +#define EFIERR(a) (0x80000000 | a) +#define EFI_ERROR_MASK 0x80000000 +#define EFIERR_OEM(a) (0xc0000000 | a) + +// +// Processor specific defines +// +#define EFI_MAX_BIT 0x80000000 +#define MAX_2_BITS 0xC0000000 + +// +// Maximum legal IA-32 address +// +#define EFI_MAX_ADDRESS 0xFFFFFFFF + +// +// Bad pointer value to use in check builds. +// if you see this value you are using uninitialized or free'ed data +// +#define EFI_BAD_POINTER 0xAFAFAFAF +#define EFI_BAD_POINTER_AS_BYTE 0xAF + +#define EFI_DEADLOOP() { volatile UINTN __iii; __iii = 1; while (__iii); } + +// +// Inject a break point in the code to assist debugging for NT Emulation Environment +// For real hardware, just put in a halt loop. Don't do a while(1) because the +// compiler will optimize away the rest of the function following, so that you run out in +// the weeds if you skip over it with a debugger. +// +#define EFI_BREAKPOINT EFI_DEADLOOP() + + +// +// Memory Fence forces serialization, and is needed to support out of order +// memory transactions. The Memory Fence is mainly used to make sure IO +// transactions complete in a deterministic sequence, and to syncronize locks +// an other MP code. Currently no memory fencing is required. +// +#define MEMORY_FENCE() + +// +// Some compilers don't support the forward reference construct: +// typedef struct XXXXX. The forward reference is required for +// ANSI compatibility. +// +// The following macro provide a workaround for such cases. +// + + +#ifdef EFI_NO_INTERFACE_DECL + #define EFI_FORWARD_DECLARATION(x) +#else + #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x +#endif + + +// +// Some C compilers optimize the calling conventions to increase performance. +// EFIAPI is used to make all public APIs follow the standard C calling +// convention. +// +#define EFIAPI + + + +// +// For symbol name in GNU assembly code, an extra "_" is necessary +// +#if defined(__GNUC__) + /// + /// Private worker functions for ASM_PFX() + /// + #define _CONCATENATE(a, b) __CONCATENATE(a, b) + #define __CONCATENATE(a, b) a ## b + + /// + /// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix + /// on symbols in assembly language. + /// + #define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) + +#endif + +#define INTERFACE_DECL(x) struct x + +#endif diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile index 8cbbaf3..3f536c8 100644 --- a/sys/boot/efi/loader/Makefile +++ b/sys/boot/efi/loader/Makefile @@ -87,6 +87,8 @@ OBJDUMP?= objdump EFI_TARGET= efi-app-x86_64 .elif ${MACHINE_CPUARCH} == "i386" EFI_TARGET= efi-app-ia32 +.else +EFI_TARGET= binary .endif loader.efi: loader.sym @@ -94,7 +96,7 @@ loader.efi: loader.sym ${OBJDUMP} -t ${.ALLSRC} | fgrep '*UND*'; \ exit 1; \ fi - ${OBJCOPY} -j .text -j .sdata -j .data \ + ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel.dyn \ -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} diff --git a/sys/boot/efi/loader/arch/arm/Makefile.inc b/sys/boot/efi/loader/arch/arm/Makefile.inc new file mode 100644 index 0000000..853c957 --- /dev/null +++ b/sys/boot/efi/loader/arch/arm/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SRCS+= exec.c \ + start.S \ + reloc.c diff --git a/sys/boot/efi/loader/arch/arm/exec.c b/sys/boot/efi/loader/arch/arm/exec.c new file mode 100644 index 0000000..1cbbce5 --- /dev/null +++ b/sys/boot/efi/loader/arch/arm/exec.c @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 2001 Benno Rice <benno@FreeBSD.org> + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/linker.h> + +#include <machine/md_var.h> +#include <machine/metadata.h> +#include <machine/elf.h> + +#include <stand.h> + +#include <efi.h> +#include <efilib.h> + +#include "bootstrap.h" +#include "loader_efi.h" + +extern vm_offset_t md_load(char *, vm_offset_t *); + +int +__elfN(arm_load)(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + int r; + + r = __elfN(loadfile)(filename, dest, result); + if (r != 0) + return (r); + + return (0); +} + +int +__elfN(arm_exec)(struct preloaded_file *fp) +{ + struct file_metadata *fmp; + vm_offset_t modulep, kernend; + Elf_Ehdr *e; + int error; + void (*entry)(void *); + EFI_STATUS status; + + if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return (EFTYPE); + + e = (Elf_Ehdr *)&fmp->md_data; + + if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0) + return (error); + + entry = efi_translate(e->e_entry); + printf("Kernel entry at 0x%x...\n", (unsigned)entry); + printf("Kernel args: %s\n", fp->f_args); + printf("modulep: %#x\n", modulep); + printf("relocation_offset %llx\n", __elfN(relocation_offset)); + + status = BS->ExitBootServices(IH, efi_mapkey); + if (EFI_ERROR(status)) { + printf("%s: ExitBootServices() returned 0x%lx\n", __func__, + (long)status); + return (EINVAL); + } + + dev_cleanup(); + + (*entry)((void *)modulep); + panic("exec returned"); +} + +static struct file_format arm_elf = { + __elfN(arm_load), + __elfN(arm_exec) +}; + +struct file_format *file_formats[] = { + &arm_elf, + NULL +}; + diff --git a/sys/boot/efi/loader/arch/arm/ldscript.arm b/sys/boot/efi/loader/arch/arm/ldscript.arm new file mode 100644 index 0000000..0b747aa --- /dev/null +++ b/sys/boot/efi/loader/arch/arm/ldscript.arm @@ -0,0 +1,86 @@ +/* $FreeBSD$ */ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", + "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .peheader : { + *(.peheader) + } + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + . = ALIGN(4096); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + *(.rodata) + *(.rodata.*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .got1 : { *(.got1) } + .dynamic : { *(.dynamic) } + /* Put .ctors and .dtors next to the .got2 section, so that the pointers + get relocated with -mrelocatable. Also put in the .fixup pointers. + The current compiler no longer needs this, but keep it around for 2.7.2 */ + PROVIDE (_GOT2_START_ = .); + .got2 : { *(.got2) } + PROVIDE (__CTOR_LIST__ = .); + .ctors : { *(.ctors) } + PROVIDE (__CTOR_END__ = .); + PROVIDE (__DTOR_LIST__ = .); + .dtors : { *(.dtors) } + PROVIDE (__DTOR_END__ = .); + PROVIDE (_FIXUP_START_ = .); + .fixup : { *(.fixup) } + PROVIDE (_FIXUP_END_ = .); + PROVIDE (_GOT2_END_ = .); + PROVIDE (_GOT_START_ = .); + .got : { *(.got) } + .got.plt : { *(.got.plt) } + PROVIDE (_GOT_END_ = .); + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + __gp = .; + PROVIDE (__bss_start = .); + .sbss : + { + *(.sbss) + *(.scommon) + *(.dynsbss) + } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + PROVIDE (__bss_end = .); + .plt : { *(.plt) } + .dynamic : { *(.dynamic) } + .reloc : { *(.reloc) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + _edata = .; +} diff --git a/sys/boot/efi/loader/arch/arm/reloc.c b/sys/boot/efi/loader/arch/arm/reloc.c new file mode 100644 index 0000000..8b19f1b --- /dev/null +++ b/sys/boot/efi/loader/arch/arm/reloc.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo <rpaulo@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <elf.h> +#include <bootstrap.h> + +/* + * A simple relocator for ARM binaries. + */ +void +_reloc(unsigned long ImageBase, Elf32_Dyn *dynamic) +{ + unsigned long relsz, relent; + unsigned long *newaddr; + Elf32_Rel *rel; + Elf32_Dyn *dynp; + + /* + * Find the relocation address, its size and the relocation entry. + */ + relsz = 0; + relent = 0; + for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_REL: + rel = (Elf32_Rel *) ((unsigned long) dynp->d_un.d_ptr + + ImageBase); + break; + case DT_RELSZ: + relsz = dynp->d_un.d_val; + break; + case DT_RELENT: + relent = dynp->d_un.d_val; + break; + default: + break; + } + } + + /* + * Perform the actual relocation. + */ + for (; relsz > 0; relsz -= relent) { + switch (ELF32_R_TYPE(rel->r_info)) { + case R_ARM_RELATIVE: + /* Address relative to the base address. */ + newaddr = (unsigned long *)(ImageBase + rel->r_offset); + *newaddr += ImageBase; + break; + default: + /* XXX: do we need other relocations ? */ + break; + } + rel = (Elf32_Rel *) ((caddr_t) rel + relent); + } +} diff --git a/sys/boot/efi/loader/arch/arm/start.S b/sys/boot/efi/loader/arch/arm/start.S new file mode 100644 index 0000000..0bb709c --- /dev/null +++ b/sys/boot/efi/loader/arch/arm/start.S @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 2014, 2015 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <machine/asm.h> + +/* + * We need to be a PE32 file for EFI. On some architectures we can use + * objcopy to create the correct file, however on arm we need to do + * it ourselves. + */ + +#define IMAGE_FILE_MACHINE_ARM 0x01c2 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 + + .section .peheader +efi_start: + /* The MS-DOS Stub, only used to get the offset of the COFF header */ + .ascii "MZ" + .short 0 + .space 0x38 + .long pe_sig - efi_start + + /* The PE32 Signature. Needs to be 8-byte aligned */ + .align 3 +pe_sig: + .ascii "PE" + .short 0 +coff_head: + .short IMAGE_FILE_MACHINE_ARM /* ARM file */ + .short 2 /* 2 Sections */ + .long 0 /* Timestamp */ + .long 0 /* No symbol table */ + .long 0 /* No symbols */ + .short section_table - optional_header /* Optional header size */ + .short 0 /* Characteristics TODO: Fill in */ + +optional_header: + .short 0x010b /* PE32 (32-bit addressing) */ + .byte 0 /* Major linker version */ + .byte 0 /* Minor linker version */ + .long _edata - _end_header /* Code size */ + .long 0 /* No initialized data */ + .long 0 /* No uninitialized data */ + .long _start - efi_start /* Entry point */ + .long _end_header - efi_start /* Start of code */ + .long 0 /* Start of data */ + +optional_windows_header: + .long 0 /* Image base */ + .long 32 /* Section Alignment */ + .long 8 /* File alignment */ + .short 0 /* Major OS version */ + .short 0 /* Minor OS version */ + .short 0 /* Major image version */ + .short 0 /* Minor image version */ + .short 0 /* Major subsystem version */ + .short 0 /* Minor subsystem version */ + .long 0 /* Win32 version */ + .long _edata - efi_start /* Image size */ + .long _end_header - efi_start /* Header size */ + .long 0 /* Checksum */ + .short 0xa /* Subsystem (EFI app) */ + .short 0 /* DLL Characteristics */ + .long 0 /* Stack reserve */ + .long 0 /* Stack commit */ + .long 0 /* Heap reserve */ + .long 0 /* Heap commit */ + .long 0 /* Loader flags */ + .long 6 /* Number of RVAs */ + + /* RVAs: */ + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + +section_table: + /* We need a .reloc section for EFI */ + .ascii ".reloc" + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long 0 /* Virtual size */ + .long 0 /* Virtual address */ + .long 0 /* Size of raw data */ + .long 0 /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */ + + /* The contents of the loader */ + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long _edata - _end_header /* Virtual size */ + .long _end_header - efi_start /* Virtual address */ + .long _edata - _end_header /* Size of raw data */ + .long _end_header - efi_start /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \ + IMAGE_SCN_MEM_READ) /* Characteristics */ +_end_header: + + .text +_start: + /* Save the boot params to the stack */ + push {r0, r1} + + adr r0, .Lbase + ldr r1, [r0] + sub r5, r0, r1 + + ldr r0, .Limagebase + add r0, r0, r5 + ldr r1, .Ldynamic + add r1, r1, r5 + + bl _C_LABEL(_reloc) + + /* Zero the BSS, _reloc fixed the values for us */ + ldr r0, .Lbss + ldr r1, .Lbssend + mov r2, #0 + +1: cmp r0, r1 + bgt 2f + str r2, [r0], #4 + b 1b +2: + + pop {r0, r1} + bl _C_LABEL(efi_main) + +1: WFI + b 1b + +.Lbase: + .word . +.Limagebase: + .word ImageBase +.Ldynamic: + .word _DYNAMIC +.Lbss: + .word __bss_start +.Lbssend: + .word __bss_end + +.align 3 +stack: + .space 512 +stack_end: + diff --git a/sys/boot/efi/loader/bootinfo.c b/sys/boot/efi/loader/bootinfo.c index d6607cd..988bdf2 100644 --- a/sys/boot/efi/loader/bootinfo.c +++ b/sys/boot/efi/loader/bootinfo.c @@ -219,6 +219,9 @@ bi_copymodules(vm_offset_t addr) if (fp->f_args) MOD_ARGS(addr, fp->f_args, c); v = fp->f_addr; +#if defined(__arm__) + v -= __elfN(relocation_offset); +#endif MOD_ADDR(addr, v, c); v = fp->f_size; MOD_SIZE(addr, v, c); @@ -332,6 +335,21 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) vm_offset_t dtbp; int dtb_size; #endif +#if defined(__arm__) + vm_offset_t vaddr; + int i; + /* + * These metadata addreses must be converted for kernel after + * relocation. + */ + uint32_t mdt[] = { + MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, + MODINFOMD_ENVP, +#if defined(LOADER_FDT_SUPPORT) + MODINFOMD_DTBP +#endif + }; +#endif howto = bi_getboothowto(args); @@ -405,6 +423,22 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) md = file_findmetadata(kfp, MODINFOMD_KERNEND); bcopy(&kernend, md->md_data, sizeof kernend); +#if defined(__arm__) + *modulep -= __elfN(relocation_offset); + + /* Do relocation fixup on metadata of each module. */ + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + for (i = 0; i < sizeof mdt / sizeof mdt[0]; i++) { + md = file_findmetadata(xp, mdt[i]); + if (md) { + bcopy(md->md_data, &vaddr, sizeof vaddr); + vaddr -= __elfN(relocation_offset); + bcopy(&vaddr, md->md_data, sizeof vaddr); + } + } + } +#endif + /* Copy module list and metadata. */ (void)bi_copymodules(addr); diff --git a/sys/boot/efi/loader/copy.c b/sys/boot/efi/loader/copy.c index 1da3f43..406e945 100644 --- a/sys/boot/efi/loader/copy.c +++ b/sys/boot/efi/loader/copy.c @@ -61,9 +61,21 @@ efi_copy_init(void) } staging_end = staging + STAGE_PAGES * 4096; +#ifdef __arm__ + /* Round the kernel load address to a 2MiB value */ + staging = roundup2(staging, 2 * 1024 * 1024); +#endif + return (0); } +void * +efi_translate(vm_offset_t ptr) +{ + + return ((void *)(ptr + stage_offset)); +} + ssize_t efi_copyin(const void *src, vm_offset_t dest, const size_t len) { |