Commit f5fbc7c8 authored by Marek Vasut's avatar Marek Vasut
Browse files

mxssb: Rework SB image header generation



Rework the mechanism behind generating the SB image header generation.
This also puts down the groundwork for further rework of the mechanism
for contructing the image.

The basic idea here is to parse the whole image, construct a tree-like
structure in RAM that represents the image and operate with it throughout
the whole life-cycle of the program. Right now, this only serves the
purpose of filling the SB image header, but this will change in subsequent
patches.

NOTE that this patch introduces a lot of FIXMEs, since this is a huge
rework of the whole tool. This patch revealed a lot of weak spots too.
Signed-off-by: Marek Vasut's avatarMarek Vasut <marex@denx.de>
parent 2f76748a
......@@ -31,7 +31,39 @@ enum {
CPU_MX28,
};
/*
* IMAGE
* |-SECTION
* | |-CMD
* | |-CMD
* | `-CMD
* |-SECTION
* | |-CMD
* : :
*/
struct sb_cmd_ctx {
struct sb_cmd_ctx *cmd;
uint8_t *data;
uint32_t length;
struct sb_command payload;
};
struct sb_section_ctx {
unsigned int boot:1;
struct sb_section_ctx *sect;
struct sb_cmd_ctx *cmd;
struct sb_sections_header payload;
};
struct sb_image_ctx {
int target_cpu;
int verbose_boot;
struct sb_section_ctx *sect;
EVP_CIPHER_CTX cipher_ctx;
EVP_MD_CTX md_ctx;
......@@ -116,41 +148,6 @@ static struct sb_source_entry mx28_boot_list[] = {
}
};
static const struct sb_boot_image_header sb_header_template = {
.signature1 = { 'S', 'T', 'M', 'P' },
.major_version = SB_VERSION_MAJOR,
.minor_version = SB_VERSION_MINOR,
.image_blocks =
( /*
* The amount of blocks below is not final, this is
* only the amount of bytes until the section #0.
*/
/* The main SB header. */
sizeof(struct sb_boot_image_header) +
/* The section #0 header. */
sizeof(struct sb_sections_header) +
/* The key dictionary. */
sizeof(struct sb_key_dictionary_key)
) / SB_BLOCK_SIZE,
.first_boot_section_id = 0,
.key_count = 1,
.header_blocks = sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE,
.section_count = 1,
.section_header_size = sizeof(struct sb_sections_header) / SB_BLOCK_SIZE,
.signature2 = { 's', 'g', 't', 'l' },
.product_version = {
.major = __cpu_to_be16(0x999),
.minor = __cpu_to_be16(0x999),
.revision = __cpu_to_be16(0x999),
},
.component_version = {
.major = __cpu_to_be16(0x999),
.minor = __cpu_to_be16(0x999),
.revision = __cpu_to_be16(0x999),
},
.drive_tag = 0, /* Must be 0x0 for MX233. */
};
/* Blank image key. */
static uint8_t image_key[16] = {0};
......@@ -297,40 +294,12 @@ static time_t sb_get_timestamp(void)
return seconds_to_now - seconds_to_2000;
}
static void sb_complete_sb_header(struct sb_boot_image_header *sb_header)
{
EVP_MD_CTX md_ctx;
EVP_MD_CTX_init(&md_ctx);
EVP_DigestInit(&md_ctx, EVP_sha1());
sb_header->image_blocks +=
sb_get_sections_block_size() + /* Size of the section #0. */
2; /* Size of the image's SHA1 digest. */
sb_header->flags = verbose_boot ? SB_IMAGE_FLAG_VERBOSE : 0,
sb_header->key_dictionary_block =
sb_header->header_blocks +
sb_header->section_header_size * sb_header->section_count;
sb_header->first_boot_tag_block =
sb_header->key_dictionary_block +
sizeof(struct sb_key_dictionary_key) / SB_BLOCK_SIZE;
sb_header->timestamp_us = sb_get_timestamp() * 1000000;
EVP_DigestUpdate(&md_ctx, sb_header->signature1,
sizeof(struct sb_boot_image_header) -
sizeof(sb_header->digest));
EVP_DigestFinal(&md_ctx, sb_header->digest, NULL);
}
static void sb_encrypt_sb_header(
EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *md_ctx,
struct sb_boot_image_header *sb_header)
{
uint8_t *sb_header_ptr = (uint8_t *)sb_header;
/* Fill in the missing parts of the SB image header. */
sb_complete_sb_header(sb_header);
/* Encrypt the header, compute the digest. */
sb_aes_encrypt(cipher_ctx, sb_header_ptr, NULL, sizeof(*sb_header));
EVP_DigestUpdate(md_ctx, sb_header_ptr, sizeof(*sb_header));
......@@ -471,7 +440,7 @@ static int sb_create_image(struct sb_image_ctx *ctx, uint8_t **image)
size_t image_offset = 0;
/* Save offset of the TAG tag. */
uint32_t tag_offset = sb_header->image_blocks;
uint32_t tag_offset = sb_header->first_boot_tag_block;
/* Start image-wide crypto. */
EVP_MD_CTX_init(&ctx->md_ctx);
......@@ -659,6 +628,239 @@ static int set_cpu(const char *pn, const char *cpu)
return -1;
}
static int sb_parse_cmds(struct sb_section_ctx *sctx)
{
struct sb_cmd_ctx *cctx, *prev = NULL, *head = NULL;
struct sb_source_entry *src = sb_get_boot_list(target_cpu);
unsigned int insts = sb_get_boot_list_size(target_cpu);
int ret;
struct sb_command *cmd;
while (insts--) {
cctx = calloc(1, sizeof(*cctx));
if (!cctx)
return -ENOMEM;
if (!head)
head = cctx;
ret = sb_tag_to_command(src, &cmd);
if (ret)
goto err;
/* FIXME -- remove this useless allocation later. */
memcpy(&cctx->payload, cmd, sizeof(*cmd));
free(cmd);
/* FIXME -- this is where the file loading will happen. */
if (src->tag == ROM_LOAD_CMD) {
cctx->data = src->payload;
cctx->length = src->length;
}
if (prev)
prev->cmd = cctx;
prev = cctx;
src++;
}
sctx->cmd = head;
return 0;
err:
while (head) {
cctx = head;
head = head->cmd;
free(cctx);
}
return -EINVAL;
}
static int sb_parse_sections(struct sb_image_ctx *ictx)
{
/* This function is a stub, we support only one section so far. */
struct sb_section_ctx *sctx;
int ret;
sctx = calloc(1, sizeof(*sctx));
if (!sctx)
return -ENOMEM;
ret = sb_parse_cmds(sctx);
if (ret) {
free(sctx);
return ret;
}
sctx->boot = 1;
ictx->sect = sctx;
return 0;
}
static int sb_prefill_image_header(struct sb_image_ctx *ictx)
{
struct sb_boot_image_header *hdr = &ictx->payload;
/* Fill signatures */
memcpy(hdr->signature1, "STMP", 4);
memcpy(hdr->signature2, "sgtl", 4);
/* SB Image version 1.1 */
hdr->major_version = SB_VERSION_MAJOR;
hdr->minor_version = SB_VERSION_MINOR;
/* Boot image major version */
hdr->product_version.major = __cpu_to_be16(0x999);
hdr->product_version.minor = __cpu_to_be16(0x999);
hdr->product_version.revision = __cpu_to_be16(0x999);
/* Boot image major version */
hdr->component_version.major = __cpu_to_be16(0x999);
hdr->component_version.minor = __cpu_to_be16(0x999);
hdr->component_version.revision = __cpu_to_be16(0x999);
/* Drive tag must be 0x0 for i.MX23 */
hdr->drive_tag = 0;
hdr->header_blocks = sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE;
hdr->section_header_size = sizeof(struct sb_sections_header) / SB_BLOCK_SIZE;
hdr->timestamp_us = sb_get_timestamp() * 1000000;
/* FIXME -- add proper config option */
hdr->flags = verbose_boot ? SB_IMAGE_FLAG_VERBOSE : 0,
/* FIXME -- We support only default key */
hdr->key_count = 1;
return 0;
}
static int sb_postfill_image_header(struct sb_image_ctx *ictx)
{
struct sb_boot_image_header *hdr = &ictx->payload;
struct sb_section_ctx *sctx = ictx->sect;
struct sb_cmd_ctx *cctx;
uint32_t kd_size, sections_blocks;
signed int bootable_section = -1;
EVP_MD_CTX md_ctx;
/* The main SB header size in blocks. */
hdr->image_blocks = hdr->header_blocks;
/* Size of the key dictionary, which has single zero entry. */
kd_size = hdr->key_count * sizeof(struct sb_key_dictionary_key);
hdr->image_blocks += kd_size / SB_BLOCK_SIZE;
/* Now count the payloads. */
hdr->section_count = 0;
while (sctx) {
/* Check if this section is bootable. */
if (sctx->boot) {
if (bootable_section < 0)
bootable_section = hdr->section_count;
else
fprintf(stderr, "WARN: Multiple bootable sections!\n");
}
/* Load CMD pointer, move section pointer. */
cctx = sctx->cmd;
sctx = sctx->sect;
hdr->section_count++;
/* Check for degenerated section. */
if (!cctx) {
fprintf(stderr, "WARN: Empty section!\n");
continue;
}
while (cctx) {
hdr->image_blocks += sizeof(struct sb_command) / SB_BLOCK_SIZE;
if (cctx->data) {
if (cctx->length & (SB_BLOCK_SIZE - 1))
fprintf(stderr, "WARN: Unaligned payload!\n");
hdr->image_blocks += cctx->length / SB_BLOCK_SIZE;
}
cctx = cctx->cmd;
}
}
if (bootable_section < 0)
fprintf(stderr, "WARN: No bootable section selected!\n");
else
hdr->first_boot_section_id = bootable_section;
/* The n * SB section size in blocks. */
sections_blocks = hdr->section_count * hdr->section_header_size;
hdr->image_blocks += sections_blocks;
/* Key dictionary offset. */
hdr->key_dictionary_block = hdr->header_blocks + sections_blocks;
/* Digest of the whole image. */
hdr->image_blocks += 2;
/* Pointer past the dictionary. */
hdr->first_boot_tag_block =
hdr->key_dictionary_block + kd_size / SB_BLOCK_SIZE;
/* Compute header digest. */
EVP_MD_CTX_init(&md_ctx);
EVP_DigestInit(&md_ctx, EVP_sha1());
EVP_DigestUpdate(&md_ctx, hdr->signature1,
sizeof(struct sb_boot_image_header) -
sizeof(hdr->digest));
EVP_DigestFinal(&md_ctx, hdr->digest, NULL);
return 0;
}
static int sb_parse_image(struct sb_image_ctx *ictx)
{
int ret;
ret = sb_prefill_image_header(ictx);
if (ret)
return ret;
ret = sb_parse_sections(ictx);
if (ret)
return ret;
ret = sb_postfill_image_header(ictx);
if (ret) {
/* FIXME -- free image! */
return ret;
}
return 0;
}
static void sb_free_image(struct sb_image_ctx *ictx)
{
struct sb_section_ctx *sctx = ictx->sect, *s_head;
struct sb_cmd_ctx *cctx, *c_head;
if (!sctx)
return;
while (sctx) {
s_head = sctx;
c_head = sctx->cmd;
while (c_head) {
cctx = c_head;
c_head = c_head->cmd;
free(cctx);
}
sctx = sctx->sect;
free(s_head);
}
}
int main(int argc, char **argv)
{
uint8_t *image;
......@@ -670,6 +872,7 @@ int main(int argc, char **argv)
char *uboot_filename = NULL;
struct sb_image_ctx ctx;
memset(&ctx, 0, sizeof(ctx));
while ((opt = getopt(argc, argv, "c:s:u:o:vh")) != -1) {
switch (opt) {
......@@ -720,7 +923,10 @@ int main(int argc, char **argv)
if (ret)
return ret;
memcpy(&ctx.payload, &sb_header_template, sizeof(sb_header_template));
ret = sb_parse_image(&ctx);
if (ret)
goto fail;
ret = sb_create_image(&ctx, &image);
if (ret)
return ret;
......@@ -728,6 +934,9 @@ int main(int argc, char **argv)
image_size = ctx.payload.image_blocks * SB_BLOCK_SIZE;
ret = sb_save_image(output_filename, image, image_size);
fail:
sb_free_image(&ctx);
sb_unload_binary(1);
sb_unload_binary(0);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment