// 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
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_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",
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 e->sec_specialized_img;
}
+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
* the requirements of the Marvell SoC BootROM specifications.
return csum;
}
-size_t kwbimage_header_size(unsigned char *ptr)
-{
- if (kwbimage_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.
*/
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;
*/
headersz = sizeof(struct main_hdr_v1);
+ if (image_get_csk_index() >= 0) {
+ headersz += sizeof(struct secure_hdr_v1);
+ if (hasext)
+ *hasext = 1;
+ }
+
count = image_count_options(IMAGE_CFG_DATA);
if (count > 0)
headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
return 0;
}
- headersz += sizeof(struct opt_hdr_v1) +
- ALIGN(s.st_size, 4) +
- (binarye->binary.nargs + 2) * sizeof(uint32_t);
- if (hasext)
- *hasext = 1;
- }
-
- if (image_get_csk_index() >= 0) {
- headersz += sizeof(struct secure_hdr_v1);
+ 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;
}
}
int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
- struct image_cfg_element *binarye)
+ struct image_cfg_element *binarye,
+ struct main_hdr_v1 *main_hdr)
{
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;
goto err_close;
}
- binhdrsz = sizeof(struct opt_hdr_v1) +
- (binarye->binary.nargs + 2) * sizeof(uint32_t) +
- ALIGN(s.st_size, 4);
- hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
- hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
-
*cur += sizeof(struct opt_hdr_v1);
args = (uint32_t *)*cur;
*cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
+ /*
+ * 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,
*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;
err_close:
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;
if (e->type != IMAGE_CFG_BINARY)
continue;
- if (add_binary_header_v1(&cur, &next_ext, e))
+ if (add_binary_header_v1(&cur, &next_ext, e, main_hdr))
return NULL;
}
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;
return e->version;
}
-static int image_get_bootfrom(void)
-{
- struct image_cfg_element *e;
-
- e = image_find_option(IMAGE_CFG_BOOT_FROM);
- if (!e)
- return -1;
-
- return e->bootfrom;
-}
-
static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
struct image_tool_params *params)
{
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;
struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
if (mhdr->ext & 0x1) {
- struct ext_hdr_v0 *ext_hdr;
-
- if (header_size + sizeof(*ext_hdr) > image_size)
- return -FDT_ERR_BADSTRUCTURE;
+ struct ext_hdr_v0 *ext_hdr = (void *)(mhdr + 1);
- 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)
+ csum = image_checksum8(ext_hdr, sizeof(*ext_hdr) - 1);
+ if (csum != ext_hdr->checksum)
return -FDT_ERR_BADSTRUCTURE;
}
} else if (kwbimage_version(ptr) == 1) {
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 = kwbimage_header_size(ptr);
+ size_t header_size = kwbheader_size(ptr);
struct opt_hdr_v1 *ohdr;
int idx = params->pflag;
int cur_idx = 0;