[PATCH 2/2] tools: amlimage: Add support for GXBB eMMC header

Neil Armstrong neil.armstrong at linaro.org
Mon Jan 6 10:27:59 CET 2025


On 03/01/2025 22:58, Jonas Karlman wrote:
> GXBB BL1 only tries to read boot image from sector 0 on eMMC and sector
> 1 on SD-card. GXL and newer read boot image from sector 1 on both eMMC
> and SD-card.
> 
> Vendor BL2 have solved the issue with different offsets by considering
> where BL2 was loaded from to adjust the offset where BL3 is read from.
> 
> This provide a different solution to create a boot image that can be
> booted from both eMMC and SD-card and where the offset for reading next
> stage loader can be shared for both boot options.
> 
> Inject code, that relocate the payload located at 0x1200 offset in TZRAM
> to the expected offset of 0x1000, into the padding area at offset 0x200
> when a normal GXBB boot image is created. A special GXBB eMMC header can
> then be created that have the payload offset point to this relocate
> code, BL1 will jump to this relocate code when booted from eMMC instead
> of the normal payload start. One effect of this is that the payload size
> limit must be reduced by 512 bytes on GXBB.
> 
> Example of how to use it:
>    # Create a normal boot image
>    tools/mkimage -T amlimage -n gxbb -d u-boot-spl.bin bl2.bin
> 
>    # Create a boot image with a special eMMC header
>    tools/mkimage -T amlimage -n emmc -d bl2.bin bl2-emmc.bin
> 
>    # Write normal boot image to sector 1 of eMMC/SD-card
>    dd if=bl2.bin of=/path/to/dev bs=512 seek=1
> 
>    # Write eMMC header, 112 bytes, to start of eMMC
>    dd if=bl2-emmc.bin of=/path/to/dev bs=1 count=112
> 
> Or with binman using something like:
>    binman {
> 	multiple-images;
> 
> 	u-boot-gxbb-sd {
> 		filename = "u-boot-gxbb-sd.bin";
> 		pad-byte = <0xff>;
> 
> 		mkimage {
> 			filename = "bl2.bin";
> 			args = "-n", "gxbb", "-T", "amlimage";
> 
> 			u-boot-spl {
> 			};
> 		};
> 	};
> 
> 	u-boot-gxbb-emmc {
> 		filename = "u-boot-gxbb-emmc.bin";
> 		pad-byte = <0xff>;
> 
> 		mkimage {
> 			filename = "bl2-emmc.bin";
> 			args = "-n", "emmc", "-T", "amlimage";
> 
> 			blob-ext {
> 				filename = "bl2.bin";
> 			}
> 		};
> 	};
>    };
> 
> Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
> ---
>   tools/amlimage-gxbb-relocate.c | 79 ++++++++++++++++++++++++++++++++++
>   tools/amlimage.c               | 37 ++++++++++++++++
>   2 files changed, 116 insertions(+)
>   create mode 100644 tools/amlimage-gxbb-relocate.c
> 
> diff --git a/tools/amlimage-gxbb-relocate.c b/tools/amlimage-gxbb-relocate.c
> new file mode 100644
> index 000000000000..3503805c460e
> --- /dev/null
> +++ b/tools/amlimage-gxbb-relocate.c
> @@ -0,0 +1,79 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +// Copyright Contributors to the U-Boot project.
> +
> +/*
> + * The following commands can be used to reproduce the gxbb_relocate
> + * byte array in amlimage.c
> + *
> + * Start U-Boot CI docker container from U-Boot source code root folder:
> + *  docker run --rm -v $(pwd):/build -u uboot -it docker.io/trini/u-boot-gitlab-ci-runner:jammy-20240911.1-08Dec2024
> + *
> + * Run the following commands inside the docker container:
> + *  export PATH=/opt/gcc-13.2.0-nolibc/aarch64-linux/bin:$PATH
> + *  cd /build/tools
> + *
> + * Generate assembly code for the c code in this file:
> + *  aarch64-linux-gcc -nostdlib -ffreestanding -Os -S -o amlimage-gxbb-relocate.S amlimage-gxbb-relocate.c
> + *
> + * Manually remove 'mov x16, x2' and replace 'x16' with 'x2' on the last line.
> + *
> + * Compile assembly code and extract the AArch64 binary code:
> + *  aarch64-linux-as -o amlimage-gxbb-relocate.o amlimage-gxbb-relocate.S
> + *  aarch64-linux-objcopy -O binary -j .text amlimage-gxbb-relocate.o amlimage-gxbb-relocate.bin
> + *
> + * Print binary code as a byte array that can be copied into amlimage.c
> + *  hexdump -ve '1/1 "0x%.2x, "' amlimage-gxbb-relocate.bin | fold -w 72 && echo
> + *
> + * Remember to update assembly code below when byte array is updated.
> + */
> +
> +#include <stdint.h>
> +
> +#define TZRAM_BASE		0xd9000000
> +#define PAYLOAD_OFFSET		0x200
> +#define BL2_OFFSET		0x1000
> +#define BL2_BASE		(void *)(TZRAM_BASE + BL2_OFFSET)
> +#define BL2_SIZE		0xb000
> +
> +void _start(uint64_t x0, uint64_t x1)
> +{
> +	void (*bl2)(uint64_t, uint64_t) = BL2_BASE;
> +	uint64_t i, *dst = BL2_BASE, *src = BL2_BASE + PAYLOAD_OFFSET;
> +
> +	/* memmove payload from 0x1200 to 0x1000 offset in TZRAM */
> +	for (i = 0; i < BL2_SIZE / sizeof(*src); i++)
> +		*(dst + i) = *(src + i);
> +
> +	/* goto entry point with x0 and x1 reg intact */
> +	bl2(x0, x1);
> +}
> +
> +/*
> +	.arch armv8-a
> +	.file	"amlimage-gxbb-relocate.c"
> +	.text
> +	.align	2
> +	.global	_start
> +	.type	_start, %function
> +_start:
> +.LFB0:
> +	.cfi_startproc
> +	mov	x2, 4608
> +	movk	x2, 0xd900, lsl 16
> +	add	x3, x2, 45056
> +.L2:
> +	sub	x4, x2, #32768
> +	add	x2, x2, 8
> +	ldr	x5, [x2, -8]
> +	str	x5, [x4, 32256]
> +	cmp	x2, x3
> +	bne	.L2
> +	mov	x2, 4096
> +	movk	x2, 0xd900, lsl 16
> +	br	x2
> +	.cfi_endproc
> +.LFE0:
> +	.size	_start, .-_start
> +	.ident	"GCC: (GNU) 13.2.0"
> +	.section	.note.GNU-stack,"", at progbits
> +*/
> diff --git a/tools/amlimage.c b/tools/amlimage.c
> index 9af795602e69..43be1636ed11 100644
> --- a/tools/amlimage.c
> +++ b/tools/amlimage.c
> @@ -51,6 +51,7 @@ struct amlimage_variant {
>   		  .payload_size = size, } }
>   
>   static const struct amlimage_variant variants[] = {
> +	VARIANT("emmc", 1, 0, 0xb000 + PAYLOAD_OFFSET),
>   	VARIANT("gxbb", 1, 0, 0xb000),
>   	VARIANT("gxl",  1, 1, 0xb000),
>   	VARIANT("gxm",  1, 1, 0xb000),
> @@ -176,6 +177,17 @@ static void amlimage_set_header(void *buf, struct stat *sbuf, int ifd,
>   	hdr->data_offset = hdr->digest_offset + SHA256_SUM_LEN;
>   	hdr->data_size = hdr->total_size - hdr->data_offset;
>   
> +	/* Adjust offset and size in GXBB eMMC header */
> +	if (!strcmp("emmc", params->imagename)) {
> +		hdr->total_size -= PAYLOAD_OFFSET;
> +		/* Use offset to relocate code relative to eMMC header */
> +		hdr->payload_offset = 0x400 - HEADER_OFFSET;
> +		hdr->payload_size = hdr->total_size - hdr->payload_offset;
> +		/* Use 0x200 offset to exclude MBR from the data range */
> +		hdr->data_offset = 0x200 - HEADER_OFFSET;
> +		hdr->data_size = hdr->total_size - hdr->data_offset;
> +	}
> +
>   	sha256_starts(&ctx);
>   	/* Header and data is used as input for sha256 digest */
>   	sha256_update(&ctx, (void *)hdr, hdr->header_size);
> @@ -203,6 +215,22 @@ static int amlimage_check_image_type(uint8_t type)
>   	return EXIT_FAILURE;
>   }
>   
> +/*
> + * AArch64 binary code to relocate payload when booting from eMMC on GXBB.
> + *
> + * Payload is relocated from offset 0x1200 to 0x1000 in TZRAM, similar to:
> + * memmove(0xd9001000, 0xd9001200, 0xb000)
> + * goto 0xd9001000
> + *
> + * See amlimage-gxbb-relocate.c on how to reproduce the following byte array.
> + */
> +static const uint8_t gxbb_relocate[] = {
> +	0x02, 0x40, 0x82, 0xd2, 0x02, 0x20, 0xbb, 0xf2, 0x43, 0x2c, 0x40, 0x91,
> +	0x44, 0x20, 0x40, 0xd1, 0x42, 0x20, 0x00, 0x91, 0x45, 0x80, 0x5f, 0xf8,
> +	0x85, 0x00, 0x3f, 0xf9, 0x5f, 0x00, 0x03, 0xeb, 0x61, 0xff, 0xff, 0x54,
> +	0x02, 0x00, 0x82, 0xd2, 0x02, 0x20, 0xbb, 0xf2, 0x40, 0x00, 0x1f, 0xd6,
> +};
> +
>   static int amlimage_vrec_header(struct image_tool_params *params,
>   				struct image_type_params *tparams)
>   {
> @@ -213,6 +241,10 @@ static int amlimage_vrec_header(struct image_tool_params *params,
>   	/* Use payload offset as header size, datafile will be appended */
>   	tparams->header_size = PAYLOAD_OFFSET;
>   
> +	/* Only prepend 512 bytes for GXBB eMMC header */
> +	if (!strcmp("emmc", variant->name))
> +		tparams->header_size = 0x200;
> +
>   	tparams->hdr = calloc(1, tparams->header_size);
>   	if (!tparams->hdr) {
>   		fprintf(stderr, "%s: Can't alloc header: %s\n",
> @@ -223,6 +255,11 @@ static int amlimage_vrec_header(struct image_tool_params *params,
>   	/* Start with a copy of the variant header */
>   	memcpy(tparams->hdr + HEADER_OFFSET, hdr, hdr->header_size);
>   
> +	/* Insert relocate code to move payload from 0x1200 to 0x1000 on GXBB */
> +	if (!strcmp("gxbb", variant->name))
> +		memcpy(tparams->hdr + 0x200,
> +		       gxbb_relocate, sizeof(gxbb_relocate));
> +
>   	/* Pad up to payload size of the variant header */
>   	return hdr->payload_size - params->file_size;
>   }

Awesome work !

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>


More information about the U-Boot mailing list