X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=inline;f=tools%2Fkwbimage.c;h=369aba7bcab9d00e6c965354ff05bb579d420809;hb=dede284d1ce9f9d9e79a5114fe7eb814fec07679;hp=1120e9b3729024fc851ddba5a3410dcc92cf29d1;hpb=03a3536c7b7f2902932606da9248c6f08318174a;p=u-boot diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 1120e9b372..369aba7bca 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -12,93 +12,11 @@ */ #include "imagetool.h" +#include #include #include #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; @@ -114,6 +32,7 @@ struct boot_mode boot_modes[] = { { 0x78, "sata" }, { 0x9C, "pex" }, { 0x69, "uart" }, + { 0xAE, "sdio" }, {}, }; @@ -171,17 +90,6 @@ struct image_cfg_element { #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 @@ -324,11 +232,12 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, 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) @@ -338,7 +247,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, 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)); @@ -347,15 +256,17 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, 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++; } @@ -396,22 +307,42 @@ static size_t image_headersz_v1(struct image_tool_params *params, 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 @@ -449,12 +380,13 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, 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); @@ -470,7 +402,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, 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; @@ -488,20 +420,27 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, 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) { @@ -513,7 +452,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, fclose(bin); - cur += s.st_size; + cur += ALIGN_SUP(s.st_size, 4); /* * For now, we don't support more than one binary @@ -521,7 +460,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, * supported. So, the binary header is necessarily the * last one */ - *((unsigned char *)cur) = 0; + *((uint32_t *)cur) = 0x00000000; cur += sizeof(uint32_t); } @@ -546,13 +485,14 @@ static int image_create_config_parse_oneline(char *line, 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; @@ -564,13 +504,14 @@ static int image_create_config_parse_oneline(char *line, 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; @@ -720,7 +661,7 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd, FILE *fcfg; void *image = NULL; int version; - size_t headersz; + size_t headersz = 0; uint32_t checksum; int ret; int size; @@ -751,15 +692,29 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd, 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"); @@ -770,7 +725,8 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd, 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", @@ -792,8 +748,8 @@ static void kwbimage_print_header(const void *ptr) 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); @@ -816,7 +772,8 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, 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; @@ -824,7 +781,8 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, 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; } @@ -858,7 +816,15 @@ static int kwbimage_generate(struct image_tool_params *params, 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; } /* @@ -882,19 +848,17 @@ static int kwbimage_check_params(struct image_tool_params *params) /* * 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 +);