*/
#include "imagetool.h"
+#include <limits.h>
#include <image.h>
#include <stdint.h>
#include "kwbimage.h"
-#define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
-
-/* Structure of the main header, version 0 (Kirkwood, Dove) */
-struct main_hdr_v0 {
- uint8_t blockid; /*0 */
- uint8_t nandeccmode; /*1 */
- uint16_t nandpagesize; /*2-3 */
- uint32_t blocksize; /*4-7 */
- uint32_t rsvd1; /*8-11 */
- uint32_t srcaddr; /*12-15 */
- uint32_t destaddr; /*16-19 */
- uint32_t execaddr; /*20-23 */
- uint8_t satapiomode; /*24 */
- uint8_t rsvd3; /*25 */
- uint16_t ddrinitdelay; /*26-27 */
- uint16_t rsvd2; /*28-29 */
- uint8_t ext; /*30 */
- uint8_t checksum; /*31 */
-};
-
-struct ext_hdr_v0_reg {
- uint32_t raddr;
- uint32_t rdata;
-};
-
-#define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
-
-struct ext_hdr_v0 {
- uint32_t offset;
- uint8_t reserved[0x20 - sizeof(uint32_t)];
- struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
- uint8_t reserved2[7];
- uint8_t checksum;
-};
-
-/* Structure of the main header, version 1 (Armada 370, Armada XP) */
-struct main_hdr_v1 {
- uint8_t blockid; /* 0 */
- uint8_t reserved1; /* 1 */
- uint16_t reserved2; /* 2-3 */
- uint32_t blocksize; /* 4-7 */
- uint8_t version; /* 8 */
- uint8_t headersz_msb; /* 9 */
- uint16_t headersz_lsb; /* A-B */
- uint32_t srcaddr; /* C-F */
- uint32_t destaddr; /* 10-13 */
- uint32_t execaddr; /* 14-17 */
- uint8_t reserved3; /* 18 */
- uint8_t nandblocksize; /* 19 */
- uint8_t nandbadblklocation; /* 1A */
- uint8_t reserved4; /* 1B */
- uint16_t reserved5; /* 1C-1D */
- uint8_t ext; /* 1E */
- uint8_t checksum; /* 1F */
-};
-
-/*
- * Header for the optional headers, version 1 (Armada 370, Armada XP)
- */
-struct opt_hdr_v1 {
- uint8_t headertype;
- uint8_t headersz_msb;
- uint16_t headersz_lsb;
- char data[0];
-};
-
-/*
- * Various values for the opt_hdr_v1->headertype field, describing the
- * different types of optional headers. The "secure" header contains
- * informations related to secure boot (encryption keys, etc.). The
- * "binary" header contains ARM binary code to be executed prior to
- * executing the main payload (usually the bootloader). This is
- * typically used to execute DDR3 training code. The "register" header
- * allows to describe a set of (address, value) tuples that are
- * generally used to configure the DRAM controller.
- */
-#define OPT_HDR_V1_SECURE_TYPE 0x1
-#define OPT_HDR_V1_BINARY_TYPE 0x2
-#define OPT_HDR_V1_REGISTER_TYPE 0x3
-
-#define KWBHEADER_V1_SIZE(hdr) \
- (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
-
static struct image_cfg_element *image_cfg;
static int cfgn;
{ 0x78, "sata" },
{ 0x9C, "pex" },
{ 0x69, "uart" },
+ { 0xAE, "sdio" },
{},
};
#define IMAGE_CFG_ELEMENT_MAX 256
-/*
- * Byte 8 of the image header contains the version number. In the v0
- * header, byte 8 was reserved, and always set to 0. In the v1 header,
- * byte 8 has been changed to a proper field, set to 1.
- */
-static unsigned int image_version(void *header)
-{
- unsigned char *ptr = header;
- return ptr[8];
-}
-
/*
* Utility functions to manipulate boot mode and ecc modes (convert
* them back and forth between description strings and the
main_hdr = image;
/* Fill in the main header */
- main_hdr->blocksize = payloadsz + sizeof(uint32_t);
- main_hdr->srcaddr = headersz;
+ main_hdr->blocksize =
+ cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
+ main_hdr->srcaddr = cpu_to_le32(headersz);
main_hdr->ext = has_ext;
- main_hdr->destaddr = params->addr;
- main_hdr->execaddr = params->ep;
+ main_hdr->destaddr = cpu_to_le32(params->addr);
+ main_hdr->execaddr = cpu_to_le32(params->ep);
e = image_find_option(IMAGE_CFG_BOOT_FROM);
if (e)
main_hdr->nandeccmode = e->nandeccmode;
e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
if (e)
- main_hdr->nandpagesize = e->nandpagesz;
+ main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
main_hdr->checksum = image_checksum8(image,
sizeof(struct main_hdr_v0));
int cfgi, datai;
ext_hdr = image + sizeof(struct main_hdr_v0);
- ext_hdr->offset = 0x40;
+ ext_hdr->offset = cpu_to_le32(0x40);
for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
e = &image_cfg[cfgi];
if (e->type != IMAGE_CFG_DATA)
continue;
- ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
- ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
+ ext_hdr->rcfg[datai].raddr =
+ cpu_to_le32(e->regdata.raddr);
+ ext_hdr->rcfg[datai].rdata =
+ cpu_to_le32(e->regdata.rdata);
datai++;
}
ret = stat(binarye->binary.file, &s);
if (ret < 0) {
- char *cwd = get_current_dir_name();
+ char cwd[PATH_MAX];
+ char *dir = cwd;
+
+ memset(cwd, 0, sizeof(cwd));
+ if (!getcwd(cwd, sizeof(cwd))) {
+ dir = "current working directory";
+ perror("getcwd() failed");
+ }
+
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",
- binarye->binary.file, cwd);
- free(cwd);
+ binarye->binary.file, dir);
return 0;
}
- headersz += s.st_size +
- binarye->binary.nargs * sizeof(unsigned int);
+ headersz += sizeof(struct opt_hdr_v1) +
+ s.st_size +
+ (binarye->binary.nargs + 2) * sizeof(uint32_t);
if (hasext)
*hasext = 1;
}
+#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;
+ } else {
+ headersz = CONFIG_SYS_U_BOOT_OFFS;
+ }
+#endif
+
/*
* The payload should be aligned on some reasonable
* boundary
cur += sizeof(struct main_hdr_v1);
/* Fill the main header */
- main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t);
- main_hdr->headersz_lsb = headersz & 0xFFFF;
+ main_hdr->blocksize =
+ cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
+ main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
- main_hdr->destaddr = params->addr;
- main_hdr->execaddr = params->ep;
- main_hdr->srcaddr = headersz;
+ 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);
binarye = image_find_option(IMAGE_CFG_BINARY);
if (binarye) {
struct opt_hdr_v1 *hdr = cur;
- unsigned int *args;
+ uint32_t *args;
size_t binhdrsz;
struct stat s;
int argi;
fstat(fileno(bin), &s);
binhdrsz = sizeof(struct opt_hdr_v1) +
- (binarye->binary.nargs + 1) * sizeof(unsigned int) +
+ (binarye->binary.nargs + 2) * sizeof(uint32_t) +
s.st_size;
- hdr->headersz_lsb = binhdrsz & 0xFFFF;
+
+ /*
+ * 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);
args = cur;
- *args = binarye->binary.nargs;
+ *args = cpu_to_le32(binarye->binary.nargs);
args++;
for (argi = 0; argi < binarye->binary.nargs; argi++)
- args[argi] = binarye->binary.args[argi];
+ args[argi] = cpu_to_le32(binarye->binary.args[argi]);
- cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
+ cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
ret = fread(cur, s.st_size, 1, bin);
if (ret != 1) {
fclose(bin);
- cur += s.st_size;
+ cur += ALIGN_SUP(s.st_size, 4);
/*
* For now, we don't support more than one binary
* supported. So, the binary header is necessarily the
* last one
*/
- *((unsigned char *)cur) = 0;
+ *((uint32_t *)cur) = 0x00000000;
cur += sizeof(uint32_t);
}
el->version = atoi(value);
} else if (!strcmp(keyword, "BOOT_FROM")) {
char *value = strtok_r(NULL, deliminiters, &saveptr);
- el->type = IMAGE_CFG_BOOT_FROM;
- el->bootfrom = image_boot_mode_id(value);
- if (el->bootfrom < 0) {
+ int ret = image_boot_mode_id(value);
+ if (ret < 0) {
fprintf(stderr,
"Invalid boot media '%s'\n", value);
return -1;
}
+ el->type = IMAGE_CFG_BOOT_FROM;
+ el->bootfrom = ret;
} else if (!strcmp(keyword, "NAND_BLKSZ")) {
char *value = strtok_r(NULL, deliminiters, &saveptr);
el->type = IMAGE_CFG_NAND_BLKSZ;
strtoul(value, NULL, 16);
} else if (!strcmp(keyword, "NAND_ECC_MODE")) {
char *value = strtok_r(NULL, deliminiters, &saveptr);
- el->type = IMAGE_CFG_NAND_ECC_MODE;
- el->nandeccmode = image_nand_ecc_mode_id(value);
- if (el->nandeccmode < 0) {
+ int ret = image_nand_ecc_mode_id(value);
+ if (ret < 0) {
fprintf(stderr,
"Invalid NAND ECC mode '%s'\n", value);
return -1;
}
+ el->type = IMAGE_CFG_NAND_ECC_MODE;
+ el->nandeccmode = ret;
} else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
char *value = strtok_r(NULL, deliminiters, &saveptr);
el->type = IMAGE_CFG_NAND_PAGESZ;
FILE *fcfg;
void *image = NULL;
int version;
- size_t headersz;
+ size_t headersz = 0;
uint32_t checksum;
int ret;
int size;
exit(EXIT_FAILURE);
}
- version = image_get_version();
- /* Fallback to version 0 is no version is provided in the cfg file */
- if (version == -1)
- version = 0;
+ /* The MVEBU BootROM does not allow non word aligned payloads */
+ sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
- if (version == 0)
+ version = image_get_version();
+ switch (version) {
+ /*
+ * Fallback to version 0 if no version is provided in the
+ * cfg file
+ */
+ case -1:
+ case 0:
image = image_create_v0(&headersz, params, sbuf->st_size);
- else if (version == 1)
+ break;
+
+ case 1:
image = image_create_v1(&headersz, params, sbuf->st_size);
+ break;
+
+ default:
+ fprintf(stderr, "Unsupported version %d\n", version);
+ free(image_cfg);
+ exit(EXIT_FAILURE);
+ }
if (!image) {
fprintf(stderr, "Could not create image\n");
free(image_cfg);
/* Build and add image checksum header */
- checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
+ 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",
printf("Image Type: MVEBU Boot from %s Image\n",
image_boot_mode_name(mhdr->blockid));
- printf("Data Size: ");
printf("Image version:%d\n", image_version((void *)ptr));
+ printf("Data Size: ");
genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
printf("Load Address: %08x\n", mhdr->destaddr);
printf("Entry Point: %08x\n", mhdr->execaddr);
main_hdr = (void *)ptr;
checksum = image_checksum8(ptr,
- sizeof(struct main_hdr_v0));
+ sizeof(struct main_hdr_v0)
+ - sizeof(uint8_t));
if (checksum != main_hdr->checksum)
return -FDT_ERR_BADSTRUCTURE;
if (image_version((void *)ptr) == 0) {
ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
checksum = image_checksum8(ext_hdr,
- sizeof(struct ext_hdr_v0));
+ sizeof(struct ext_hdr_v0)
+ - sizeof(uint8_t));
if (checksum != ext_hdr->checksum)
return -FDT_ERR_BADSTRUCTURE;
}
tparams->header_size = alloc_len;
tparams->hdr = hdr;
- return 0;
+ /*
+ * 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.
+ */
+ return 1;
}
/*
/*
* kwbimage type parameters definition
*/
-static struct image_type_params kwbimage_params = {
- .name = "Marvell MVEBU Boot Image support",
- .header_size = 0, /* no fixed header size */
- .hdr = NULL,
- .vrec_header = kwbimage_generate,
- .check_image_type = kwbimage_check_image_types,
- .verify_header = kwbimage_verify_header,
- .print_header = kwbimage_print_header,
- .set_header = kwbimage_set_header,
- .check_params = kwbimage_check_params,
-};
-
-void init_kwb_image_type (void)
-{
- register_image_type(&kwbimage_params);
-}
+U_BOOT_IMAGE_TYPE(
+ kwbimage,
+ "Marvell MVEBU Boot Image support",
+ 0,
+ NULL,
+ kwbimage_check_params,
+ kwbimage_verify_header,
+ kwbimage_print_header,
+ kwbimage_set_header,
+ NULL,
+ kwbimage_check_image_types,
+ NULL,
+ kwbimage_generate
+);