Files
u-boot/tools/amlimage.c
Robert Marko 6f42057c67 tools: amlimage: include <inttypes.h>
PRIuN, PRIxN, etc macros are defined in <inttypes.h>, without it being
included errors like:
tools/amlimage.c:124:38: error: expected ‘)’ before ‘PRIu8’
tools/amlimage.c:126:31: error: expected ‘)’ before ‘PRIu32’

Can be hit depending on the host compiler and HOSTCFLAGS.

Fixes: 18c1654567 ("tools: mkimage: Add Amlogic Boot Image type")
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Reviewed-by: Mark Kettenis <kettenis@openbsd.org>
Reviewed-by: Ferass El Hafidi <funderscore@postmarketos.org>
2026-01-19 13:08:19 -06:00

257 lines
7.1 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright Contributors to the U-Boot project.
#include "imagetool.h"
#include <inttypes.h>
#include <u-boot/sha256.h>
/*
* Image contain data in the following order:
* Nonce 16 byte
* Header 64 byte
* Digest 32 byte
* Padding align up to 4K
* Payload
*/
#define HEADER_MAGIC 0x4c4d4140 /* @AML */
#define HEADER_OFFSET 0x10 /* 16 */
#define HEADER_SIZE 0x40 /* 64 */
#define PAYLOAD_OFFSET 0x1000 /* 4096 */
struct amlimage_header {
uint32_t magic;
uint32_t total_size;
uint8_t header_size;
uint8_t root_key_index;
uint8_t version_major;
uint8_t version_minor;
uint32_t padding1;
uint32_t digest_type;
uint32_t digest_offset;
uint32_t digest_size;
uint32_t data_offset;
uint32_t key_type;
uint32_t key_offset;
uint32_t key_size;
uint32_t data_size;
uint32_t payload_type;
uint32_t payload_offset;
uint32_t payload_size;
uint32_t padding2;
} __packed;
struct amlimage_variant {
const char *name;
const struct amlimage_header hdr;
};
#define VARIANT(name, major, minor, size) \
{ name, { .magic = HEADER_MAGIC, .header_size = HEADER_SIZE, \
.version_major = major, .version_minor = minor, \
.payload_size = size, } }
static const struct amlimage_variant variants[] = {
VARIANT("gxbb", 1, 0, 0xb000),
VARIANT("gxl", 1, 1, 0xb000),
VARIANT("gxm", 1, 1, 0xb000),
VARIANT("axg", 1, 1, 0xb000),
VARIANT("g12a", 1, 1, 0xf000),
VARIANT("g12b", 1, 1, 0xf000),
VARIANT("sm1", 1, 1, 0xf000),
};
static const struct amlimage_variant *amlimage_get_variant(const char *name)
{
if (!name)
return NULL;
for (int i = 0; i < ARRAY_SIZE(variants); i++)
if (!strcmp(name, variants[i].name))
return &variants[i];
return NULL;
}
static int amlimage_check_params(struct image_tool_params *params)
{
const struct amlimage_variant *variant =
amlimage_get_variant(params->imagename);
int datafile_size;
if (params->lflag || params->iflag)
return EXIT_SUCCESS;
if (!variant) {
fprintf(stderr, "%s: unsupported image name: %s\n",
params->cmdname, params->imagename);
exit(EXIT_FAILURE);
}
datafile_size = imagetool_get_filesize(params, params->datafile);
if (datafile_size < 0) {
exit(EXIT_FAILURE);
} else if (datafile_size > variant->hdr.payload_size) {
fprintf(stderr, "%s: datafile is too large (%#x > %#x)\n",
params->cmdname, datafile_size,
variant->hdr.payload_size);
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
static int amlimage_verify_header(unsigned char *buf, int size,
struct image_tool_params *params)
{
const struct amlimage_header *hdr = (void *)buf + HEADER_OFFSET;
if (size >= HEADER_OFFSET + HEADER_SIZE + SHA256_SUM_LEN &&
hdr->magic == HEADER_MAGIC && hdr->header_size == HEADER_SIZE &&
hdr->version_major == 1 && hdr->version_minor <= 1)
return 0;
return -1;
}
static void amlimage_print_header(const void *buf,
struct image_tool_params *params)
{
const struct amlimage_header *hdr = buf + HEADER_OFFSET;
uint8_t digest[SHA256_SUM_LEN];
sha256_context ctx;
bool valid;
printf("Amlogic Boot Image %" PRIu8 ".%" PRIu8 "\n",
hdr->version_major, hdr->version_minor);
printf("Total size: %" PRIu32 "\n", hdr->total_size);
printf("Digest %" PRIu32 ": %" PRIu32 " @ 0x%" PRIx32 "\n",
hdr->digest_type, hdr->digest_size, hdr->digest_offset);
printf("Key %" PRIu32 ": %" PRIu32 " @ 0x%" PRIx32 "\n",
hdr->key_type, hdr->key_size, hdr->key_offset);
printf("Payload %" PRIu32 ": %" PRIu32 " @ 0x%" PRIx32 "\n",
hdr->payload_type, hdr->payload_size, hdr->payload_offset);
if (hdr->digest_type == 0) {
/* sha256 digest (normal boot) */
sha256_starts(&ctx);
/* Header and data is used as input for sha256 digest */
sha256_update(&ctx, (void *)hdr, hdr->header_size);
sha256_update(&ctx, (void *)hdr + hdr->data_offset, hdr->data_size);
sha256_finish(&ctx, digest);
valid = !memcmp((void *)hdr + hdr->digest_offset,
digest, SHA256_SUM_LEN);
printf("Data: %" PRIu32 " @ 0x%" PRIx32 " - %s\n",
hdr->data_size, hdr->data_offset, valid ? "OK" : "BAD");
} else {
/* RSA (secure boot) */
printf("Data: %" PRIu32 " @ 0x%" PRIx32 " - Secure Boot\n",
hdr->data_size, hdr->data_offset);
}
}
static void amlimage_set_header(void *buf, struct stat *sbuf, int ifd,
struct image_tool_params *params)
{
struct amlimage_header *hdr = buf + HEADER_OFFSET;
sha256_context ctx;
/* Use header size as initial size */
hdr->total_size = hdr->header_size;
/* Use sha256 digest (normal boot) */
hdr->digest_type = 0;
/* The sha256 digest is stored directly following the header */
hdr->digest_offset = hdr->total_size;
/* Unknown if this is used as block size instead of digest size */
hdr->digest_size = 512;
hdr->total_size += hdr->digest_size;
/* Use key as padding so that payload ends up 4K aligned in TZRAM */
hdr->key_type = 0;
hdr->key_offset = hdr->total_size;
hdr->key_size = PAYLOAD_OFFSET - HEADER_OFFSET - hdr->key_offset;
hdr->total_size += hdr->key_size;
/* With padding above payload will have a 0x1000 offset in TZRAM */
hdr->payload_type = 0;
hdr->payload_offset = hdr->total_size;
/* Payload size has already been copied from the variant header */
hdr->total_size += hdr->payload_size;
/* Set the data range to be used as input for sha256 digest */
hdr->data_offset = hdr->digest_offset + SHA256_SUM_LEN;
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);
sha256_update(&ctx, (void *)hdr + hdr->data_offset, hdr->data_size);
/* Write sha256 digest to the 32 bytes directly following the header */
sha256_finish(&ctx, (void *)hdr + hdr->digest_offset);
}
static int amlimage_extract_subimage(void *buf,
struct image_tool_params *params)
{
const struct amlimage_header *hdr = buf + HEADER_OFFSET;
/* Save payload as the subimage */
return imagetool_save_subimage(params->outfile,
(ulong)hdr + hdr->payload_offset,
hdr->payload_size);
}
static int amlimage_check_image_type(uint8_t type)
{
if (type == IH_TYPE_AMLIMAGE)
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
static int amlimage_vrec_header(struct image_tool_params *params,
struct image_type_params *tparams)
{
const struct amlimage_variant *variant =
amlimage_get_variant(params->imagename);
const struct amlimage_header *hdr = &variant->hdr;
/* Use payload offset as header size, datafile will be appended */
tparams->header_size = PAYLOAD_OFFSET;
tparams->hdr = calloc(1, tparams->header_size);
if (!tparams->hdr) {
fprintf(stderr, "%s: Can't alloc header: %s\n",
params->cmdname, strerror(errno));
exit(EXIT_FAILURE);
}
/* Start with a copy of the variant header */
memcpy(tparams->hdr + HEADER_OFFSET, hdr, hdr->header_size);
/* Pad up to payload size of the variant header */
return hdr->payload_size - params->file_size;
}
/*
* amlimage parameters
*/
U_BOOT_IMAGE_TYPE(
amlimage,
"Amlogic Boot Image",
0,
NULL,
amlimage_check_params,
amlimage_verify_header,
amlimage_print_header,
amlimage_set_header,
amlimage_extract_subimage,
amlimage_check_image_type,
NULL,
amlimage_vrec_header
);