diff options
Diffstat (limited to 'scripts/imx/imx-image.c')
-rw-r--r-- | scripts/imx/imx-image.c | 826 |
1 files changed, 409 insertions, 417 deletions
diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index e8d9dbf23e..20815bfb98 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. * */ +#define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <getopt.h> @@ -26,45 +27,29 @@ #include <sys/stat.h> #include <fcntl.h> #include <endian.h> +#include <linux/kernel.h> +#include <sys/file.h> -#include <include/filetype.h> +#include "imx.h" -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) -#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#include <include/filetype.h> #define MAX_DCD 1024 -#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */ #define CSF_LEN 0x2000 /* length of the CSF (needed for HAB) */ -static uint32_t image_load_addr; -static uint32_t image_dcd_offset; static uint32_t dcdtable[MAX_DCD]; static int curdcd; -static int header_version; -static int cpu_type; static int add_barebox_header; -static int prepare_sign; +static int create_usb_image; +static char *prgname; /* * ============================================================================ * i.MX flash header v1 handling. Found on i.MX35 and i.MX51 * ============================================================================ */ -struct imx_flash_header { - uint32_t app_code_jump_vector; - uint32_t app_code_barker; - uint32_t app_code_csf; - uint32_t dcd_ptr_ptr; - uint32_t super_root_key; - uint32_t dcd; - uint32_t app_dest; - uint32_t dcd_barker; - uint32_t dcd_block_len; -} __attribute__((packed)); #define FLASH_HEADER_OFFSET 0x400 -#define DCD_BARKER 0xb17219e9 static uint32_t bb_header[] = { 0xea0003fe, /* b 0x1000 */ @@ -89,11 +74,141 @@ static uint32_t bb_header[] = { 0x55555555, }; -static int add_header_v1(void *buf, int offset, uint32_t loadaddr, uint32_t imagesize) +struct hab_rsa_public_key { + uint8_t rsa_exponent[4]; /* RSA public exponent */ + uint32_t rsa_modulus; /* RSA modulus pointer */ + uint16_t exponent_size; /* Exponent size in bytes */ + uint16_t modulus_size; /* Modulus size in bytes*/ + uint8_t init_flag; /* Indicates if key initialized */ +}; + +#ifdef IMXIMAGE_SSL_SUPPORT +#define PUBKEY_ALGO_LEN 2048 + +#include <openssl/x509v3.h> +#include <openssl/bn.h> +#include <openssl/asn1.h> +#include <openssl/x509.h> +#include <openssl/x509_vfy.h> +#include <openssl/pem.h> +#include <openssl/bio.h> + +static int extract_key(const char *certfile, uint8_t **modulus, int *modulus_len, + uint8_t **exponent, int *exponent_len) +{ + char buf[PUBKEY_ALGO_LEN]; + int pubkey_algonid; + const char *sslbuf; + EVP_PKEY *pkey; + FILE *fp; + X509 *cert; + RSA *rsa_key; + + fp = fopen(certfile, "r"); + if (!fp) { + fprintf(stderr, "unable to open certfile: %s\n", certfile); + return -errno; + } + + cert = PEM_read_X509(fp, NULL, NULL, NULL); + if (!cert) { + fprintf(stderr, "unable to parse certificate in: %s\n", certfile); + fclose(fp); + return -errno; + } + + fclose(fp); + + pubkey_algonid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); + if (pubkey_algonid == NID_undef) { + fprintf(stderr, "unable to find specified public key algorithm name.\n"); + return -EINVAL; + } + + if (pubkey_algonid != NID_rsaEncryption) + return -EINVAL; + + sslbuf = OBJ_nid2ln(pubkey_algonid); + strncpy(buf, sslbuf, PUBKEY_ALGO_LEN); + + pkey = X509_get_pubkey(cert); + if (!pkey) { + fprintf(stderr, "unable to extract public key from certificate"); + return -EINVAL; + } + + rsa_key = pkey->pkey.rsa; + if (!rsa_key) { + fprintf(stderr, "unable to extract RSA public key"); + return -EINVAL; + } + + *modulus_len = BN_num_bytes(rsa_key->n); + *modulus = malloc(*modulus_len); + BN_bn2bin(rsa_key->n, *modulus); + + *exponent_len = BN_num_bytes(rsa_key->e); + *exponent = malloc(*exponent_len); + BN_bn2bin(rsa_key->e, *exponent); + + EVP_PKEY_free(pkey); + X509_free(cert); + + return 0; +} + +static int add_srk(void *buf, int offset, uint32_t loadaddr, const char *srkfile) +{ + struct imx_flash_header *hdr = buf + offset; + struct hab_rsa_public_key *key = buf + 0xc00; + uint8_t *exponent = NULL, *modulus = NULL, *modulus_dest; + int exponent_len = 0, modulus_len = 0; + int ret; + + hdr->super_root_key = loadaddr + 0xc00; + + key->init_flag = 1; + key->exponent_size = htole16(3); + + ret = extract_key(srkfile, &modulus, &modulus_len, &exponent, &exponent_len); + if (ret) + return ret; + + modulus_dest = (void *)(key + 1); + + memcpy(modulus_dest, modulus, modulus_len); + + key->modulus_size = htole16(modulus_len); + key->rsa_modulus = htole32(hdr->super_root_key + sizeof(*key)); + + if (exponent_len > 4) + return -EINVAL; + + key->exponent_size = exponent_len; + memcpy(&key->rsa_exponent, exponent, key->exponent_size); + + return 0; +} +#else +static int add_srk(void *buf, int offset, uint32_t loadaddr, const char *srkfile) +{ + fprintf(stderr, "This version of imx-image is compiled without SSL support\n"); + + return -EINVAL; +} +#endif /* IMXIMAGE_SSL_SUPPORT */ + +static int dcd_ptr_offset; +static uint32_t dcd_ptr_content; + +static int add_header_v1(struct config_data *data, void *buf) { struct imx_flash_header *hdr; int dcdsize = curdcd * sizeof(uint32_t); uint32_t *psize = buf + ARM_HEAD_SIZE_OFFSET; + int offset = data->image_dcd_offset; + uint32_t loadaddr = data->image_load_addr; + uint32_t imagesize = data->load_size; if (add_barebox_header) { memcpy(buf, bb_header, sizeof(bb_header)); @@ -108,10 +223,17 @@ static int add_header_v1(void *buf, int offset, uint32_t loadaddr, uint32_t imag hdr->app_code_csf = 0x0; hdr->dcd_ptr_ptr = loadaddr + offset + offsetof(struct imx_flash_header, dcd); hdr->super_root_key = 0x0; - hdr->dcd = loadaddr + offset + offsetof(struct imx_flash_header, dcd_barker); + hdr->dcd = loadaddr + offset + offsetof(struct imx_flash_header, dcd_barker); + hdr->app_dest = loadaddr; hdr->dcd_barker = DCD_BARKER; - hdr->dcd_block_len = dcdsize; + if (create_usb_image) { + dcd_ptr_offset = offsetof(struct imx_flash_header, dcd_block_len) + offset; + hdr->dcd_block_len = 0; + dcd_ptr_content = dcdsize; + } else { + hdr->dcd_block_len = dcdsize; + } buf += sizeof(struct imx_flash_header); @@ -119,6 +241,11 @@ static int add_header_v1(void *buf, int offset, uint32_t loadaddr, uint32_t imag buf += dcdsize; + if (data->csf) { + hdr->app_code_csf = loadaddr + imagesize; + imagesize += CSF_LEN; + } + *(uint32_t *)buf = imagesize; return 0; @@ -144,45 +271,14 @@ static int write_mem_v1(uint32_t addr, uint32_t val, int width) * ============================================================================ */ -struct imx_boot_data { - uint32_t start; - uint32_t size; - uint32_t plugin; -} __attribute__((packed)); - -#define TAG_IVT_HEADER 0xd1 -#define IVT_VERSION 0x40 -#define TAG_DCD_HEADER 0xd2 -#define DCD_VERSION 0x40 -#define TAG_WRITE 0xcc -#define TAG_CHECK 0xcf - -struct imx_ivt_header { - uint8_t tag; - uint16_t length; - uint8_t version; -} __attribute__((packed)); - -struct imx_flash_header_v2 { - struct imx_ivt_header header; - - uint32_t entry; - uint32_t reserved1; - uint32_t dcd_ptr; - uint32_t boot_data_ptr; - uint32_t self; - uint32_t csf; - uint32_t reserved2; - - struct imx_boot_data boot_data; - struct imx_ivt_header dcd_header; -} __attribute__((packed)); - -static int add_header_v2(void *buf, int offset, uint32_t loadaddr, uint32_t imagesize) +static int add_header_v2(struct config_data *data, void *buf) { struct imx_flash_header_v2 *hdr; int dcdsize = curdcd * sizeof(uint32_t); uint32_t *psize = buf + ARM_HEAD_SIZE_OFFSET; + int offset = data->image_dcd_offset; + uint32_t loadaddr = data->image_load_addr; + uint32_t imagesize = data->load_size; if (add_barebox_header) memcpy(buf, bb_header, sizeof(bb_header)); @@ -196,13 +292,18 @@ static int add_header_v2(void *buf, int offset, uint32_t loadaddr, uint32_t imag hdr->entry = loadaddr + HEADER_LEN; hdr->dcd_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, dcd_header); + if (create_usb_image) { + dcd_ptr_content = hdr->dcd_ptr; + dcd_ptr_offset = offsetof(struct imx_flash_header_v2, dcd_ptr) + offset; + hdr->dcd_ptr = 0; + } hdr->boot_data_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, boot_data); hdr->self = loadaddr + offset; hdr->boot_data.start = loadaddr; hdr->boot_data.size = imagesize; - if (prepare_sign) { + if (data->csf) { hdr->csf = loadaddr + imagesize; hdr->boot_data.size += CSF_LEN; } @@ -230,55 +331,10 @@ static void usage(const char *prgname) "-b add barebox header to image. If used, barebox recognizes\n" " the image as regular barebox image which can be used as\n" " second stage image\n" - "-p prepare image for signing\n" "-h this help\n", prgname); exit(1); } -#define MAXARGS 5 - -static int parse_line(char *line, char *argv[]) -{ - int nargs = 0; - - while (nargs < MAXARGS) { - - /* skip any white space */ - while ((*line == ' ') || (*line == '\t')) - ++line; - - if (*line == '\0') /* end of line, no more args */ - argv[nargs] = NULL; - - if (*line == '\0') { /* end of line, no more args */ - argv[nargs] = NULL; - return nargs; - } - - argv[nargs++] = line; /* begin of argument string */ - - /* find end of string */ - while (*line && (*line != ' ') && (*line != '\t')) - ++line; - - if (*line == '\0') { /* end of line, no more args */ - argv[nargs] = NULL; - return nargs; - } - - *line++ = '\0'; /* terminate current arg */ - } - - printf("** Too many args (max. %d) **\n", MAXARGS); - - return nargs; -} - -struct command { - const char *name; - int (*parse)(int argc, char *argv[]); -}; - static uint32_t last_write_cmd; static int last_cmd_len; static uint32_t *last_dcd; @@ -324,67 +380,64 @@ static int write_mem_v2(uint32_t addr, uint32_t val, int width) return 0; } -static const char *check_cmds[] = { - "while_all_bits_clear", /* while ((*address & mask) == 0); */ - "while_all_bits_set" , /* while ((*address & mask) == mask); */ - "while_any_bit_clear", /* while ((*address & mask) != mask); */ - "while_any_bit_set", /* while ((*address & mask) != 0); */ -}; - -static void do_cmd_check_usage(void) +static int xread(int fd, void *buf, int len) { - fprintf(stderr, - "usage: check <width> <cmd> <addr> <mask>\n" - "<width> access width in bytes [1|2|4]\n" - "with <cmd> one of:\n" - "while_all_bits_clear: while ((*addr & mask) == 0)\n" - "while_all_bits_set: while ((*addr & mask) == mask)\n" - "while_any_bit_clear: while ((*addr & mask) != mask)\n" - "while_any_bit_set: while ((*addr & mask) != 0)\n"); + int ret; + + while (len) { + ret = read(fd, buf, len); + if (ret < 0) + return ret; + if (!ret) + return EOF; + buf += ret; + len -= ret; + } + + return 0; } -static int do_cmd_check(int argc, char *argv[]) +static int xwrite(int fd, void *buf, int len) { - uint32_t addr, mask, cmd; - int i, width; - const char *scmd; + int ret; - if (argc < 5) { - do_cmd_check_usage(); - return -EINVAL; + while (len) { + ret = write(fd, buf, len); + if (ret < 0) + return ret; + buf += ret; + len -= ret; } - width = strtoul(argv[1], NULL, 0) >> 3; - scmd = argv[2]; - addr = strtoul(argv[3], NULL, 0); - mask = strtoul(argv[4], NULL, 0); + return 0; +} - switch (width) { - case 1: - case 2: - case 4: - break; - default: - fprintf(stderr, "illegal width %d\n", width); - return -EINVAL; - }; +static int write_dcd(const char *outfile) +{ + int outfd, ret; + int dcdsize = curdcd * sizeof(uint32_t); - if (curdcd > MAX_DCD - 3) { - fprintf(stderr, "At maximum %d dcd entried are allowed\n", MAX_DCD); - return -ENOMEM; + outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (outfd < 0) { + perror("open"); + exit(1); } - for (i = 0; i < ARRAY_SIZE(check_cmds); i++) { - if (!strcmp(scmd, check_cmds[i])) - break; + ret = xwrite(outfd, dcdtable, dcdsize); + if (ret < 0) { + perror("write"); + exit(1); } - if (i == ARRAY_SIZE(check_cmds)) { - do_cmd_check_usage(); - return -EINVAL; - } + return 0; +} - cmd = (TAG_CHECK << 24) | (i << 3) | width | ((sizeof(uint32_t) * 3) << 8); +static int check(struct config_data *data, uint32_t cmd, uint32_t addr, uint32_t mask) +{ + if (curdcd > MAX_DCD - 3) { + fprintf(stderr, "At maximum %d dcd entried are allowed\n", MAX_DCD); + return -ENOMEM; + } check_last_dcd(cmd); @@ -395,47 +448,9 @@ static int do_cmd_check(int argc, char *argv[]) return 0; } -static int do_cmd_write_mem(int argc, char *argv[]) +static int write_mem(struct config_data *data, uint32_t addr, uint32_t val, int width) { - uint32_t addr, val, width; - char *end; - - if (argc != 4) { - fprintf(stderr, "usage: wm [8|16|32] <addr> <val>\n"); - return -EINVAL; - } - - width = strtoul(argv[1], &end, 0); - if (*end != '\0') { - fprintf(stderr, "illegal width token \"%s\"\n", argv[1]); - return -EINVAL; - } - - addr = strtoul(argv[2], &end, 0); - if (*end != '\0') { - fprintf(stderr, "illegal address token \"%s\"\n", argv[2]); - return -EINVAL; - } - - val = strtoul(argv[3], &end, 0); - if (*end != '\0') { - fprintf(stderr, "illegal value token \"%s\"\n", argv[3]); - return -EINVAL; - } - - width >>= 3; - - switch (width) { - case 1: - case 2: - case 4: - break; - default: - fprintf(stderr, "illegal width %d\n", width); - return -EINVAL; - }; - - switch (header_version) { + switch (data->header_version) { case 1: return write_mem_v1(addr, val, width); case 2: @@ -445,218 +460,158 @@ static int do_cmd_write_mem(int argc, char *argv[]) } } -static int do_loadaddr(int argc, char *argv[]) -{ - if (argc < 2) - return -EINVAL; - - image_load_addr = strtoul(argv[1], NULL, 0); - - return 0; -} - -static int do_dcd_offset(int argc, char *argv[]) -{ - if (argc < 2) - return -EINVAL; - - image_dcd_offset = strtoul(argv[1], NULL, 0); - - return 0; -} - -struct soc_type { - char *name; - int header_version; - int cpu_type; -}; - -static struct soc_type socs[] = { - { .name = "imx25", .header_version = 1, .cpu_type = 25}, - { .name = "imx35", .header_version = 1, .cpu_type = 35 }, - { .name = "imx51", .header_version = 1, .cpu_type = 51 }, - { .name = "imx53", .header_version = 2, .cpu_type = 53 }, - { .name = "imx6", .header_version = 2, .cpu_type = 6 }, -}; - -static int do_soc(int argc, char *argv[]) +/* + * This uses the Freescale Code Signing Tool (CST) to sign the image. + * The cst is expected to be executable as 'cst' or if exists, the content + * of the environment variable 'CST' is used. + */ +static int hab_sign(struct config_data *data) { - char *soc; - int i; + int fd, outfd, ret, lockfd; + char *csffile, *command; + struct stat s; + char *cst; + void *buf; - if (argc < 2) - return -EINVAL; + cst = getenv("CST"); + if (!cst) + cst = "cst"; - soc = argv[1]; + ret = asprintf(&csffile, "%s.csfbin", data->outfile); + if (ret < 0) + exit(1); - for (i = 0; i < ARRAY_SIZE(socs); i++) { - if (!strcmp(socs[i].name, soc)) { - header_version = socs[i].header_version; - cpu_type = socs[i].cpu_type; - return 0; + ret = stat(csffile, &s); + if (!ret) { + if (S_ISREG(s.st_mode)) { + ret = unlink(csffile); + if (ret) { + fprintf(stderr, "Cannot remove %s: %s\n", + csffile, strerror(errno)); + return -errno; + } + } else { + fprintf(stderr, "%s exists and is no regular file\n", + csffile); + return -EINVAL; } } - fprintf(stderr, "unkown SoC type \"%s\". Known SoCs are:\n", soc); - for (i = 0; i < ARRAY_SIZE(socs); i++) - fprintf(stderr, "%s ", socs[i].name); - fprintf(stderr, "\n"); - - return -EINVAL; -} - -struct command cmds[] = { - { - .name = "wm", - .parse = do_cmd_write_mem, - }, { - .name = "check", - .parse = do_cmd_check, - }, { - .name = "loadaddr", - .parse = do_loadaddr, - }, { - .name = "dcdofs", - .parse = do_dcd_offset, - }, { - .name = "soc", - .parse = do_soc, - }, -}; - -static char *readcmd(FILE *f) -{ - static char *buf; - char *str; - ssize_t ret; + ret = asprintf(&command, "%s -o %s", cst, csffile); + if (ret < 0) + return -ENOMEM; - if (!buf) { - buf = malloc(4096); - if (!buf) - return NULL; + /* + * The cst uses "csfsig.bin" as temporary file. This of course breaks when it's + * called multiple times as often happens with parallel builds. Until cst learns + * how to properly create temporary files without races lock accesses to this + * file. + */ + lockfd = open(prgname, O_RDONLY); + if (lockfd < 0) { + fprintf(stderr, "Cannot open csfsig.bin: %s\n", strerror(errno)); + return -errno; } - str = buf; - *str = 0; - - while (1) { - ret = fread(str, 1, 1, f); - if (!ret) - return strlen(buf) ? buf : NULL; - - if (*str == '\n' || *str == ';') { - *str = 0; - return buf; - } - - str++; + ret = flock(lockfd, LOCK_EX); + if (ret) { + fprintf(stderr, "Cannot lock csfsig.bin: %s\n", strerror(errno)); + return -errno; } -} -static int parse_config(const char *filename) -{ - FILE *f; - int lineno = 0; - char *line = NULL, *tmp; - char *argv[MAXARGS]; - int nargs, i, ret = 0; - - f = fopen(filename, "r"); + FILE *f = popen(command, "w"); if (!f) { - fprintf(stderr, "Error: %s - Can't open DCD file\n", filename); - exit(1); + perror("popen"); + return -errno; } - while (1) { - line = readcmd(f); - if (!line) - break; - - lineno++; - - tmp = strchr(line, '#'); - if (tmp) - *tmp = 0; + fwrite(data->csf, 1, strlen(data->csf) + 1, f); - nargs = parse_line(line, argv); - if (!nargs) - continue; + pclose(f); - ret = -ENOENT; + flock(lockfd, LOCK_UN); + close(lockfd); - for (i = 0; i < ARRAY_SIZE(cmds); i++) { - if (!strcmp(cmds[i].name, argv[0])) { - ret = cmds[i].parse(nargs, argv); - if (ret) { - fprintf(stderr, "error in line %d: %s\n", - lineno, strerror(-ret)); - goto cleanup; - } - break; - } - } + /* + * the Freescale code signing tool doesn't fail if there + * are errors in the command sequence file, it just doesn't + * produce any output, so we have to check for existence of + * the output file rather than checking the return value of + * the cst call. + */ + fd = open(csffile, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Failed to open %s: %s\n", csffile, strerror(errno)); + fprintf(stderr, "%s failed\n", cst); + return -errno; + } - if (ret == -ENOENT) { - fprintf(stderr, "no such command: %s\n", argv[0]); - goto cleanup; - } + ret = fstat(fd, &s); + if (ret < 0) { + fprintf(stderr, "stat failed: %s\n", strerror(errno)); + return -errno; } -cleanup: - fclose(f); - return ret; -} + buf = malloc(CSF_LEN); + if (!buf) + return -ENOMEM; -static int xread(int fd, void *buf, int len) -{ - int ret; + memset(buf, 0x5a, CSF_LEN); - while (len) { - ret = read(fd, buf, len); - if (ret < 0) - return ret; - if (!ret) - return EOF; - buf += ret; - len -= ret; + if (s.st_size > CSF_LEN) { + fprintf(stderr, "CSF file size exceeds maximum CSF len of %d bytes\n", + CSF_LEN); } - return 0; -} + ret = xread(fd, buf, s.st_size); + if (ret < 0) { + fprintf(stderr, "read failed: %s\n", strerror(errno)); + return -errno; + } -static int xwrite(int fd, void *buf, int len) -{ - int ret; + outfd = open(data->outfile, O_WRONLY | O_APPEND); - while (len) { - ret = write(fd, buf, len); - if (ret < 0) - return ret; - buf += ret; - len -= ret; + ret = xwrite(outfd, buf, CSF_LEN); + if (ret < 0) { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + return -errno; + } + + ret = close(outfd); + if (ret) { + perror("close"); + exit(1); } return 0; } -static int write_dcd(const char *outfile) +static void *read_file(const char *filename, size_t *size) { - int outfd, ret; - int dcdsize = curdcd * sizeof(uint32_t); + int fd, ret; + void *buf; + struct stat s; - outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (outfd < 0) { + fd = open(filename, O_RDONLY); + if (fd < 0) { perror("open"); exit(1); } - ret = xwrite(outfd, dcdtable, dcdsize); - if (ret < 0) { - perror("write"); + ret = fstat(fd, &s); + if (ret) + return NULL; + + *size = s.st_size; + buf = malloc(*size); + if (!buf) exit(1); - } - return 0; + xread(fd, buf, *size); + + close(fd); + + return buf; } int main(int argc, char *argv[]) @@ -664,16 +619,23 @@ int main(int argc, char *argv[]) int opt, ret; char *configfile = NULL; char *imagename = NULL; - char *outfile = NULL; void *buf; - size_t image_size = 0, load_size, insize; + size_t insize; void *infile; struct stat s; - int infd, outfd; + int outfd; int dcd_only = 0; int now = 0; + int sign_image = 0; + struct config_data data = { + .image_dcd_offset = 0xffffffff, + .write_mem = write_mem, + .check = check, + }; - while ((opt = getopt(argc, argv, "c:hf:o:bdp")) != -1) { + prgname = argv[0]; + + while ((opt = getopt(argc, argv, "c:hf:o:bdus")) != -1) { switch (opt) { case 'c': configfile = optarg; @@ -682,7 +644,7 @@ int main(int argc, char *argv[]) imagename = optarg; break; case 'o': - outfile = optarg; + data.outfile = optarg; break; case 'b': add_barebox_header = 1; @@ -690,8 +652,11 @@ int main(int argc, char *argv[]) case 'd': dcd_only = 1; break; - case 'p': - prepare_sign = 1; + case 's': + sign_image = 1; + break; + case 'u': + create_usb_image = 1; break; case 'h': usage(argv[0]); @@ -710,7 +675,7 @@ int main(int argc, char *argv[]) exit(1); } - if (!outfile) { + if (!data.outfile) { fprintf(stderr, "output file not given\n"); exit(1); } @@ -722,83 +687,81 @@ int main(int argc, char *argv[]) exit(1); } - image_size = s.st_size; + data.image_size = s.st_size; } - ret = parse_config(configfile); + /* + * Add HEADER_LEN to the image size for the blank aera + IVT + DCD. + * Align up to a 4k boundary, because: + * - at least i.MX5 NAND boot only reads full NAND pages and misses the + * last partial NAND page. + * - i.MX6 SPI NOR boot corrupts the last few bytes of an image loaded + * in ver funy ways when the image size is not 4 byte aligned + */ + data.load_size = roundup(data.image_size + HEADER_LEN, 0x1000); + + ret = parse_config(&data, configfile); if (ret) exit(1); + if (!sign_image) + data.csf = NULL; + + if (create_usb_image && !data.csf) { + fprintf(stderr, "Warning: the -u option only has effect with signed images\n"); + create_usb_image = 0; + } + buf = calloc(1, HEADER_LEN); if (!buf) exit(1); - if (!image_dcd_offset) { - fprintf(stderr, "no dcd offset given ('dcdofs'). Defaulting to 0x%08x\n", - FLASH_HEADER_OFFSET); - image_dcd_offset = FLASH_HEADER_OFFSET; + if (data.image_dcd_offset == 0xffffffff) { + if (create_usb_image) + data.image_dcd_offset = 0x0; + else + data.image_dcd_offset = FLASH_HEADER_OFFSET; } - if (!header_version) { + if (!data.header_version) { fprintf(stderr, "no SoC given. (missing 'soc' in config)\n"); exit(1); } - if (header_version == 2) + if (data.header_version == 2) check_last_dcd(0); if (dcd_only) { - ret = write_dcd(outfile); + ret = write_dcd(data.outfile); if (ret) exit(1); exit (0); } - /* - * Add HEADER_LEN to the image size for the blank aera + IVT + DCD. - * Align up to a 4k boundary, because: - * - at least i.MX5 NAND boot only reads full NAND pages and misses the - * last partial NAND page. - * - i.MX6 SPI NOR boot corrupts the last few bytes of an image loaded - * in ver funy ways when the image size is not 4 byte aligned - */ - load_size = roundup(image_size + HEADER_LEN, 0x1000); - - if (cpu_type == 35) - load_size += HEADER_LEN; - - switch (header_version) { + switch (data.header_version) { case 1: - add_header_v1(buf, image_dcd_offset, image_load_addr, load_size); + add_header_v1(&data, buf); + if (data.srkfile) { + ret = add_srk(buf, data.image_dcd_offset, data.image_load_addr, + data.srkfile); + if (ret) + exit(1); + } break; case 2: - add_header_v2(buf, image_dcd_offset, image_load_addr, load_size); + add_header_v2(&data, buf); break; default: fprintf(stderr, "Congratulations! You're welcome to implement header version %d\n", - header_version); - exit(1); - } - - infd = open(imagename, O_RDONLY); - if (infd < 0) { - perror("open"); + data.header_version); exit(1); } - ret = fstat(infd, &s); - if (ret) - return ret; - - insize = s.st_size; - infile = malloc(insize); + infile = read_file(imagename, &insize); if (!infile) exit(1); - xread(infd, infile, insize); - close(infd); - - outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + outfd = open(data.outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (outfd < 0) { perror("open"); exit(1); @@ -810,7 +773,7 @@ int main(int argc, char *argv[]) exit(1); } - if (cpu_type == 35) { + if (data.cpu_type == 35) { ret = xwrite(outfd, buf, HEADER_LEN); if (ret < 0) { perror("write"); @@ -826,7 +789,7 @@ int main(int argc, char *argv[]) /* pad until next 4k boundary */ now = 4096 - (insize % 4096); - if (prepare_sign && now) { + if (data.csf && now) { memset(buf, 0x5a, now); ret = xwrite(outfd, buf, now); @@ -842,5 +805,34 @@ int main(int argc, char *argv[]) exit(1); } + if (data.csf) { + ret = hab_sign(&data); + if (ret) + exit(1); + } + + if (create_usb_image) { + uint32_t *dcd; + + infile = read_file(data.outfile, &insize); + + dcd = infile + dcd_ptr_offset; + *dcd = dcd_ptr_content; + + outfd = open(data.outfile, O_WRONLY | O_TRUNC); + if (outfd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", data.outfile, strerror(errno)); + exit(1); + } + + ret = xwrite(outfd, infile, insize); + if (ret < 0) { + perror("write"); + exit (1); + } + + close(outfd); + } + exit(0); } |