Merge branch 'patch/mkimage-toc1' into allwinner

This commit is contained in:
Samuel Holland 2022-10-31 22:44:10 -05:00
commit 66908e01f5
5 changed files with 347 additions and 0 deletions

View File

@ -180,6 +180,7 @@ static const table_entry_t uimage_type[] = {
{ IH_TYPE_COPRO, "copro", "Coprocessor Image"},
{ IH_TYPE_SUNXI_EGON, "sunxi_egon", "Allwinner eGON Boot Image" },
{ IH_TYPE_SUNXI_TOC0, "sunxi_toc0", "Allwinner TOC0 Boot Image" },
{ IH_TYPE_SUNXI_TOC1, "sunxi_toc1", "Allwinner TOC1 Boot Image" },
{ -1, "", "", },
};

View File

@ -229,6 +229,7 @@ enum image_type_t {
IH_TYPE_COPRO, /* Coprocessor Image for remoteproc*/
IH_TYPE_SUNXI_EGON, /* Allwinner eGON Boot Image */
IH_TYPE_SUNXI_TOC0, /* Allwinner TOC0 Boot Image */
IH_TYPE_SUNXI_TOC1, /* Allwinner TOC1 Boot Image */
IH_TYPE_COUNT, /* Number of image types */
};

View File

@ -116,4 +116,30 @@ struct __packed toc0_item_info {
#define TOC0_ITEM_INFO_NAME_KEY 0x00010303
#define TOC0_ITEM_INFO_END "IIE;"
struct __packed toc1_main_info {
uint8_t name[16];
__le32 magic;
__le32 checksum;
__le32 serial;
__le32 status;
__le32 num_items;
__le32 length;
__le32 major_version;
__le32 minor_version;
__le32 reserved[3];
uint8_t end[4];
};
struct __packed toc1_item_info {
uint8_t name[64];
__le32 offset;
__le32 length;
__le32 encryption;
__le32 type;
__le32 load_addr;
__le32 index;
__le32 reserved[69];
uint8_t end[4];
};
#endif

View File

@ -130,6 +130,7 @@ dumpimage-mkimage-objs := aisimage.o \
$(ROCKCHIP_OBS) \
socfpgaimage.o \
sunxi_egon.o \
sunxi_toc1.o \
lib/crc16-ccitt.o \
lib/hash-checksum.o \
lib/sha1.o \

318
tools/sunxi_toc1.c Normal file
View File

@ -0,0 +1,318 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2018 Arm Ltd.
* (C) Copyright 2020-2021 Samuel Holland <samuel@sholland.org>
*/
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <image.h>
#include <sunxi_image.h>
#include "imagetool.h"
#include "mkimage.h"
#define SECTOR_SIZE 512
struct item_desc {
const char *name;
const char *file;
unsigned long addr;
long length;
};
static uint32_t toc1_header_length(uint32_t num_items)
{
return ALIGN(sizeof(struct toc1_main_info) +
sizeof(struct toc1_item_info) * num_items, SECTOR_SIZE);
}
static int toc1_parse_cfg(const char *file, struct item_desc **desc,
uint32_t *main_length, uint32_t *num_items)
{
struct item_desc *descs = NULL;
int ret = EXIT_FAILURE;
FILE *cfg, *fp = NULL;
uint32_t ndescs = 0;
char *line = NULL;
size_t len = 0;
*desc = NULL;
*main_length = 0;
*num_items = 0;
cfg = fopen(file, "r");
if (!cfg)
return ret;
while (getline(&line, &len, cfg) > 0) {
char *end, *s;
if (line[0] == '[') {
s = line + 1;
end = strchr(s, ']');
if (!end || end[1] != '\n')
goto err;
end[0] = '\0';
ndescs++;
descs = reallocarray(descs, ndescs, sizeof(*descs));
if (!descs)
goto err;
descs[ndescs - 1].name = strdup(s);
} else if (line[0] != '#' && line[0] != '\n') {
s = strchr(line, '=');
if (!s)
goto err;
while ((++s)[0] == ' ')
;
end = strchr(s, '\n');
if (!end)
goto err;
end[0] = '\0';
if (!strncmp(line, "file", strlen("file"))) {
fp = fopen(s, "rb");
if (!fp)
goto err;
if (fseek(fp, 0, SEEK_END) < 0)
goto err;
descs[ndescs - 1].file = strdup(s);
descs[ndescs - 1].length = ftell(fp);
*main_length += ALIGN(descs[ndescs - 1].length,
SECTOR_SIZE);
fclose(fp);
fp = NULL;
} else if (!strncmp(line, "addr", strlen("addr"))) {
descs[ndescs - 1].addr = strtoul(s, NULL, 0);
} else {
goto err;
}
}
}
*desc = descs;
*main_length += toc1_header_length(ndescs);
*num_items = ndescs;
ret = EXIT_SUCCESS;
err:
if (fp)
fclose(fp);
if (ret)
free(descs);
free(line);
fclose(cfg);
return ret;
}
static int toc1_create(uint8_t *buf, uint32_t len,
const struct item_desc *desc, uint32_t num_items)
{
struct toc1_main_info *main = (void *)buf;
struct toc1_item_info *item = (void *)(main + 1);
uint32_t item_offset, item_length;
uint32_t *buf32 = (void *)buf;
int ret = EXIT_FAILURE;
uint32_t checksum = 0;
FILE *fp = NULL;
int i;
/* Create the main TOC1 header. */
main->magic = cpu_to_le32(TOC0_MAIN_INFO_MAGIC);
main->checksum = cpu_to_le32(BROM_STAMP_VALUE);
main->num_items = cpu_to_le32(num_items);
memcpy(main->end, TOC0_MAIN_INFO_END, sizeof(main->end));
item_offset = 0;
item_length = toc1_header_length(num_items);
for (i = 0; i < num_items; ++i, ++item, ++desc) {
item_offset = item_offset + item_length;
item_length = desc->length;
/* Create the item header. */
memcpy(item->name, desc->name,
strnlen(desc->name, sizeof(item->name)));
item->offset = cpu_to_le32(item_offset);
item->length = cpu_to_le32(item_length);
item->load_addr = cpu_to_le32(desc->addr);
memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
/* Read in the data. */
fp = fopen(desc->file, "rb");
if (!fp)
goto err;
if (!fread(buf + item_offset, item_length, 1, fp))
goto err;
fclose(fp);
fp = NULL;
/* Pad the sectors with 0xff to be flash-friendly. */
item_offset = item_offset + item_length;
item_length = ALIGN(item_offset, SECTOR_SIZE) - item_offset;
memset(buf + item_offset, 0xff, item_length);
}
/* Fill in the total padded file length. */
item_offset = item_offset + item_length;
main->length = cpu_to_le32(item_offset);
/* Verify enough space was provided when creating the image. */
assert(len >= item_offset);
/* Calculate the checksum. Yes, it's that simple. */
for (i = 0; i < item_offset / 4; ++i)
checksum += le32_to_cpu(buf32[i]);
main->checksum = cpu_to_le32(checksum);
ret = EXIT_SUCCESS;
err:
if (fp)
fclose(fp);
return ret;
}
static int toc1_verify(const uint8_t *buf, uint32_t len)
{
const struct toc1_main_info *main = (void *)buf;
const struct toc1_item_info *item = (void *)(main + 1);
uint32_t checksum = BROM_STAMP_VALUE;
uint32_t main_length, num_items;
uint32_t *buf32 = (void *)buf;
int ret = EXIT_FAILURE;
int i;
num_items = le32_to_cpu(main->num_items);
main_length = le32_to_cpu(main->length);
if (len < main_length || main_length < toc1_header_length(num_items))
goto err;
/* Verify the main header. */
if (le32_to_cpu(main->magic) != TOC0_MAIN_INFO_MAGIC)
goto err;
/* Verify the checksum without modifying the buffer. */
for (i = 0; i < main_length / 4; ++i)
checksum += le32_to_cpu(buf32[i]);
if (checksum != 2 * le32_to_cpu(main->checksum))
goto err;
/* The length must be at least 512 byte aligned. */
if (main_length % SECTOR_SIZE)
goto err;
if (memcmp(main->end, TOC0_MAIN_INFO_END, sizeof(main->end)))
goto err;
/* Verify each item header. */
for (i = 0; i < num_items; ++i, ++item)
if (memcmp(item->end, TOC0_ITEM_INFO_END, sizeof(item->end)))
goto err;
ret = EXIT_SUCCESS;
err:
return ret;
}
static int toc1_check_params(struct image_tool_params *params)
{
if (!params->dflag)
return -EINVAL;
return 0;
}
static int toc1_verify_header(unsigned char *buf, int image_size,
struct image_tool_params *params)
{
return toc1_verify(buf, image_size);
}
static void toc1_print_header(const void *buf)
{
const struct toc1_main_info *main = buf;
const struct toc1_item_info *item = (void *)(main + 1);
uint32_t head_length, main_length, num_items;
uint32_t item_offset, item_length, item_addr;
int i;
num_items = le32_to_cpu(main->num_items);
head_length = sizeof(*main) + num_items * sizeof(*item);
main_length = le32_to_cpu(main->length);
printf("Allwinner TOC1 Image\n"
"Size: %d bytes\n"
"Contents: %d items\n"
" 00000000:%08x Headers\n",
main_length, num_items, head_length);
for (i = 0; i < num_items; ++i, ++item) {
item_offset = le32_to_cpu(item->offset);
item_length = le32_to_cpu(item->length);
item_addr = le32_to_cpu(item->load_addr);
printf(" %08x:%08x => %08x %s\n",
item_offset, item_length, item_addr, item->name);
}
}
static void toc1_set_header(void *buf, struct stat *sbuf, int ifd,
struct image_tool_params *params)
{
/* Image is already written below. */
}
static int toc1_check_image_type(uint8_t type)
{
return type == IH_TYPE_SUNXI_TOC1 ? 0 : 1;
}
static int toc1_vrec_header(struct image_tool_params *params,
struct image_type_params *tparams)
{
uint32_t main_length, num_items;
struct item_desc *desc;
int ret;
/* This "header" contains the entire image. */
params->skipcpy = 1;
ret = toc1_parse_cfg(params->datafile, &desc, &main_length, &num_items);
if (ret)
exit(ret);
tparams->header_size = main_length;
tparams->hdr = calloc(tparams->header_size, 1);
if (!tparams->hdr)
exit(ret);
ret = toc1_create(tparams->hdr, tparams->header_size, desc, num_items);
if (ret)
exit(ret);
return 0;
}
U_BOOT_IMAGE_TYPE(
sunxi_toc1,
"Allwinner TOC1 Boot Image support",
0,
NULL,
toc1_check_params,
toc1_verify_header,
toc1_print_header,
toc1_set_header,
NULL,
toc1_check_image_type,
NULL,
toc1_vrec_header
);