static void *image_create_v0(struct image_cfg_element *image_cfg, int cfgn, const char *output, size_t *imagesz) { struct image_cfg_element *e, *payloade; size_t headersz, payloadsz, totalsz; struct main_hdr_v0 *main_hdr; struct ext_hdr_v0 *ext_hdr; void *image; int has_ext = 0; int ret; /* Calculate the size of the header and the size of the * payload */ headersz = sizeof(struct main_hdr_v0); payloadsz = 0; if (image_count_options(image_cfg, cfgn, IMAGE_CFG_DATA) > 0) { has_ext = 1; headersz += sizeof(struct ext_hdr_v0); } if (image_count_options(image_cfg, cfgn, IMAGE_CFG_PAYLOAD) > 1) { fprintf(stderr, "More than one payload, not possible\n"); return NULL; } payloade = image_find_option(image_cfg, cfgn, IMAGE_CFG_PAYLOAD); if (payloade) { struct stat s; int ret; ret = stat(payloade->payload, &s); if (ret < 0) { fprintf(stderr, "Cannot stat payload file %s\n", payloade->payload); return NULL; } /* payload size must be multiple of 32b */ payloadsz = 4 * ((s.st_size + 3)/4); } /* Headers, payload and 32-bits checksum */ totalsz = headersz + payloadsz + sizeof(uint32_t); image = malloc(totalsz); if (!image) { fprintf(stderr, "Cannot allocate memory for image\n"); return NULL; } memset(image, 0, totalsz); main_hdr = image; /* Fill in the main header */ main_hdr->blocksize = payloadsz + sizeof(uint32_t); main_hdr->srcaddr = headersz; main_hdr->ext = has_ext; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_BOOT_FROM); if (e) main_hdr->blockid = e->bootfrom; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_DEST_ADDR); if (e) main_hdr->destaddr = e->dstaddr; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_EXEC_ADDR); if (e) main_hdr->execaddr = e->execaddr; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_NAND_ECC_MODE); if (e) main_hdr->nandeccmode = e->nandeccmode; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_NAND_PAGESZ); if (e) main_hdr->nandpagesize = e->nandpagesz; main_hdr->checksum = image_checksum8(image, sizeof(struct main_hdr_v0)); /* Generate the ext header */ if (has_ext) { int cfgi, datai; ext_hdr = image + sizeof(struct main_hdr_v0); ext_hdr->offset = 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; datai++; } ext_hdr->checksum = image_checksum8(ext_hdr, sizeof(struct ext_hdr_v0)); } if (payloade) { ret = image_create_payload(image + headersz, payloadsz, payloade->payload); if (ret < 0) return NULL; } *imagesz = totalsz; return image; }
static int image_extract_v1(void *fdimap, const char *output, FILE *focfg) { struct main_hdr_v1 *main_hdr = fdimap; struct opt_hdr_v1 *opt_hdr; const char *boot_mode_name; int headersz = KWBHEADER_V1_SIZE(main_hdr); int hasheaders; uint8_t cksum; int opthdrid; /* * Verify the checkum. We have to substract the checksum * itself, because when the checksum is calculated, the * checksum field is 0. */ cksum = image_checksum8(main_hdr, headersz); cksum -= main_hdr->checksum; if (cksum != main_hdr->checksum) { fprintf(stderr, "Invalid main header checksum: 0x%08x vs. 0x%08x\n", cksum, main_hdr->checksum); return -1; } /* First, take care of the main header */ boot_mode_name = image_boot_mode_name(main_hdr->blockid); if (!boot_mode_name) { fprintf(stderr, "Invalid boot ID: 0x%x\n", main_hdr->blockid); return -1; } fprintf(focfg, "VERSION 1\n"); fprintf(focfg, "BOOT_FROM %s\n", boot_mode_name); fprintf(focfg, "DESTADDR %08x\n", main_hdr->destaddr); fprintf(focfg, "EXECADDR %08x\n", main_hdr->execaddr); fprintf(focfg, "NAND_BLKSZ %08x\n", main_hdr->nandblocksize * 64 * 1024); fprintf(focfg, "NAND_BADBLK_LOCATION %02x\n", main_hdr->nandbadblklocation); hasheaders = main_hdr->ext; opt_hdr = fdimap + sizeof(struct main_hdr_v1); opthdrid = 0; /* Then, go through all the extension headers */ while (hasheaders) { int opthdrsz = KWBHEADER_V1_SIZE(opt_hdr); switch (opt_hdr->headertype) { case OPT_HDR_V1_BINARY_TYPE: image_extract_binary_hdr_v1(opt_hdr->data, output, focfg, opthdrid, opthdrsz - sizeof(struct opt_hdr_v1)); break; case OPT_HDR_V1_SECURE_TYPE: case OPT_HDR_V1_REGISTER_TYPE: fprintf(stderr, "Support for header type 0x%x not implemented\n", opt_hdr->headertype); exit(1); break; default: fprintf(stderr, "Invalid header type 0x%x\n", opt_hdr->headertype); exit(1); } /* * The first byte of the last double word of the * current header indicates whether there is a next * header or not. */ hasheaders = ((char *)opt_hdr)[opthdrsz - 4]; /* Move to the next header */ opt_hdr = ((void *)opt_hdr) + opthdrsz; opthdrid++; } /* Finally, handle the image itself */ fprintf(focfg, "PAYLOAD %s/payload\n", output); return image_extract_payload(fdimap + main_hdr->srcaddr, main_hdr->blocksize - 4, output); }
static int image_extract_v0(void *fdimap, const char *output, FILE *focfg) { struct main_hdr_v0 *main_hdr = fdimap; struct ext_hdr_v0 *ext_hdr; const char *boot_mode_name; uint32_t *img_checksum; size_t payloadsz; int cksum, i; /* * Verify checksum. When calculating the header, discard the * last byte of the header, which itself contains the * checksum. */ cksum = image_checksum8(main_hdr, sizeof(struct main_hdr_v0)-1); if (cksum != main_hdr->checksum) { fprintf(stderr, "Invalid main header checksum: 0x%08x vs. 0x%08x\n", cksum, main_hdr->checksum); return -1; } boot_mode_name = image_boot_mode_name(main_hdr->blockid); if (!boot_mode_name) { fprintf(stderr, "Invalid boot ID: 0x%x\n", main_hdr->blockid); return -1; } fprintf(focfg, "VERSION 0\n"); fprintf(focfg, "BOOT_FROM %s\n", boot_mode_name); fprintf(focfg, "DESTADDR %08x\n", main_hdr->destaddr); fprintf(focfg, "EXECADDR %08x\n", main_hdr->execaddr); if (!strcmp(boot_mode_name, "nand")) { const char *nand_ecc_mode = image_nand_ecc_mode_name(main_hdr->nandeccmode); fprintf(focfg, "NAND_ECCMODE %s\n", nand_ecc_mode); fprintf(focfg, "NAND_PAGESZ %08x\n", main_hdr->nandpagesize); } /* No extension header, we're done */ if (!main_hdr->ext) return 0; ext_hdr = fdimap + sizeof(struct main_hdr_v0); for (i = 0; i < EXT_HDR_V0_REG_COUNT; i++) { if (ext_hdr->rcfg[i].raddr == 0 && ext_hdr->rcfg[i].rdata == 0) break; fprintf(focfg, "DATA %08x %08x\n", ext_hdr->rcfg[i].raddr, ext_hdr->rcfg[i].rdata); } /* The image is concatenated with a 32 bits checksum */ payloadsz = main_hdr->blocksize - sizeof(uint32_t); img_checksum = (uint32_t *) (fdimap + main_hdr->srcaddr + payloadsz); if (*img_checksum != image_checksum32(fdimap + main_hdr->srcaddr, payloadsz)) { fprintf(stderr, "The image checksum does not match\n"); return -1; } /* Finally, handle the image itself */ fprintf(focfg, "PAYLOAD %s/payload\n", output); return image_extract_payload(fdimap + main_hdr->srcaddr, payloadsz, output); }
static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, int payloadsz) { struct image_cfg_element *e, *binarye; struct main_hdr_v1 *main_hdr; size_t headersz; void *image, *cur; int hasext = 0; int ret; /* * Calculate the size of the header and the size of the * payload */ headersz = image_headersz_v1(params, &hasext); if (headersz == 0) return NULL; image = malloc(headersz); if (!image) { fprintf(stderr, "Cannot allocate memory for image\n"); return NULL; } memset(image, 0, headersz); cur = main_hdr = image; 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->headersz_msb = (headersz & 0xFFFF0000) >> 16; main_hdr->destaddr = params->addr; main_hdr->execaddr = params->ep; main_hdr->srcaddr = headersz; main_hdr->ext = hasext; main_hdr->version = 1; e = image_find_option(IMAGE_CFG_BOOT_FROM); if (e) main_hdr->blockid = e->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_BADBLK_LOCATION); if (e) main_hdr->nandbadblklocation = e->nandbadblklocation; binarye = image_find_option(IMAGE_CFG_BINARY); if (binarye) { struct opt_hdr_v1 *hdr = cur; unsigned int *args; size_t binhdrsz; struct stat s; int argi; FILE *bin; hdr->headertype = OPT_HDR_V1_BINARY_TYPE; bin = fopen(binarye->binary.file, "r"); if (!bin) { fprintf(stderr, "Cannot open binary file %s\n", binarye->binary.file); return NULL; } fstat(fileno(bin), &s); binhdrsz = sizeof(struct opt_hdr_v1) + (binarye->binary.nargs + 1) * sizeof(unsigned int) + s.st_size; binhdrsz = ALIGN_SUP(binhdrsz, 32); hdr->headersz_lsb = binhdrsz & 0xFFFF; hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; cur += sizeof(struct opt_hdr_v1); args = cur; *args = binarye->binary.nargs; args++; for (argi = 0; argi < binarye->binary.nargs; argi++) args[argi] = binarye->binary.args[argi]; cur += (binarye->binary.nargs + 1) * sizeof(unsigned int); ret = fread(cur, s.st_size, 1, bin); if (ret != 1) { fprintf(stderr, "Could not read binary image %s\n", binarye->binary.file); return NULL; } fclose(bin); cur += s.st_size; /* * 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 */ *((unsigned char *)cur) = 0; cur += sizeof(uint32_t); } /* Calculate and set the header checksum */ main_hdr->checksum = image_checksum8(main_hdr, headersz); *imagesz = headersz; return image; }
static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, int payloadsz) { struct image_cfg_element *e; size_t headersz; struct main_hdr_v0 *main_hdr; struct ext_hdr_v0 *ext_hdr; void *image; int has_ext = 0; /* * Calculate the size of the header and the size of the * payload */ headersz = sizeof(struct main_hdr_v0); if (image_count_options(IMAGE_CFG_DATA) > 0) { has_ext = 1; 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"); return NULL; } memset(image, 0, headersz); main_hdr = image; /* Fill in the main header */ main_hdr->blocksize = payloadsz + sizeof(uint32_t) - headersz; main_hdr->srcaddr = headersz; main_hdr->ext = has_ext; main_hdr->destaddr = params->addr; main_hdr->execaddr = params->ep; 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; e = image_find_option(IMAGE_CFG_NAND_PAGESZ); if (e) main_hdr->nandpagesize = e->nandpagesz; main_hdr->checksum = image_checksum8(image, sizeof(struct main_hdr_v0)); /* Generate the ext header */ if (has_ext) { int cfgi, datai; ext_hdr = image + sizeof(struct main_hdr_v0); ext_hdr->offset = 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; datai++; } ext_hdr->checksum = image_checksum8(ext_hdr, sizeof(struct ext_hdr_v0)); } *imagesz = headersz; return image; }
static void *image_create_v1(struct image_cfg_element *image_cfg, int cfgn, const char *output, size_t *imagesz) { struct image_cfg_element *e, *payloade, *binarye; struct main_hdr_v1 *main_hdr; size_t headersz, payloadsz, totalsz; void *image, *cur; int hasext = 0; int ret; /* Calculate the size of the header and the size of the * payload */ headersz = sizeof(struct main_hdr_v1); payloadsz = 0; if (image_count_options(image_cfg, cfgn, IMAGE_CFG_BINARY) > 1) { fprintf(stderr, "More than one binary blob, not supported\n"); return NULL; } if (image_count_options(image_cfg, cfgn, IMAGE_CFG_PAYLOAD) > 1) { fprintf(stderr, "More than one payload, not possible\n"); return NULL; } binarye = image_find_option(image_cfg, cfgn, IMAGE_CFG_BINARY); if (binarye) { struct stat s; ret = stat(binarye->binary.file, &s); if (ret < 0) { char *cwd = get_current_dir_name(); 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); return NULL; } headersz += ALIGN_SUP(s.st_size, 4) + 12 + binarye->binary.nargs * sizeof(unsigned int); hasext = 1; } payloade = image_find_option(image_cfg, cfgn, IMAGE_CFG_PAYLOAD); if (payloade) { struct stat s; ret = stat(payloade->payload, &s); if (ret < 0) { fprintf(stderr, "Cannot stat payload file %s\n", payloade->payload); return NULL; } /* payload size must be multiple of 32b */ payloadsz = ALIGN_SUP(s.st_size, 4); } /* The payload should be aligned on some reasonable * boundary */ headersz = ALIGN_SUP(headersz, 4096); /* The total size includes the headers, the payload, and the * 32 bits checksum at the end of the payload */ totalsz = headersz + payloadsz + sizeof(uint32_t); image = malloc(totalsz); if (!image) { fprintf(stderr, "Cannot allocate memory for image\n"); return NULL; } memset(image, 0, totalsz); cur = main_hdr = image; cur += sizeof(struct main_hdr_v1); /* Fill the main header */ main_hdr->blocksize = payloadsz + sizeof(uint32_t); main_hdr->headersz_lsb = headersz & 0xFFFF; main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16; main_hdr->srcaddr = headersz; main_hdr->ext = hasext; main_hdr->version = 1; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_BOOT_FROM); if (e) main_hdr->blockid = e->bootfrom; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_DEST_ADDR); if (e) main_hdr->destaddr = e->dstaddr; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_EXEC_ADDR); if (e) main_hdr->execaddr = e->execaddr; e = image_find_option(image_cfg, cfgn, IMAGE_CFG_NAND_BLKSZ); if (e) main_hdr->nandblocksize = e->nandblksz / (64 * 1024); e = image_find_option(image_cfg, cfgn, IMAGE_CFG_NAND_BADBLK_LOCATION); if (e) main_hdr->nandbadblklocation = e->nandbadblklocation; if (binarye) { struct opt_hdr_v1 *hdr = cur; unsigned int *args; size_t binhdrsz; struct stat s; int argi; FILE *bin; hdr->headertype = OPT_HDR_V1_BINARY_TYPE; bin = fopen(binarye->binary.file, "r"); if (!bin) { fprintf(stderr, "Cannot open binary file %s\n", binarye->binary.file); return NULL; } fstat(fileno(bin), &s); binhdrsz = sizeof(struct opt_hdr_v1) + (binarye->binary.nargs + 2) * sizeof(unsigned int) + ALIGN_SUP(s.st_size, 4); hdr->headersz_lsb = binhdrsz & 0xFFFF; hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; cur += sizeof(struct opt_hdr_v1); args = cur; *args = binarye->binary.nargs; args++; for (argi = 0; argi < binarye->binary.nargs; argi++) args[argi] = binarye->binary.args[argi]; cur += (binarye->binary.nargs + 1) * sizeof(unsigned int); if (s.st_size) ret = fread(cur, s.st_size, 1, bin); else ret = 1; if (ret != 1) { fprintf(stderr, "Could not read binary image %s\n", binarye->binary.file); return NULL; } fclose(bin); cur += ALIGN_SUP(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 */ *((unsigned char *) cur) = 0; cur += sizeof(uint32_t); } /* Calculate and set the header checksum */ main_hdr->checksum = image_checksum8(main_hdr, headersz); if (payloade) { ret = image_create_payload(image + headersz, payloadsz, payloade->payload); if (ret < 0) return NULL; } *imagesz = totalsz; return image; }