1#!/bin/sh
2#
3# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
4#
5# SPDX-License-Identifier: GPL-2.0-only
6#
7
8set -eu
9
10PROGNAME=${0##*/}
11
12# We use the following exit status conventions:
13#   0: normal operation, successful, "true"
14#   1: expected failure, "false"
15#   2: usage error
16#   3: other error
17EXIT_STATUS=3
18
19# Emit diagnostic message.
20# @params: a set of strings comprising a human-intelligible message
21_print () {
22    echo "${PROGNAME:-(unknown program)}: $*"
23}
24
25# Emit error message to standard error.
26# @params: a set of strings comprising a human-intelligible message
27fail () {
28    _print "error: $*" >&2
29}
30
31# Report unrecoverable error and terminate script.
32# @params: a set of strings comprising a human-intelligible message
33#
34# Note: $EXIT_STATUS, if set in the invoking scope, determines the exit status
35# used by this function.
36die () {
37    _print "fatal error: $*" >&2
38    exit ${EXIT_STATUS:-3}
39}
40
41# Display a usage message.
42show_usage () {
43    cat <<EOF
44$PROGNAME: generate U-Boot payload for ARM platform
45
46Usage:
47    $PROGNAME OBJCOPY-TOOL ELF-FILE ARCHITECTURE OUTPUT-FILE
48
49$PROGNAME uses objcopy, readelf (both from GNU binutils), and mkimage
50(from the U-Boot tools) to extract the entry point (start symbol) of an
51ELF executable and wrap the object in a chain-loadable payload for use
52by the U-Boot boot loader.
53
54OBJCOPY-TOOL should be the path to a version of GNU objcopy appropriate
55for the (cross-)built ELF-FILE.  ELF-FILE should be an ELF executable
56object.  ARCHITECTURE must be either "arm" or "arm64".  The image is
57written to OUTPUT-FILE.
58EOF
59}
60
61# Clean up temporary file.  $TEMPFILE is defined before this function is called.
62cleanup () {
63    rm -f $TEMPFILE
64}
65
66# Output the start symbol from given ELF object.
67#
68# Note: This function is sensitive to the output format of "readelf".
69get_start_symbol() {
70    ELF_FILE=$1
71
72    if ! readelf -h "$ELF_FILE" > /dev/null
73    then
74        die "\"$ELF_FILE\" does not appear to be an ELF file"
75    fi
76
77    set -- $(readelf -s $ELF_FILE | grep -w _start)
78    echo $2
79}
80
81if [ $# -ne 4 ]
82then
83    fail "expected 4 arguments, got $#: \"$*\""
84    show_usage >&2
85    exit 2
86fi
87
88OBJCOPY=$1
89ELF_FILE=$2
90ARCHITECTURE=$3
91OUTPUT=$4
92
93# Validate arguments.  $ELF_FILE is validated by get_start_symbol().  We'll let
94# mkimage fail if $OUTPUT is not writable.
95
96if ! [ -x "$OBJCOPY" ]
97then
98    die "\"$OBJCOPY\" does not exist or is not executable"
99fi
100
101case "$ARCHITECTURE" in
102    (arm|arm64)
103        ;;
104    (*)
105        EXIT_STATUS=2
106        die "unrecognized (ARM) architecture \"$ARCHITECTURE\""
107        ;;
108esac
109
110# $ARCHITECTURE is now known to be a safe string and no longer requires
111# quotation.
112
113TEMPFILE=$(mktemp)
114trap cleanup HUP INT QUIT TERM EXIT
115
116# Note: Because we are using a temporary file, the appending redirection is
117# important!  Do not degenerate it to ">", which will unlink the destination
118# first and reintroduce the race that mktemp avoids.
119"$OBJCOPY" -O binary "$ELF_FILE" /dev/stdout >> $TEMPFILE
120START=$(get_start_symbol "$ELF_FILE")
121mkimage -A $ARCHITECTURE -O linux -T kernel -C none \
122    -a $START -e $START -d $TEMPFILE "$OUTPUT"
123
124exit 0
125