Merge tag 'u-boot-amlogic-next-20251219' of https://source.denx.de/u-boot/custodians/u-boot-amlogic into next
- Add u-boot SPL support for GX SoCs - meson_gx_mmc: reduce maximum frequency - Add support for EFI capsule updates on all Amlogic boards
This commit is contained in:
@@ -110,6 +110,7 @@ ROCKCHIP_OBS = generated/lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
|
||||
|
||||
# common objs for dumpimage and mkimage
|
||||
dumpimage-mkimage-objs := aisimage.o \
|
||||
amlimage.o \
|
||||
atmelimage.o \
|
||||
$(FIT_OBJS-y) \
|
||||
$(FIT_SIG_OBJS-y) \
|
||||
|
||||
255
tools/amlimage.c
Normal file
255
tools/amlimage.c
Normal file
@@ -0,0 +1,255 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// Copyright Contributors to the U-Boot project.
|
||||
|
||||
#include "imagetool.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
|
||||
);
|
||||
Reference in New Issue
Block a user