开云体育

ctrl + shift + ? for shortcuts
© 2025 开云体育

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


Jonas Karlman
 

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@...>
---
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,"",@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;
}
--
2.47.1


Simon Glass
 

Hi Jonas,

On Sat, 4 Jan 2025 at 10:59, Jonas Karlman <jonas@...> 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@...>
---
tools/amlimage-gxbb-relocate.c | 79 ++++++++++++++++++++++++++++++++++
tools/amlimage.c | 37 ++++++++++++++++
2 files changed, 116 insertions(+)
create mode 100644 tools/amlimage-gxbb-relocate.c
I sent [1] some years ago and would quite like to enable the odroid-c2
in my lab. Is that an older version of what you are supporting here?

I heard that there are people working on open source tools, but it has
been a few years and I'd be quite OK to just use vendor tools.

For your docs, could you put them in doc/ instead?

[..]

Regards,
Simon

[1]


Jonas Karlman
 

Hi Simon,

On 2025-01-04 20:31, Simon Glass wrote:
Hi Jonas,

On Sat, 4 Jan 2025 at 10:59, Jonas Karlman <jonas@...> 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@...>
---
tools/amlimage-gxbb-relocate.c | 79 ++++++++++++++++++++++++++++++++++
tools/amlimage.c | 37 ++++++++++++++++
2 files changed, 116 insertions(+)
create mode 100644 tools/amlimage-gxbb-relocate.c
I sent [1] some years ago and would quite like to enable the odroid-c2
in my lab. Is that an older version of what you are supporting here?
The amlimage type in this series is only for creating an image format
that the SoCs BootROM (BL1) can understand. This image type will most
likely only be useful together with Ferass El Hafidi's U-Boot SPL work
or for someone wanting to run bare metal code from SRAM on these SoCs.

Vendor bl2.bin blobs is based on TF-A, is already in correct image
format and expect next stage payload to be signed using a Amlogic FIP
format. For this you will still need to use vendor tools or open source
tools like meson-tools, gxlimg or meson64-tools.

The amlogic-boot-fip repo [2] has blobs, vendor tools and Makefiles to
combine the blobs with a U-Boot proper u-boot.bin to create a firmware
image that should boot for a wide range of boards.

[2]


I heard that there are people working on open source tools, but it has
been a few years and I'd be quite OK to just use vendor tools.
Open-source tools exist to replace the binary-only Amlogic tools:
- (GXBB, GXL & GXM only)
- (GXBB, GXL, GXM & AXG only)
- (developed for G12B, should work on G12A & SM1)

Would be nice if someone would combine those into a mkimage amlfip type
or similar (a different format than this amlimage format).


For your docs, could you put them in doc/ instead?
Not fully sure what you want me to put in doc/, please be specific. The
code comments and commit message should already document as much as
possible until there is upstream use of the GXBB eMMC header workaround.

At such time something like following could be documented:

Write image to SD-card or eMMC module:
dd if=u-boot-amlogic.bin of=/path/to/dev bs=512 seek=1 conv=fsync,notrunc

Write the eMMC header to eMMC module:
dd if=u-boot-gxbb-emmc.bin of=/path/to/dev bs=1 count=112 conv=fsync,notrunc

Until Ferass El Hafidi's U-Boot SPL work has made its way upstream such
commands and information would purely be speculative and will be easier
to document in a future series.

Regards,
Jonas


[..]

Regards,
Simon

[1]


 

Hi Jonas and Simon,

On Sat Jan 4, 2025 at 10:23 PM UTC, Jonas Karlman wrote:
Hi Simon,

On 2025-01-04 20:31, Simon Glass wrote:
Hi Jonas,

On Sat, 4 Jan 2025 at 10:59, Jonas Karlman <jonas@...> 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@...>
---
tools/amlimage-gxbb-relocate.c | 79 ++++++++++++++++++++++++++++++++++
tools/amlimage.c | 37 ++++++++++++++++
2 files changed, 116 insertions(+)
create mode 100644 tools/amlimage-gxbb-relocate.c
I sent [1] some years ago and would quite like to enable the odroid-c2
in my lab. Is that an older version of what you are supporting here?
The amlimage type in this series is only for creating an image format
that the SoCs BootROM (BL1) can understand. This image type will most
likely only be useful together with Ferass El Hafidi's U-Boot SPL work
or for someone wanting to run bare metal code from SRAM on these SoCs.
I'm happy to announce that U-Boot SPL can now boot on gxbb and gxl SoCs,
and I'll be sending some patches to upstream that work later on.


Vendor bl2.bin blobs is based on TF-A, is already in correct image
format and expect next stage payload to be signed using a Amlogic FIP
format. For this you will still need to use vendor tools or open source
tools like meson-tools, gxlimg or meson64-tools.

The amlogic-boot-fip repo [2] has blobs, vendor tools and Makefiles to
combine the blobs with a U-Boot proper u-boot.bin to create a firmware
image that should boot for a wide range of boards.

[2]


