diff options
Diffstat (limited to 'scripts/imx/imx.c')
-rw-r--r-- | scripts/imx/imx.c | 316 |
1 files changed, 240 insertions, 76 deletions
diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c index b3e8d62ba8..5ccc116cfe 100644 --- a/scripts/imx/imx.c +++ b/scripts/imx/imx.c @@ -1,20 +1,5 @@ -/* - * (C) Copyright 2016 Sascha Hauer, Pengutronix - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2016 Sascha Hauer, Pengutronix #define _GNU_SOURCE #include <stdio.h> @@ -24,7 +9,6 @@ #include <errno.h> #include <sys/stat.h> #include <linux/kernel.h> -#include <mach/imx_cpu_types.h> #include "imx.h" @@ -36,6 +20,23 @@ */ #define ENCRYPT_OFFSET (HEADER_LEN + 0x10) +static char *strcata(char *str, const char *add) +{ + size_t size = (str ? strlen(str) : 0) + strlen(add) + 1; + bool need_init = str ? false : true; + + str = realloc(str, size); + if (!str) + return NULL; + + if (need_init) + memset(str, 0, size); + + strcat(str, add); + + return str; +} + static int parse_line(char *line, char *argv[]) { int nargs = 0; @@ -215,16 +216,22 @@ static int do_loadaddr(struct config_data *data, int argc, char *argv[]) return 0; } -static int do_dcd_offset(struct config_data *data, int argc, char *argv[]) +static int do_ivt_offset(struct config_data *data, int argc, char *argv[]) { if (argc < 2) return -EINVAL; - data->image_dcd_offset = strtoul(argv[1], NULL, 0); + data->image_ivt_offset = strtoul(argv[1], NULL, 0); return 0; } +static int do_dcdofs_error(struct config_data *data, int argc, char *argv[]) +{ + fprintf(stderr, "ERROR: misnomer dcdofs has been renamed to ivtofs. imxcfg must be adapted.\n"); + return -EINVAL; +} + struct soc_type { char *name; int header_version; @@ -243,6 +250,9 @@ static struct soc_type socs[] = { { .name = "imx53", .header_version = 2, .cpu_type = IMX_CPU_IMX53, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, { .name = "imx6", .header_version = 2, .cpu_type = IMX_CPU_IMX6, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, { .name = "imx7", .header_version = 2, .cpu_type = IMX_CPU_IMX7, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, + { .name = "imx8mm", .header_version = 2, .cpu_type = IMX_CPU_IMX8MM, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, + { .name = "imx8mn", .header_version = 2, .cpu_type = IMX_CPU_IMX8MN, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, + { .name = "imx8mp", .header_version = 2, .cpu_type = IMX_CPU_IMX8MP, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, { .name = "imx8mq", .header_version = 2, .cpu_type = IMX_CPU_IMX8MQ, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, { .name = "vf610", .header_version = 2, .cpu_type = IMX_CPU_VF610, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, }; @@ -271,7 +281,7 @@ static int do_soc(struct config_data *data, int argc, char *argv[]) } } - fprintf(stderr, "unkown SoC type \"%s\". Known SoCs are:\n", soc); + fprintf(stderr, "unknown 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"); @@ -289,16 +299,53 @@ static int do_max_load_size(struct config_data *data, int argc, char *argv[]) return 0; } +static int do_hab_qspi(struct config_data *data, int argc, char *argv[]) +{ + /* + * Force 'hab_qspi' to specified before any 'hab' to ensure correct CSF + * generation. + */ + if (data->csf) { + fprintf(stderr, + "'hab_qspi' must be specified before any 'hab' command\n"); + return -EINVAL; + } + + data->hab_qspi_support = true; + + return 0; +} + static int hab_add_str(struct config_data *data, const char *str) { - int len = strlen(str); + data->csf = strcata(data->csf, str); + if (!data->csf) + return -ENOMEM; - if (data->csf_space < len) + if (!data->hab_qspi_support) + return 0; + + data->flexspi_csf = strcata(data->flexspi_csf, str); + if (!data->flexspi_csf) return -ENOMEM; - strcat(data->csf, str); + return 0; +} - data->csf_space -= len; +static int hab_add_barebox_blocks(struct config_data *data, + const char *csf_str, + const char *flexspi_csf_str) +{ + data->csf = strcata(data->csf, csf_str); + if (!data->csf) + return -ENOMEM; + + if (!flexspi_csf_str) + return 0; + + data->flexspi_csf = strcata(data->flexspi_csf, flexspi_csf_str); + if (!data->flexspi_csf) + return -ENOMEM; return 0; } @@ -307,14 +354,6 @@ static int do_hab(struct config_data *data, int argc, char *argv[]) { int i, ret; - if (!data->csf) { - data->csf_space = 0x10000; - - data->csf = calloc(data->csf_space + 1, 1); - if (!data->csf) - return -ENOMEM; - } - for (i = 1; i < argc; i++) { ret = hab_add_str(data, argv[i]); if (ret) @@ -332,22 +371,48 @@ static int do_hab(struct config_data *data, int argc, char *argv[]) return 0; } +static void +imx8m_get_offset_size(struct config_data *data, + uint32_t *offset, uint32_t *signed_size, + uint32_t *flexspi_offset, uint32_t *flexspi_signed_size) +{ + unsigned int hdrlen = HEADER_LEN; + + if (flexspi_image(data)) + hdrlen += FLEXSPI_HEADER_LEN; + + *signed_size = roundup(data->pbl_code_size + hdrlen, 0x1000); + *flexspi_signed_size = roundup(data->pbl_code_size + FLEXSPI_HEADER_LEN, + 0x1000); + + *offset += data->header_gap; + *flexspi_offset += data->header_gap; + /* + * Starting with i.MX8MP/N the FlexSPI IVT offset is 0x0 but the primary + * image offset is at 0x1000. + */ + if (data->cpu_type != IMX_CPU_IMX8MM) + *flexspi_offset += HEADER_LEN; + + if (data->signed_hdmi_firmware_file) { + *offset += PLUGIN_HDMI_SIZE; + *flexspi_offset += PLUGIN_HDMI_SIZE; + } +} + static int do_hab_blocks(struct config_data *data, int argc, char *argv[]) { - const char *type; - char *str; + char *str, *flexspi_str = NULL; int ret; + int i; uint32_t signed_size = data->load_size; - uint32_t offset = 0; + uint32_t flexspi_signed_size = signed_size; + uint32_t offset = data->image_ivt_offset; + uint32_t flexspi_offset = data->image_flexspi_ivt_offset; if (!data->csf) return -EINVAL; - if (argc < 2) - type = "full"; - else - type = argv[1]; - /* * In case of encrypted image we reduce signed area to beginning * of encrypted area. @@ -358,43 +423,83 @@ static int do_hab_blocks(struct config_data *data, int argc, char *argv[]) /* * Ensure we only sign the PBL for i.MX8MQ */ - if (data->pbl_code_size && data->cpu_type == IMX_CPU_IMX8MQ) { - offset = data->header_gap; - signed_size = roundup(data->pbl_code_size + HEADER_LEN, 0x1000); - if (data->signed_hdmi_firmware_file) - offset += PLUGIN_HDMI_SIZE; - } - - if (!strcmp(type, "full")) { - ret = asprintf(&str, "Blocks = 0x%08x 0x%08x 0x%08x \"%s\"\n", - data->image_load_addr, offset, signed_size, - data->outfile); - } else if (!strcmp(type, "from-dcdofs")) { - ret = asprintf(&str, "Blocks = 0x%08x 0x%x %d \"%s\"\n", - data->image_load_addr + data->image_dcd_offset, - data->image_dcd_offset, - signed_size - data->image_dcd_offset, - data->outfile); - } else if (!strcmp(type, "skip-mbr")) { - ret = asprintf(&str, - "Blocks = 0x%08x 0 440 \"%s\", \\\n" - " 0x%08x 512 %d \"%s\"\n", - data->image_load_addr, data->outfile, - data->image_load_addr + 512, - signed_size - 512, data->outfile); + if (data->pbl_code_size && cpu_is_mx8m(data)) + imx8m_get_offset_size(data, &offset, &signed_size, + &flexspi_offset, &flexspi_signed_size); + + if (signed_size > 0) { + ret = asprintf(&str, "Blocks = 0x%08x 0x%08x 0x%08x \"%s\"", + data->image_load_addr + data->image_ivt_offset, offset, + signed_size - data->image_ivt_offset, data->outfile); + if (data->flexspi_csf) + ret |= asprintf(&flexspi_str, + "Blocks = 0x%08x 0x%08x 0x%08x \"%s\"", + data->image_load_addr + + data->image_flexspi_ivt_offset, + flexspi_offset, flexspi_signed_size, + data->outfile); } else { - fprintf(stderr, "Invalid hab_blocks option: %s\n", type); + fprintf(stderr, "Invalid signed size area 0x%08x\n", + signed_size); return -EINVAL; } if (ret < 0) return -ENOMEM; - ret = hab_add_str(data, str); + ret = hab_add_barebox_blocks(data, str, flexspi_str); + free(str); + free(flexspi_str); if (ret) return ret; - return 0; + for (i = 1; i < argc; i++) { + uint32_t addr; + uint32_t off; + uint32_t size; + char *b; + char *e; + + b = argv[i]; + if (*b == '"') // remove leading qoute + b++; + if (!*b || *b == '"') + continue; // skip if empty + + off = strtoul(b, &e, 0); + if (*e != '+') { + fprintf(stderr, "failed to find '+' in '%s'\n", b); + fprintf(stderr, "format off+size@addr expected, but given: %s\n", argv[i]); + return -EINVAL; + } + + b = e + 1; + size = strtoul(b, &e, 0); + if (*e != '@') { + fprintf(stderr, "failed to find '@' in '%s'\n", b); + fprintf(stderr, "format off+size@addr expected, but given: %s\n", argv[i]); + return -EINVAL; + } + + b = e + 1; + addr = strtoul(b, &e, 0); + if (*e && *e != '"') { // ignore trailing qoute + fprintf(stderr, "unexpected char at the end: '%c'\n", *e); + fprintf(stderr, "format off+size@addr expected, but given: %s\n", argv[i]); + return -EINVAL; + } + + ret = asprintf(&str, ", 0x%08x 0x%08x 0x%08x \"%s\"", addr, off, size, data->outfile); + if (ret < 0) + return -ENOMEM; + + ret = hab_add_str(data, str); + free(str); + if (ret) + return ret; + } + + return hab_add_str(data, "\n"); } static int do_hab_encrypt(struct config_data *data, int argc, char *argv[]) @@ -586,6 +691,38 @@ do_signed_hdmi_firmware(struct config_data *data, int argc, char *argv[]) return 0; } +static int do_flexspi_ivtofs(struct config_data *data, int argc, char *argv[]) +{ + if (argc < 2) + return -EINVAL; + + if (data->csf) { + fprintf(stderr, "#include <mach/imx/flexspi-imx8m*-cfg.h> must be placed in front " + "of #include <mach/imx/habv4-imx8-gencsf.h>\n"); + return -EINVAL; + } + + data->image_flexspi_ivt_offset = strtoul(argv[1], NULL, 0); + + return 0; +} + +static int do_flexspi_fcfbofs(struct config_data *data, int argc, char *argv[]) +{ + if (argc < 2) + return -EINVAL; + + if (data->csf) { + fprintf(stderr, "#include <mach/imx/flexspi-imx8m*-cfg.h> must be placed in front " + "of #include <mach/imx/habv4-imx8-gencsf.h>\n"); + return -EINVAL; + } + + data->image_flexspi_fcfb_offset = strtoul(argv[1], NULL, 0); + + return 0; +} + struct command cmds[] = { { .name = "wm", @@ -606,8 +743,11 @@ struct command cmds[] = { .name = "loadaddr", .parse = do_loadaddr, }, { + .name = "ivtofs", + .parse = do_ivt_offset, + }, { .name = "dcdofs", - .parse = do_dcd_offset, + .parse = do_dcdofs_error, }, { .name = "soc", .parse = do_soc, @@ -636,11 +776,20 @@ struct command cmds[] = { .name = "hab_encrypt_blocks", .parse = do_hab_encrypt_blocks, }, { + .name = "hab_qspi", + .parse = do_hab_qspi, + }, { .name = "super_root_key", .parse = do_super_root_key, }, { .name = "signed_hdmi_firmware", .parse = do_signed_hdmi_firmware, + }, { + .name = "flexspi_fcfbofs", + .parse = do_flexspi_fcfbofs, + }, { + .name = "flexspi_ivtofs", + .parse = do_flexspi_ivtofs, }, }; @@ -649,6 +798,7 @@ static char *readcmd(struct config_data *data, FILE *f) static char *buf; char *str; ssize_t ret; + int inquotes = 0; if (!buf) { buf = malloc(4096); @@ -663,8 +813,9 @@ static char *readcmd(struct config_data *data, FILE *f) ret = fread(str, 1, 1, f); if (!ret) return strlen(buf) ? buf : NULL; - - if (*str == '\n' || *str == ';') { + if (*str == '"') { + inquotes = !inquotes; + } else if ((*str == '\n' || *str == ';') && !inquotes) { *str = 0; return buf; } @@ -673,13 +824,16 @@ static char *readcmd(struct config_data *data, FILE *f) } } -int parse_config(struct config_data *data, const char *filename) +int parse_config(struct config_data *data, const char *_filename) { FILE *f; int lineno = 0; char *line = NULL, *tmp; char *argv[MAXARGS]; int nargs, i, ret = 0; + char *filename; + + filename = strdup(_filename); f = fopen(filename, "r"); if (!f) { @@ -695,8 +849,17 @@ int parse_config(struct config_data *data, const char *filename) lineno++; tmp = strchr(line, '#'); - if (tmp) - *tmp = 0; + if (tmp) { + char *endptr; + long linenum = strtol(tmp + 1, &endptr, 10); + if (strncmp(endptr, " \"", 2) == 0 && endptr[2]) { + free(filename); + lineno = linenum - 1; + filename = strdup(endptr + 2); + filename[strlen(filename) - 1] = '\0'; + } + *tmp = '\0'; + } nargs = parse_line(line, argv); if (!nargs) @@ -708,8 +871,8 @@ int parse_config(struct config_data *data, const char *filename) if (!strcmp(cmds[i].name, argv[0])) { ret = cmds[i].parse(data, nargs, argv); if (ret) { - fprintf(stderr, "error in line %d: %s\n", - lineno, strerror(-ret)); + fprintf(stderr, "%s:%d: %s\n", + filename, lineno, strerror(-ret)); goto cleanup; } break; @@ -724,5 +887,6 @@ int parse_config(struct config_data *data, const char *filename) cleanup: fclose(f); + free(filename); return ret; } |