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>
257 lines
7.1 KiB
C
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
|
|
);
|