[PATCH] Makefile: perform sanity checks on payload during build
Samuel Holland
samuel.holland at sifive.com
Fri Oct 4 17:49:54 PDT 2024
Hi Tim,
On 2024-10-04 8:14 AM, Tim Hutt wrote:
> To make mistakes more obvious and debugging easier we can check that the payload is not an ELF file, and that the first byte is possibly the start of a valid instruction.
>
> I would have preferred to not do this check in Bash but I didn't want to introduce any additional dependencies, and there isn't a proper language already in use.
>
> I also made it an `#error` to not define `FW_PAYLOAD_PATH` since the build system will always do that. If the user doesn't specify one a default file is used.
You need a Signed-off-by. Please also wrap the commit message to 72 characters.
> ---
> firmware/external_deps.mk | 3 ++-
> firmware/fw_payload.S | 6 ++----
> scripts/check-payload.sh | 43 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 47 insertions(+), 5 deletions(-)
> create mode 100755 scripts/check-payload.sh
>
> diff --git a/firmware/external_deps.mk b/firmware/external_deps.mk
> index 6264005..d4c480c 100644
> --- a/firmware/external_deps.mk
> +++ b/firmware/external_deps.mk
> @@ -10,5 +10,6 @@
> $(platform_build_dir)/firmware/fw_dynamic.o: $(FW_FDT_PATH)
> $(platform_build_dir)/firmware/fw_jump.o: $(FW_FDT_PATH)
> $(platform_build_dir)/firmware/fw_payload.o: $(FW_FDT_PATH)
> -
> + scripts/check-payload.sh $(FW_PAYLOAD_PATH_FINAL)
> + $(call compile_as,$@,$<)
I would suggest leaving the recipe for fw_payload.o alone, and using a separate,
possibly phony, target for this check. It's surprising to have the recipe for
assembling this one file defined in a separate file.
> $(platform_build_dir)/firmware/fw_payload.o: $(FW_PAYLOAD_PATH_FINAL)
> diff --git a/firmware/fw_payload.S b/firmware/fw_payload.S
> index 3c8433e..0b0f342 100644
> --- a/firmware/fw_payload.S
> +++ b/firmware/fw_payload.S
> @@ -94,8 +94,6 @@ fw_options:
> .globl payload_bin
> payload_bin:
> #ifndef FW_PAYLOAD_PATH
> - wfi
> - j payload_bin
> -#else
> - .incbin FW_PAYLOAD_PATH
> +#error FW_PAYLOAD_PATH should always be set by the build system
> #endif
> + .incbin FW_PAYLOAD_PATH
> diff --git a/scripts/check-payload.sh b/scripts/check-payload.sh
> new file mode 100755
> index 0000000..5752497
> --- /dev/null
> +++ b/scripts/check-payload.sh
> @@ -0,0 +1,43 @@
> +#!/usr/bin/env bash
With the below changes this script can be POSIX-compatible and use /bin/sh.
> +
> +# Simple script to try and detect invalid payloads. The payload should be a flat
> +# image and the first bytes should be valid instructions - OpenSBI will jump
> +# to the start of the file. It shouldn't be an ELF file.
> +#
> +# Bash is a terrible language for this purpose but we can make it work.
> +
> +if [ -z "$1" ]; then
> + echo "Usage: $0 <file>"
> + exit 1
> +fi
> +
> +# Check the payload is not an ELF file.
> +readelf -h "$1" >/dev/null 2>&1 && {
This should get $READELF from Makefile; see how that file sets OBJCOPY.
> + echo "Error: The payload is an ELF file; it should be a flat executable instead."
> + exit 1
> +}
> +
> +# Check the first bytes are a valid RISC-V instruction. Since we don't know
> +# what is valid we can only do limited checks but this will check that it is at
> +# least a 16 or 32-bit instruction. Larger instructions are currently unused.
> +first_byte="$(head -c 1 "$1")"
> +LC_ALL=C printf -v first_byte_dec %d \'$first_byte
This can be done portably with od(1):
first_byte=$(od -An -N1 -td1 "$1")
> +
> +# for byte in range(256):
> +# if not ((byte & 0b11) != 0b11 or (byte & 0b11100) != 0b11100):
> +# print(byte)
> +[ \
> + "$first_byte_dec" == 31 -o \
> + "$first_byte_dec" == 63 -o \
> + "$first_byte_dec" == 95 -o \
> + "$first_byte_dec" == 127 -o \
> + "$first_byte_dec" == 159 -o \
> + "$first_byte_dec" == 191 -o \
> + "$first_byte_dec" == 223 -o \
> + "$first_byte_dec" == 255 \
You can use arithmetic expansion here (which is also POSIX):
[ $((first_byte & 31)) -eq 31 ]
> +] && {
> + echo "Error: The payload's first byte is not a 16- or 32-bit RISC-V instruction. The payload should be a flat executable."
> + exit 1
> +}
> +
> +exit 0
No need for an explicit "exit 0" at the end.
Regards,
Samuel
More information about the opensbi
mailing list