// SPDX-License-Identifier: GPL-2.0+
/*
* Image manipulator for Marvell SoCs
- * supports Kirkwood, Dove, Armada 370, Armada XP, and Armada 38x
+ * supports Kirkwood, Dove, Armada 370, Armada XP, Armada 375, Armada 38x and
+ * Armada 39x
*
* (C) Copyright 2013 Thomas Petazzoni
- *
- * Not implemented: support for the register headers in v1 images
*/
#include "imagetool.h"
#include <stdint.h>
#include "kwbimage.h"
-#ifdef CONFIG_KWB_SECURE
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
EVP_MD_CTX_reset(ctx);
}
#endif
-#endif
static struct image_cfg_element *image_cfg;
static int cfgn;
-#ifdef CONFIG_KWB_SECURE
static int verbose_mode;
-#endif
struct boot_mode {
unsigned int id;
};
struct boot_mode boot_modes[] = {
- { 0x4D, "i2c" },
- { 0x5A, "spi" },
- { 0x8B, "nand" },
- { 0x78, "sata" },
- { 0x9C, "pex" },
- { 0x69, "uart" },
- { 0xAE, "sdio" },
+ { IBR_HDR_I2C_ID, "i2c" },
+ { IBR_HDR_SPI_ID, "spi" },
+ { IBR_HDR_NAND_ID, "nand" },
+ { IBR_HDR_SATA_ID, "sata" },
+ { IBR_HDR_PEX_ID, "pex" },
+ { IBR_HDR_UART_ID, "uart" },
+ { IBR_HDR_SDIO_ID, "sdio" },
{},
};
};
struct nand_ecc_mode nand_ecc_modes[] = {
- { 0x00, "default" },
- { 0x01, "hamming" },
- { 0x02, "rs" },
- { 0x03, "disabled" },
+ { IBR_HDR_ECC_DEFAULT, "default" },
+ { IBR_HDR_ECC_FORCED_HAMMING, "hamming" },
+ { IBR_HDR_ECC_FORCED_RS, "rs" },
+ { IBR_HDR_ECC_DISABLED, "disabled" },
{},
};
/* Used to identify an undefined execution or destination address */
#define ADDR_INVALID ((uint32_t)-1)
-#define BINARY_MAX_ARGS 8
+#define BINARY_MAX_ARGS 255
/* In-memory representation of a line of the configuration file */
IMAGE_CFG_NAND_ECC_MODE,
IMAGE_CFG_NAND_PAGESZ,
IMAGE_CFG_BINARY,
- IMAGE_CFG_PAYLOAD,
IMAGE_CFG_DATA,
+ IMAGE_CFG_DATA_DELAY,
IMAGE_CFG_BAUDRATE,
+ IMAGE_CFG_UART_PORT,
+ IMAGE_CFG_UART_MPP,
IMAGE_CFG_DEBUG,
IMAGE_CFG_KAK,
IMAGE_CFG_CSK,
[IMAGE_CFG_NAND_ECC_MODE] = "NAND_ECC_MODE",
[IMAGE_CFG_NAND_PAGESZ] = "NAND_PAGE_SIZE",
[IMAGE_CFG_BINARY] = "BINARY",
- [IMAGE_CFG_PAYLOAD] = "PAYLOAD",
[IMAGE_CFG_DATA] = "DATA",
+ [IMAGE_CFG_DATA_DELAY] = "DATA_DELAY",
[IMAGE_CFG_BAUDRATE] = "BAUDRATE",
+ [IMAGE_CFG_UART_PORT] = "UART_PORT",
+ [IMAGE_CFG_UART_MPP] = "UART_MPP",
[IMAGE_CFG_DEBUG] = "DEBUG",
[IMAGE_CFG_KAK] = "KAK",
[IMAGE_CFG_CSK] = "CSK",
unsigned int args[BINARY_MAX_ARGS];
unsigned int nargs;
} binary;
- const char *payload;
unsigned int dstaddr;
unsigned int execaddr;
unsigned int nandblksz;
unsigned int nandeccmode;
unsigned int nandpagesz;
struct ext_hdr_v0_reg regdata;
+ unsigned int regdata_delay;
unsigned int baudrate;
+ unsigned int uart_port;
+ unsigned int uart_mpp;
unsigned int debug;
const char *key_name;
int csk_idx;
return count;
}
-#if defined(CONFIG_KWB_SECURE)
-
static int image_get_csk_index(void)
{
struct image_cfg_element *e;
return e->sec_specialized_img;
}
-#endif
+static int image_get_bootfrom(void)
+{
+ struct image_cfg_element *e;
+
+ e = image_find_option(IMAGE_CFG_BOOT_FROM);
+ if (!e)
+ /* fallback to SPI if no BOOT_FROM is not provided */
+ return IBR_HDR_SPI_ID;
+
+ return e->bootfrom;
+}
/*
* Compute a 8-bit checksum of a memory area. This algorithm follows
return csum;
}
-size_t kwbimage_header_size(unsigned char *ptr)
-{
- if (image_version((void *)ptr) == 0)
- return sizeof(struct main_hdr_v0);
- else
- return KWBHEADER_V1_SIZE((struct main_hdr_v1 *)ptr);
-}
-
/*
* Verify checksum over a complete header that includes the checksum field.
* Return 1 when OK, otherwise 0.
struct main_hdr_v0 *main_hdr = (struct main_hdr_v0 *)hdr;
uint8_t checksum;
- checksum = image_checksum8(hdr, kwbimage_header_size(hdr));
+ checksum = image_checksum8(hdr, kwbheader_size_for_csum(hdr));
/* Calculated checksum includes the header checksum field. Compensate
* for that.
*/
}
}
-#if defined(CONFIG_KWB_SECURE)
static void kwb_msg(const char *fmt, ...)
{
if (verbose_mode) {
}
if (4 + size_seq > sizeof(dst->key)) {
- fprintf(stderr, "export pk failed: seq too large (%d, %lu)\n",
+ fprintf(stderr, "export pk failed: seq too large (%d, %zu)\n",
4 + size_seq, sizeof(dst->key));
fprintf(stderr, errmsg, keyname);
return -ENOBUFS;
goto err_ctx;
}
- if (!EVP_VerifyFinal(ctx, sig->sig, sizeof(sig->sig), evp_key)) {
+ if (EVP_VerifyFinal(ctx, sig->sig, sizeof(sig->sig), evp_key) != 1) {
ret = openssl_err("Could not verify signature");
goto err_ctx;
}
if (!strcmp(e->name, "a38x")) {
FILE *out = fopen("kwb_fuses_a38x.txt", "w+");
+ if (!out) {
+ fprintf(stderr, "Couldn't open eFuse settings: '%s': %s\n",
+ "kwb_fuses_a38x.txt", strerror(errno));
+ return -ENOENT;
+ }
+
kwb_dump_fuse_cmds_38x(out, sec_hdr);
fclose(out);
goto done;
return ret;
}
-#endif
-
static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
int payloadsz)
{
headersz += sizeof(struct ext_hdr_v0);
}
- if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
- fprintf(stderr, "More than one payload, not possible\n");
- return NULL;
- }
-
image = malloc(headersz);
if (!image) {
fprintf(stderr, "Cannot allocate memory for image\n");
/* Fill in the main header */
main_hdr->blocksize =
- cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
+ cpu_to_le32(payloadsz - headersz);
main_hdr->srcaddr = cpu_to_le32(headersz);
main_hdr->ext = has_ext;
+ main_hdr->version = 0;
main_hdr->destaddr = cpu_to_le32(params->addr);
main_hdr->execaddr = cpu_to_le32(params->ep);
+ main_hdr->blockid = image_get_bootfrom();
- e = image_find_option(IMAGE_CFG_BOOT_FROM);
- if (e)
- main_hdr->blockid = e->bootfrom;
e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
if (e)
main_hdr->nandeccmode = e->nandeccmode;
static size_t image_headersz_v1(int *hasext)
{
struct image_cfg_element *binarye;
+ unsigned int count;
size_t headersz;
+ int cfgi;
/*
* Calculate the size of the header and the size of the
*/
headersz = sizeof(struct main_hdr_v1);
- if (image_count_options(IMAGE_CFG_BINARY) > 1) {
- fprintf(stderr, "More than one binary blob, not supported\n");
- return 0;
+ if (image_get_csk_index() >= 0) {
+ headersz += sizeof(struct secure_hdr_v1);
+ if (hasext)
+ *hasext = 1;
}
- if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
- fprintf(stderr, "More than one payload, not possible\n");
- return 0;
- }
+ count = image_count_options(IMAGE_CFG_DATA);
+ if (count > 0)
+ headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
- binarye = image_find_option(IMAGE_CFG_BINARY);
- if (binarye) {
+ for (cfgi = 0; cfgi < cfgn; cfgi++) {
int ret;
struct stat s;
+ binarye = &image_cfg[cfgi];
+ if (binarye->type != IMAGE_CFG_BINARY)
+ continue;
+
ret = stat(binarye->binary.file, &s);
if (ret < 0) {
char cwd[PATH_MAX];
fprintf(stderr,
"Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
"This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
- "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
+ "image for your board. Use 'dumpimage -T kwbimage -p 0' to extract it from an existing image.\n",
binarye->binary.file, dir);
return 0;
}
- headersz += sizeof(struct opt_hdr_v1) +
- s.st_size +
- (binarye->binary.nargs + 2) * sizeof(uint32_t);
+ headersz += sizeof(struct opt_hdr_v1) + sizeof(uint32_t) +
+ (binarye->binary.nargs) * sizeof(uint32_t);
+ headersz = ALIGN(headersz, 16);
+ headersz += ALIGN(s.st_size, 4) + sizeof(uint32_t);
if (hasext)
*hasext = 1;
}
-#if defined(CONFIG_KWB_SECURE)
- if (image_get_csk_index() >= 0) {
- headersz += sizeof(struct secure_hdr_v1);
- if (hasext)
- *hasext = 1;
- }
-#endif
-
-#if defined(CONFIG_SYS_U_BOOT_OFFS)
- if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
- fprintf(stderr,
- "Error: Image header (incl. SPL image) too big!\n");
- fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
- (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
- fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
- return 0;
- }
-
- headersz = CONFIG_SYS_U_BOOT_OFFS;
-#endif
-
/*
* The payload should be aligned on some reasonable
* boundary
*/
- return ALIGN_SUP(headersz, 4096);
+ return ALIGN(headersz, 4096);
}
-int add_binary_header_v1(uint8_t *cur)
+int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
+ struct image_cfg_element *binarye,
+ struct main_hdr_v1 *main_hdr)
{
- struct image_cfg_element *binarye;
- struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;
+ struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)*cur;
+ uint32_t add_args;
+ uint32_t offset;
uint32_t *args;
size_t binhdrsz;
struct stat s;
FILE *bin;
int ret;
- binarye = image_find_option(IMAGE_CFG_BINARY);
-
- if (!binarye)
- return 0;
-
hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
bin = fopen(binarye->binary.file, "r");
goto err_close;
}
- binhdrsz = sizeof(struct opt_hdr_v1) +
- (binarye->binary.nargs + 2) * sizeof(uint32_t) +
- s.st_size;
-
- /*
- * The size includes the binary image size, rounded
- * up to a 4-byte boundary. Plus 4 bytes for the
- * next-header byte and 3-byte alignment at the end.
- */
- binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
- hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
- hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
-
- cur += sizeof(struct opt_hdr_v1);
+ *cur += sizeof(struct opt_hdr_v1);
- args = (uint32_t *)cur;
+ args = (uint32_t *)*cur;
*args = cpu_to_le32(binarye->binary.nargs);
args++;
for (argi = 0; argi < binarye->binary.nargs; argi++)
args[argi] = cpu_to_le32(binarye->binary.args[argi]);
- cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
+ *cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
- ret = fread(cur, s.st_size, 1, bin);
+ /*
+ * ARM executable code inside the BIN header on some mvebu platforms
+ * (e.g. A370, AXP) must always be aligned with the 128-bit boundary.
+ * This requirement can be met by inserting dummy arguments into
+ * BIN header, if needed.
+ */
+ offset = *cur - (uint8_t *)main_hdr;
+ add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t);
+ if (add_args) {
+ *(args - 1) = cpu_to_le32(binarye->binary.nargs + add_args);
+ *cur += add_args * sizeof(uint32_t);
+ }
+
+ ret = fread(*cur, s.st_size, 1, bin);
if (ret != 1) {
fprintf(stderr,
"Could not read binary image %s\n",
fclose(bin);
- cur += ALIGN_SUP(s.st_size, 4);
+ *cur += ALIGN(s.st_size, 4);
- /*
- * For now, we don't support more than one binary
- * header, and no other header types are
- * supported. So, the binary header is necessarily the
- * last one
- */
- *((uint32_t *)cur) = 0x00000000;
+ *((uint32_t *)*cur) = 0x00000000;
+ **next_ext = 1;
+ *next_ext = *cur;
+
+ *cur += sizeof(uint32_t);
- cur += sizeof(uint32_t);
+ binhdrsz = sizeof(struct opt_hdr_v1) +
+ (binarye->binary.nargs + add_args + 2) * sizeof(uint32_t) +
+ ALIGN(s.st_size, 4);
+ hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
+ hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
return 0;
return -1;
}
-#if defined(CONFIG_KWB_SECURE)
-
int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr)
{
FILE *hashf;
int res;
hashf = fopen("pub_kak_hash.txt", "w");
+ if (!hashf) {
+ fprintf(stderr, "Couldn't open hash file: '%s': %s\n",
+ "pub_kak_hash.txt", strerror(errno));
+ return 1;
+ }
res = kwb_export_pubkey(kak, &secure_hdr->kak, hashf, "KAK");
int csk_idx = image_get_csk_index();
struct sig_v1 tmp_sig;
- if (csk_idx >= 16) {
+ if (csk_idx < 0 || csk_idx > 15) {
fprintf(stderr, "Invalid CSK index %d\n", csk_idx);
return 1;
}
return 0;
}
-#endif
static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
uint8_t *ptr, int payloadsz)
{
struct image_cfg_element *e;
struct main_hdr_v1 *main_hdr;
-#if defined(CONFIG_KWB_SECURE)
+ struct register_set_hdr_v1 *register_set_hdr;
struct secure_hdr_v1 *secure_hdr = NULL;
-#endif
size_t headersz;
uint8_t *image, *cur;
int hasext = 0;
uint8_t *next_ext = NULL;
+ int cfgi, datai, size;
/*
* Calculate the size of the header and the size of the
/* Fill the main header */
main_hdr->blocksize =
- cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
+ cpu_to_le32(payloadsz - headersz);
main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
- main_hdr->destaddr = cpu_to_le32(params->addr)
- - sizeof(image_header_t);
+ main_hdr->destaddr = cpu_to_le32(params->addr);
main_hdr->execaddr = cpu_to_le32(params->ep);
main_hdr->srcaddr = cpu_to_le32(headersz);
main_hdr->ext = hasext;
main_hdr->version = 1;
- e = image_find_option(IMAGE_CFG_BOOT_FROM);
- if (e)
- main_hdr->blockid = e->bootfrom;
+ main_hdr->blockid = image_get_bootfrom();
+
e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
if (e)
main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
+ e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
+ if (e)
+ main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
if (e)
main_hdr->nandbadblklocation = e->nandbadblklocation;
e = image_find_option(IMAGE_CFG_BAUDRATE);
if (e)
- main_hdr->options = baudrate_to_option(e->baudrate);
+ main_hdr->options |= baudrate_to_option(e->baudrate);
+ e = image_find_option(IMAGE_CFG_UART_PORT);
+ if (e)
+ main_hdr->options |= (e->uart_port & 3) << 3;
+ e = image_find_option(IMAGE_CFG_UART_MPP);
+ if (e)
+ main_hdr->options |= (e->uart_mpp & 7) << 5;
e = image_find_option(IMAGE_CFG_DEBUG);
if (e)
main_hdr->flags = e->debug ? 0x1 : 0;
- e = image_find_option(IMAGE_CFG_BINARY);
- if (e) {
- char *s = strrchr(e->binary.file, '/');
- if (strcmp(s, "/binary.0") == 0)
- main_hdr->destaddr = cpu_to_le32(params->addr);
- }
+ /*
+ * For SATA srcaddr is specified in number of sectors starting from
+ * sector 0. The main header is stored at sector number 1.
+ * This expects the sector size to be 512 bytes.
+ * Header size is already aligned.
+ */
+ if (main_hdr->blockid == IBR_HDR_SATA_ID)
+ main_hdr->srcaddr = cpu_to_le32(headersz / 512 + 1);
+
+ /*
+ * For SDIO srcaddr is specified in number of sectors starting from
+ * sector 0. The main header is stored at sector number 0.
+ * This expects sector size to be 512 bytes.
+ * Header size is already aligned.
+ */
+ if (main_hdr->blockid == IBR_HDR_SDIO_ID)
+ main_hdr->srcaddr = cpu_to_le32(headersz / 512);
+
+ /* For PCIe srcaddr is not used and must be set to 0xFFFFFFFF. */
+ if (main_hdr->blockid == IBR_HDR_PEX_ID)
+ main_hdr->srcaddr = cpu_to_le32(0xFFFFFFFF);
-#if defined(CONFIG_KWB_SECURE)
if (image_get_csk_index() >= 0) {
/*
* only reserve the space here; we fill the header later since
*/
secure_hdr = (struct secure_hdr_v1 *)cur;
cur += sizeof(struct secure_hdr_v1);
+ *next_ext = 1;
next_ext = &secure_hdr->next;
}
-#endif
- *next_ext = 1;
- if (add_binary_header_v1(cur))
- return NULL;
+ datai = 0;
+ register_set_hdr = (struct register_set_hdr_v1 *)cur;
+ for (cfgi = 0; cfgi < cfgn; cfgi++) {
+ e = &image_cfg[cfgi];
+ if (e->type != IMAGE_CFG_DATA &&
+ e->type != IMAGE_CFG_DATA_DELAY)
+ continue;
+ if (e->type == IMAGE_CFG_DATA_DELAY) {
+ size = sizeof(struct register_set_hdr_v1) + 8 * datai + 4;
+ register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE;
+ register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF);
+ register_set_hdr->headersz_msb = size >> 16;
+ register_set_hdr->data[datai].last_entry.delay = e->regdata_delay;
+ cur += size;
+ *next_ext = 1;
+ next_ext = ®ister_set_hdr->data[datai].last_entry.next;
+ datai = 0;
+ continue;
+ }
+ register_set_hdr->data[datai].entry.address =
+ cpu_to_le32(e->regdata.raddr);
+ register_set_hdr->data[datai].entry.value =
+ cpu_to_le32(e->regdata.rdata);
+ datai++;
+ }
+ if (datai != 0) {
+ size = sizeof(struct register_set_hdr_v1) + 8 * datai + 4;
+ register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE;
+ register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF);
+ register_set_hdr->headersz_msb = size >> 16;
+ /* Set delay to the smallest possible value 1ms. */
+ register_set_hdr->data[datai].last_entry.delay = 1;
+ cur += size;
+ *next_ext = 1;
+ next_ext = ®ister_set_hdr->data[datai].last_entry.next;
+ }
+
+ for (cfgi = 0; cfgi < cfgn; cfgi++) {
+ e = &image_cfg[cfgi];
+ if (e->type != IMAGE_CFG_BINARY)
+ continue;
+
+ if (add_binary_header_v1(&cur, &next_ext, e, main_hdr))
+ return NULL;
+ }
-#if defined(CONFIG_KWB_SECURE)
if (secure_hdr && add_secure_header_v1(params, ptr, payloadsz,
headersz, image, secure_hdr))
return NULL;
-#endif
/* Calculate and set the header checksum */
main_hdr->checksum = image_checksum8(main_hdr, headersz);
el->regdata.raddr = strtoul(value1, NULL, 16);
el->regdata.rdata = strtoul(value2, NULL, 16);
break;
+ case IMAGE_CFG_DATA_DELAY:
+ if (!strcmp(value1, "SDRAM_SETUP"))
+ el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_SDRAM_SETUP;
+ else
+ el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_MS(strtoul(value1, NULL, 10));
+ break;
case IMAGE_CFG_BAUDRATE:
el->baudrate = strtoul(value1, NULL, 10);
break;
+ case IMAGE_CFG_UART_PORT:
+ el->uart_port = strtoul(value1, NULL, 16);
+ break;
+ case IMAGE_CFG_UART_MPP:
+ el->uart_mpp = strtoul(value1, NULL, 16);
+ break;
case IMAGE_CFG_DEBUG:
el->debug = strtoul(value1, NULL, 10);
break;
size_t headersz = 0;
uint32_t checksum;
int ret;
- int size;
fcfg = fopen(params->imagename, "r");
if (!fcfg) {
exit(EXIT_FAILURE);
}
- /* The MVEBU BootROM does not allow non word aligned payloads */
- sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
-
version = image_get_version();
switch (version) {
/*
free(image_cfg);
/* Build and add image checksum header */
- checksum =
- cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
- size = write(ifd, &checksum, sizeof(uint32_t));
- if (size != sizeof(uint32_t)) {
- fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
- params->cmdname, size, params->imagefile);
- exit(EXIT_FAILURE);
- }
-
- sbuf->st_size += sizeof(uint32_t);
+ checksum = cpu_to_le32(image_checksum32((uint8_t *)ptr + headersz,
+ sbuf->st_size - headersz - sizeof(uint32_t)));
+ memcpy((uint8_t *)ptr + sbuf->st_size - sizeof(uint32_t), &checksum,
+ sizeof(uint32_t));
/* Finally copy the header into the image area */
memcpy(ptr, image, headersz);
static void kwbimage_print_header(const void *ptr)
{
struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
+ struct opt_hdr_v1 *ohdr;
printf("Image Type: MVEBU Boot from %s Image\n",
image_boot_mode_name(mhdr->blockid));
- printf("Image version:%d\n", image_version((void *)ptr));
+ printf("Image version:%d\n", kwbimage_version(ptr));
+
+ for_each_opt_hdr_v1 (ohdr, mhdr) {
+ if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
+ printf("BIN Hdr Size: ");
+ genimg_print_size(opt_hdr_v1_size(ohdr) - 12 -
+ 4 * ohdr->data[0]);
+ }
+ }
+
printf("Data Size: ");
genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
printf("Load Address: %08x\n", mhdr->destaddr);
static int kwbimage_verify_header(unsigned char *ptr, int image_size,
struct image_tool_params *params)
{
- uint8_t checksum;
- size_t header_size = kwbimage_header_size(ptr);
+ size_t header_size = kwbheader_size(ptr);
+ uint8_t csum;
if (header_size > image_size)
return -FDT_ERR_BADSTRUCTURE;
return -FDT_ERR_BADSTRUCTURE;
/* Only version 0 extended header has checksum */
- if (image_version((void *)ptr) == 0) {
- struct ext_hdr_v0 *ext_hdr;
+ if (kwbimage_version(ptr) == 0) {
+ struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
- ext_hdr = (struct ext_hdr_v0 *)
- (ptr + sizeof(struct main_hdr_v0));
- checksum = image_checksum8(ext_hdr,
- sizeof(struct ext_hdr_v0)
- - sizeof(uint8_t));
- if (checksum != ext_hdr->checksum)
+ if (mhdr->ext & 0x1) {
+ struct ext_hdr_v0 *ext_hdr = (void *)(mhdr + 1);
+
+ csum = image_checksum8(ext_hdr, sizeof(*ext_hdr) - 1);
+ if (csum != ext_hdr->checksum)
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } else if (kwbimage_version(ptr) == 1) {
+ struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
+ const uint8_t *mhdr_end;
+ struct opt_hdr_v1 *ohdr;
+ uint32_t offset;
+ uint32_t size;
+
+ mhdr_end = (uint8_t *)mhdr + header_size;
+ for_each_opt_hdr_v1 (ohdr, ptr)
+ if (!opt_hdr_v1_valid_size(ohdr, mhdr_end))
+ return -FDT_ERR_BADSTRUCTURE;
+
+ offset = le32_to_cpu(mhdr->srcaddr);
+
+ /*
+ * For SATA srcaddr is specified in number of sectors.
+ * The main header is must be stored at sector number 1.
+ * This expects that sector size is 512 bytes and recalculates
+ * data offset to bytes relative to the main header.
+ */
+ if (mhdr->blockid == IBR_HDR_SATA_ID) {
+ if (offset < 1)
+ return -FDT_ERR_BADSTRUCTURE;
+ offset -= 1;
+ offset *= 512;
+ }
+
+ /*
+ * For SDIO srcaddr is specified in number of sectors.
+ * This expects that sector size is 512 bytes and recalculates
+ * data offset to bytes.
+ */
+ if (mhdr->blockid == IBR_HDR_SDIO_ID)
+ offset *= 512;
+
+ /*
+ * For PCIe srcaddr is always set to 0xFFFFFFFF.
+ * This expects that data starts after all headers.
+ */
+ if (mhdr->blockid == IBR_HDR_PEX_ID && offset == 0xFFFFFFFF)
+ offset = header_size;
+
+ if (offset > image_size || offset % 4 != 0)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ size = le32_to_cpu(mhdr->blocksize);
+ if (size < 4 || offset + size > image_size || size % 4 != 0)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ if (image_checksum32(ptr + offset, size - 4) !=
+ *(uint32_t *)(ptr + offset + size - 4))
return -FDT_ERR_BADSTRUCTURE;
+ } else {
+ return -FDT_ERR_BADSTRUCTURE;
}
return 0;
struct image_type_params *tparams)
{
FILE *fcfg;
+ struct stat s;
int alloc_len;
+ int bootfrom;
int version;
void *hdr;
int ret;
exit(EXIT_FAILURE);
}
+ if (stat(params->datafile, &s)) {
+ fprintf(stderr, "Could not stat data file %s: %s\n",
+ params->datafile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
sizeof(struct image_cfg_element));
if (!image_cfg) {
exit(EXIT_FAILURE);
}
+ bootfrom = image_get_bootfrom();
version = image_get_version();
switch (version) {
/*
/*
* The resulting image needs to be 4-byte aligned. At least
* the Marvell hdrparser tool complains if its unaligned.
- * By returning 1 here in this function, called via
- * tparams->vrec_header() in mkimage.c, mkimage will
- * automatically pad the the resulting image to a 4-byte
- * size if necessary.
+ * After the image data is stored 4-byte checksum.
+ * Final SPI and NAND images must be aligned to 256 bytes.
+ * Final SATA and SDIO images must be aligned to 512 bytes.
*/
- return 1;
+ if (bootfrom == IBR_HDR_SPI_ID || bootfrom == IBR_HDR_NAND_ID)
+ return 4 + (256 - (alloc_len + s.st_size + 4) % 256) % 256;
+ else if (bootfrom == IBR_HDR_SATA_ID || bootfrom == IBR_HDR_SDIO_ID)
+ return 4 + (512 - (alloc_len + s.st_size + 4) % 512) % 512;
+ else
+ return 4 + (4 - s.st_size % 4) % 4;
+}
+
+static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params)
+{
+ struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
+ size_t header_size = kwbheader_size(ptr);
+ struct opt_hdr_v1 *ohdr;
+ int idx = params->pflag;
+ int cur_idx = 0;
+ uint32_t offset;
+ ulong image;
+ ulong size;
+
+ for_each_opt_hdr_v1 (ohdr, ptr) {
+ if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE)
+ continue;
+
+ if (idx == cur_idx) {
+ image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]];
+ size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0];
+ goto extract;
+ }
+
+ ++cur_idx;
+ }
+
+ if (idx != cur_idx) {
+ printf("Image %d is not present\n", idx);
+ return -1;
+ }
+
+ offset = le32_to_cpu(mhdr->srcaddr);
+
+ if (mhdr->blockid == IBR_HDR_SATA_ID) {
+ offset -= 1;
+ offset *= 512;
+ }
+
+ if (mhdr->blockid == IBR_HDR_SDIO_ID)
+ offset *= 512;
+
+ if (mhdr->blockid == IBR_HDR_PEX_ID && offset == 0xFFFFFFFF)
+ offset = header_size;
+
+ image = (ulong)((uint8_t *)ptr + offset);
+ size = le32_to_cpu(mhdr->blocksize) - 4;
+
+extract:
+ return imagetool_save_subimage(params->outfile, image, size);
}
/*
*/
static int kwbimage_check_params(struct image_tool_params *params)
{
- if (!strlen(params->imagename)) {
+ if (!params->iflag && (!params->imagename || !strlen(params->imagename))) {
char *msg = "Configuration file for kwbimage creation omitted";
fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
return (params->dflag && (params->fflag || params->lflag)) ||
(params->fflag && (params->dflag || params->lflag)) ||
(params->lflag && (params->dflag || params->fflag)) ||
- (params->xflag) || !(strlen(params->imagename));
+ (params->xflag);
}
/*
kwbimage_verify_header,
kwbimage_print_header,
kwbimage_set_header,
- NULL,
+ kwbimage_extract_subimage,
kwbimage_check_image_types,
NULL,
kwbimage_generate