I heard that there are people working on open source tools, but it has
been a few years and I'd be quite OK to just use vendor tools.
Open-source tools exist to replace the binary-only Amlogic tools:
- (GXBB, GXL & GXM only)
- (GXBB, GXL, GXM & AXG only)
- (developed for G12B, should work on G12A & SM1)
gxlimg now also supports G12A/G12B, but it does not support GXBB at the
time of writing.


Would be nice if someone would combine those into a mkimage amlfip type
or similar (a different format than this amlimage format).


For your docs, could you put them in doc/ instead?
Not fully sure what you want me to put in doc/, please be specific. The
code comments and commit message should already document as much as
possible until there is upstream use of the GXBB eMMC header workaround.

At such time something like following could be documented:

Write image to SD-card or eMMC module:
dd if=u-boot-amlogic.bin of=/path/to/dev bs=512 seek=1 conv=fsync,notrunc

Write the eMMC header to eMMC module:
dd if=u-boot-gxbb-emmc.bin of=/path/to/dev bs=1 count=112 conv=fsync,notrunc

Until Ferass El Hafidi's U-Boot SPL work has made its way upstream such
commands and information would purely be speculative and will be easier
to document in a future series.
Yes, my tree has documentation on how to make use of images generated by
amlimage. I believe such documentation should be documented when there
actually is U-Boot SPL support as well.

Best regards.


Regards,
Jonas


[..]

Regards,
Simon

[1]


 

On 05/01/2025 11:24, Ferass El Hafidi wrote:
Hi Jonas and Simon,
On Sat Jan 4, 2025 at 10:23 PM UTC, Jonas Karlman wrote:
Hi Simon,

On 2025-01-04 20:31, Simon Glass wrote:
Hi Jonas,

On Sat, 4 Jan 2025 at 10:59, Jonas Karlman <jonas@...> 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@...>
---
tools/amlimage-gxbb-relocate.c | 79 ++++++++++++++++++++++++++++++++++
tools/amlimage.c | 37 ++++++++++++++++
2 files changed, 116 insertions(+)
create mode 100644 tools/amlimage-gxbb-relocate.c
I sent [1] some years ago and would quite like to enable the odroid-c2
in my lab. Is that an older version of what you are supporting here?
The amlimage type in this series is only for creating an image format
that the SoCs BootROM (BL1) can understand. This image type will most
likely only be useful together with Ferass El Hafidi's U-Boot SPL work
or for someone wanting to run bare metal code from SRAM on these SoCs.
I'm happy to announce that U-Boot SPL can now boot on gxbb and gxl SoCs,
and I'll be sending some patches to upstream that work later on.
\o/



Vendor bl2.bin blobs is based on TF-A, is already in correct image
format and expect next stage payload to be signed using a Amlogic FIP
format. For this you will still need to use vendor tools or open source
tools like meson-tools, gxlimg or meson64-tools.

The amlogic-boot-fip repo [2] has blobs, vendor tools and Makefiles to
combine the blobs with a U-Boot proper u-boot.bin to create a firmware
image that should boot for a wide range of boards.

[2]


I heard that there are people working on open source tools, but it has
been a few years and I'd be quite OK to just use vendor tools.
Open-source tools exist to replace the binary-only Amlogic tools:
- (GXBB, GXL & GXM only)
- (GXBB, GXL, GXM & AXG only)
- (developed for G12B, should work on G12A & SM1)
gxlimg now also supports G12A/G12B, but it does not support GXBB at the
time of writing.
Exact :-)

GXBB is radically different, it was heavily based on the TF-A FIP architecture,
then Amlogic switched to custom headers for GXL and followings.

I would instead support a full SPL boot with associated tooling in U-Boot
source an leave the legacy FIP stuff where it should be, out of tree.

Each board has basically a custom BL2 provided by Amlogic, with sometimes
some custom tools, so supporting this in U-Boot would be an endless pain.

Neil



Would be nice if someone would combine those into a mkimage amlfip type
or similar (a different format than this amlimage format).


For your docs, could you put them in doc/ instead?
Not fully sure what you want me to put in doc/, please be specific. The
code comments and commit message should already document as much as
possible until there is upstream use of the GXBB eMMC header workaround.

At such time something like following could be documented:

Write image to SD-card or eMMC module:
dd if=u-boot-amlogic.bin of=/path/to/dev bs=512 seek=1 conv=fsync,notrunc

Write the eMMC header to eMMC module:
dd if=u-boot-gxbb-emmc.bin of=/path/to/dev bs=1 count=112 conv=fsync,notrunc

Until Ferass El Hafidi's U-Boot SPL work has made its way upstream such
commands and information would purely be speculative and will be easier
to document in a future series.
Yes, my tree has documentation on how to make use of images generated by
amlimage. I believe such documentation should be documented when there
actually is U-Boot SPL support as well.
Best regards.


Regards,
Jonas


[..]

Regards,
Simon

[1]


 

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@...>
---
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,"",@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@...>


 

Hi,

On Fri Jan 3, 2025 at 9:58 PM UTC, Jonas Karlman via groups.io 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@...>
---
Acked-by: Ferass El Hafidi <funderscore@...>

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,"",@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;
}