blob: c50f2e2b2494d56c5f34e7660b54b0cb9752597d [file] [log] [blame]
Prafulla Wadaskar07329412009-09-07 15:05:02 +05301/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +02002 * Image manipulator for Marvell SoCs
3 * supports Kirkwood, Dove, Armada 370, and Armada XP
4 *
5 * (C) Copyright 2013 Thomas Petazzoni
6 * <thomas.petazzoni@free-electrons.com>
Prafulla Wadaskar07329412009-09-07 15:05:02 +05307 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
Stefan Roese3b8b19d2014-10-22 12:13:23 +02009 *
10 * Not implemented: support for the register headers and secure
11 * headers in v1 images
Prafulla Wadaskar07329412009-09-07 15:05:02 +053012 */
13
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -070014#include "imagetool.h"
Andreas Bießmann7abec5b2014-10-24 23:39:11 +020015#include <limits.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053016#include <image.h>
Stefan Roese3b8b19d2014-10-22 12:13:23 +020017#include <stdint.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053018#include "kwbimage.h"
19
Stefan Roese3b8b19d2014-10-22 12:13:23 +020020#define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
21
22/* Structure of the main header, version 0 (Kirkwood, Dove) */
23struct main_hdr_v0 {
24 uint8_t blockid; /*0 */
25 uint8_t nandeccmode; /*1 */
26 uint16_t nandpagesize; /*2-3 */
27 uint32_t blocksize; /*4-7 */
28 uint32_t rsvd1; /*8-11 */
29 uint32_t srcaddr; /*12-15 */
30 uint32_t destaddr; /*16-19 */
31 uint32_t execaddr; /*20-23 */
32 uint8_t satapiomode; /*24 */
33 uint8_t rsvd3; /*25 */
34 uint16_t ddrinitdelay; /*26-27 */
35 uint16_t rsvd2; /*28-29 */
36 uint8_t ext; /*30 */
37 uint8_t checksum; /*31 */
38};
39
40struct ext_hdr_v0_reg {
41 uint32_t raddr;
42 uint32_t rdata;
Prafulla Wadaskar07329412009-09-07 15:05:02 +053043};
44
Stefan Roese3b8b19d2014-10-22 12:13:23 +020045#define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
46
47struct ext_hdr_v0 {
48 uint32_t offset;
49 uint8_t reserved[0x20 - sizeof(uint32_t)];
50 struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
51 uint8_t reserved2[7];
52 uint8_t checksum;
53};
54
55/* Structure of the main header, version 1 (Armada 370, Armada XP) */
56struct main_hdr_v1 {
57 uint8_t blockid; /* 0 */
58 uint8_t reserved1; /* 1 */
59 uint16_t reserved2; /* 2-3 */
60 uint32_t blocksize; /* 4-7 */
61 uint8_t version; /* 8 */
62 uint8_t headersz_msb; /* 9 */
63 uint16_t headersz_lsb; /* A-B */
64 uint32_t srcaddr; /* C-F */
65 uint32_t destaddr; /* 10-13 */
66 uint32_t execaddr; /* 14-17 */
67 uint8_t reserved3; /* 18 */
68 uint8_t nandblocksize; /* 19 */
69 uint8_t nandbadblklocation; /* 1A */
70 uint8_t reserved4; /* 1B */
71 uint16_t reserved5; /* 1C-1D */
72 uint8_t ext; /* 1E */
73 uint8_t checksum; /* 1F */
74};
75
Prafulla Wadaskar07329412009-09-07 15:05:02 +053076/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020077 * Header for the optional headers, version 1 (Armada 370, Armada XP)
Prafulla Wadaskar07329412009-09-07 15:05:02 +053078 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +020079struct opt_hdr_v1 {
80 uint8_t headertype;
81 uint8_t headersz_msb;
82 uint16_t headersz_lsb;
83 char data[0];
Prafulla Wadaskar07329412009-09-07 15:05:02 +053084};
85
86/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020087 * Various values for the opt_hdr_v1->headertype field, describing the
88 * different types of optional headers. The "secure" header contains
89 * informations related to secure boot (encryption keys, etc.). The
90 * "binary" header contains ARM binary code to be executed prior to
91 * executing the main payload (usually the bootloader). This is
92 * typically used to execute DDR3 training code. The "register" header
93 * allows to describe a set of (address, value) tuples that are
94 * generally used to configure the DRAM controller.
Prafulla Wadaskar07329412009-09-07 15:05:02 +053095 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +020096#define OPT_HDR_V1_SECURE_TYPE 0x1
97#define OPT_HDR_V1_BINARY_TYPE 0x2
98#define OPT_HDR_V1_REGISTER_TYPE 0x3
99
100#define KWBHEADER_V1_SIZE(hdr) \
101 (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
102
103static struct image_cfg_element *image_cfg;
104static int cfgn;
105
106struct boot_mode {
107 unsigned int id;
108 const char *name;
109};
110
111struct boot_mode boot_modes[] = {
112 { 0x4D, "i2c" },
113 { 0x5A, "spi" },
114 { 0x8B, "nand" },
115 { 0x78, "sata" },
116 { 0x9C, "pex" },
117 { 0x69, "uart" },
118 {},
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530119};
120
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200121struct nand_ecc_mode {
122 unsigned int id;
123 const char *name;
124};
125
126struct nand_ecc_mode nand_ecc_modes[] = {
127 { 0x00, "default" },
128 { 0x01, "hamming" },
129 { 0x02, "rs" },
130 { 0x03, "disabled" },
131 {},
132};
133
134/* Used to identify an undefined execution or destination address */
135#define ADDR_INVALID ((uint32_t)-1)
136
137#define BINARY_MAX_ARGS 8
138
139/* In-memory representation of a line of the configuration file */
140struct image_cfg_element {
141 enum {
142 IMAGE_CFG_VERSION = 0x1,
143 IMAGE_CFG_BOOT_FROM,
144 IMAGE_CFG_DEST_ADDR,
145 IMAGE_CFG_EXEC_ADDR,
146 IMAGE_CFG_NAND_BLKSZ,
147 IMAGE_CFG_NAND_BADBLK_LOCATION,
148 IMAGE_CFG_NAND_ECC_MODE,
149 IMAGE_CFG_NAND_PAGESZ,
150 IMAGE_CFG_BINARY,
151 IMAGE_CFG_PAYLOAD,
152 IMAGE_CFG_DATA,
153 } type;
154 union {
155 unsigned int version;
156 unsigned int bootfrom;
157 struct {
158 const char *file;
159 unsigned int args[BINARY_MAX_ARGS];
160 unsigned int nargs;
161 } binary;
162 const char *payload;
163 unsigned int dstaddr;
164 unsigned int execaddr;
165 unsigned int nandblksz;
166 unsigned int nandbadblklocation;
167 unsigned int nandeccmode;
168 unsigned int nandpagesz;
169 struct ext_hdr_v0_reg regdata;
170 };
171};
172
173#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530174
175/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200176 * Byte 8 of the image header contains the version number. In the v0
177 * header, byte 8 was reserved, and always set to 0. In the v1 header,
178 * byte 8 has been changed to a proper field, set to 1.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530179 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200180static unsigned int image_version(void *header)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530181{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200182 unsigned char *ptr = header;
183 return ptr[8];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530184}
185
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200186/*
187 * Utility functions to manipulate boot mode and ecc modes (convert
188 * them back and forth between description strings and the
189 * corresponding numerical identifiers).
190 */
191
192static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530193{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200194 int i;
195 for (i = 0; boot_modes[i].name; i++)
196 if (boot_modes[i].id == id)
197 return boot_modes[i].name;
198 return NULL;
199}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530200
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200201int image_boot_mode_id(const char *boot_mode_name)
202{
203 int i;
204 for (i = 0; boot_modes[i].name; i++)
205 if (!strcmp(boot_modes[i].name, boot_mode_name))
206 return boot_modes[i].id;
207
208 return -1;
209}
210
211int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
212{
213 int i;
214 for (i = 0; nand_ecc_modes[i].name; i++)
215 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
216 return nand_ecc_modes[i].id;
217 return -1;
218}
219
220static struct image_cfg_element *
221image_find_option(unsigned int optiontype)
222{
223 int i;
224
225 for (i = 0; i < cfgn; i++) {
226 if (image_cfg[i].type == optiontype)
227 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530228 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200229
230 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530231}
232
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200233static unsigned int
234image_count_options(unsigned int optiontype)
235{
236 int i;
237 unsigned int count = 0;
238
239 for (i = 0; i < cfgn; i++)
240 if (image_cfg[i].type == optiontype)
241 count++;
242
243 return count;
244}
245
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530246/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200247 * Compute a 8-bit checksum of a memory area. This algorithm follows
248 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530249 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200250static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530251{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200252 uint8_t csum = 0;
253 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530254
255 /* check len and return zero checksum if invalid */
256 if (!len)
257 return 0;
258
259 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200260 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530261 p++;
262 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200263
264 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530265}
266
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200267static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530268{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200269 uint32_t csum = 0;
270 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530271
272 /* check len and return zero checksum if invalid */
273 if (!len)
274 return 0;
275
276 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200277 fprintf(stderr, "Length %d is not in multiple of %zu\n",
278 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530279 return 0;
280 }
281
282 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200283 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530284 p++;
285 len -= sizeof(uint32_t);
286 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200287
288 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530289}
290
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200291static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
292 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530293{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200294 struct image_cfg_element *e;
295 size_t headersz;
296 struct main_hdr_v0 *main_hdr;
297 struct ext_hdr_v0 *ext_hdr;
298 void *image;
299 int has_ext = 0;
300
301 /*
302 * Calculate the size of the header and the size of the
303 * payload
304 */
305 headersz = sizeof(struct main_hdr_v0);
306
307 if (image_count_options(IMAGE_CFG_DATA) > 0) {
308 has_ext = 1;
309 headersz += sizeof(struct ext_hdr_v0);
310 }
311
312 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
313 fprintf(stderr, "More than one payload, not possible\n");
314 return NULL;
315 }
316
317 image = malloc(headersz);
318 if (!image) {
319 fprintf(stderr, "Cannot allocate memory for image\n");
320 return NULL;
321 }
322
323 memset(image, 0, headersz);
324
325 main_hdr = image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530326
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200327 /* Fill in the main header */
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100328 main_hdr->blocksize = payloadsz + sizeof(uint32_t) - headersz;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200329 main_hdr->srcaddr = headersz;
330 main_hdr->ext = has_ext;
331 main_hdr->destaddr = params->addr;
332 main_hdr->execaddr = params->ep;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530333
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200334 e = image_find_option(IMAGE_CFG_BOOT_FROM);
335 if (e)
336 main_hdr->blockid = e->bootfrom;
337 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
338 if (e)
339 main_hdr->nandeccmode = e->nandeccmode;
340 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
341 if (e)
342 main_hdr->nandpagesize = e->nandpagesz;
343 main_hdr->checksum = image_checksum8(image,
344 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530345
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200346 /* Generate the ext header */
347 if (has_ext) {
348 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530349
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200350 ext_hdr = image + sizeof(struct main_hdr_v0);
351 ext_hdr->offset = 0x40;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530352
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200353 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
354 e = &image_cfg[cfgi];
355 if (e->type != IMAGE_CFG_DATA)
356 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530357
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200358 ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
359 ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
360 datai++;
361 }
362
363 ext_hdr->checksum = image_checksum8(ext_hdr,
364 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530365 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530366
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200367 *imagesz = headersz;
368 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530369}
370
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200371static size_t image_headersz_v1(struct image_tool_params *params,
372 int *hasext)
373{
374 struct image_cfg_element *binarye;
375 size_t headersz;
376 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530377
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200378 /*
379 * Calculate the size of the header and the size of the
380 * payload
381 */
382 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530383
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200384 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
385 fprintf(stderr, "More than one binary blob, not supported\n");
386 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530387 }
388
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200389 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
390 fprintf(stderr, "More than one payload, not possible\n");
391 return 0;
392 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530393
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200394 binarye = image_find_option(IMAGE_CFG_BINARY);
395 if (binarye) {
396 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530397
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200398 ret = stat(binarye->binary.file, &s);
399 if (ret < 0) {
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200400 char cwd[PATH_MAX];
401 char *dir = cwd;
402
403 memset(cwd, 0, sizeof(cwd));
404 if (!getcwd(cwd, sizeof(cwd))) {
405 dir = "current working directory";
406 perror("getcwd() failed");
407 }
408
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200409 fprintf(stderr,
410 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
411 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
412 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200413 binarye->binary.file, dir);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200414 return 0;
415 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530416
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200417 headersz += s.st_size +
418 binarye->binary.nargs * sizeof(unsigned int);
419 if (hasext)
420 *hasext = 1;
421 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530422
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200423 /*
424 * The payload should be aligned on some reasonable
425 * boundary
426 */
427 return ALIGN_SUP(headersz, 4096);
428}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530429
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200430static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
431 int payloadsz)
432{
433 struct image_cfg_element *e, *binarye;
434 struct main_hdr_v1 *main_hdr;
435 size_t headersz;
436 void *image, *cur;
437 int hasext = 0;
438 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530439
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200440 /*
441 * Calculate the size of the header and the size of the
442 * payload
443 */
444 headersz = image_headersz_v1(params, &hasext);
445 if (headersz == 0)
446 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530447
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200448 image = malloc(headersz);
449 if (!image) {
450 fprintf(stderr, "Cannot allocate memory for image\n");
451 return NULL;
452 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530453
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200454 memset(image, 0, headersz);
455
456 cur = main_hdr = image;
457 cur += sizeof(struct main_hdr_v1);
458
459 /* Fill the main header */
460 main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t);
461 main_hdr->headersz_lsb = headersz & 0xFFFF;
462 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
463 main_hdr->destaddr = params->addr;
464 main_hdr->execaddr = params->ep;
465 main_hdr->srcaddr = headersz;
466 main_hdr->ext = hasext;
467 main_hdr->version = 1;
468 e = image_find_option(IMAGE_CFG_BOOT_FROM);
469 if (e)
470 main_hdr->blockid = e->bootfrom;
471 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
472 if (e)
473 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
474 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
475 if (e)
476 main_hdr->nandbadblklocation = e->nandbadblklocation;
477
478 binarye = image_find_option(IMAGE_CFG_BINARY);
479 if (binarye) {
480 struct opt_hdr_v1 *hdr = cur;
481 unsigned int *args;
482 size_t binhdrsz;
483 struct stat s;
484 int argi;
485 FILE *bin;
486
487 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
488
489 bin = fopen(binarye->binary.file, "r");
490 if (!bin) {
491 fprintf(stderr, "Cannot open binary file %s\n",
492 binarye->binary.file);
493 return NULL;
494 }
495
496 fstat(fileno(bin), &s);
497
498 binhdrsz = sizeof(struct opt_hdr_v1) +
499 (binarye->binary.nargs + 1) * sizeof(unsigned int) +
500 s.st_size;
501 hdr->headersz_lsb = binhdrsz & 0xFFFF;
502 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
503
504 cur += sizeof(struct opt_hdr_v1);
505
506 args = cur;
507 *args = binarye->binary.nargs;
508 args++;
509 for (argi = 0; argi < binarye->binary.nargs; argi++)
510 args[argi] = binarye->binary.args[argi];
511
512 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
513
514 ret = fread(cur, s.st_size, 1, bin);
515 if (ret != 1) {
516 fprintf(stderr,
517 "Could not read binary image %s\n",
518 binarye->binary.file);
519 return NULL;
520 }
521
522 fclose(bin);
523
524 cur += s.st_size;
525
526 /*
527 * For now, we don't support more than one binary
528 * header, and no other header types are
529 * supported. So, the binary header is necessarily the
530 * last one
531 */
532 *((unsigned char *)cur) = 0;
533
534 cur += sizeof(uint32_t);
535 }
536
537 /* Calculate and set the header checksum */
538 main_hdr->checksum = image_checksum8(main_hdr, headersz);
539
540 *imagesz = headersz;
541 return image;
542}
543
544static int image_create_config_parse_oneline(char *line,
545 struct image_cfg_element *el)
546{
547 char *keyword, *saveptr;
548 char deliminiters[] = " \t";
549
550 keyword = strtok_r(line, deliminiters, &saveptr);
551 if (!strcmp(keyword, "VERSION")) {
552 char *value = strtok_r(NULL, deliminiters, &saveptr);
553 el->type = IMAGE_CFG_VERSION;
554 el->version = atoi(value);
555 } else if (!strcmp(keyword, "BOOT_FROM")) {
556 char *value = strtok_r(NULL, deliminiters, &saveptr);
557 el->type = IMAGE_CFG_BOOT_FROM;
558 el->bootfrom = image_boot_mode_id(value);
559 if (el->bootfrom < 0) {
560 fprintf(stderr,
561 "Invalid boot media '%s'\n", value);
562 return -1;
563 }
564 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
565 char *value = strtok_r(NULL, deliminiters, &saveptr);
566 el->type = IMAGE_CFG_NAND_BLKSZ;
567 el->nandblksz = strtoul(value, NULL, 16);
568 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
569 char *value = strtok_r(NULL, deliminiters, &saveptr);
570 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
571 el->nandbadblklocation =
572 strtoul(value, NULL, 16);
573 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
574 char *value = strtok_r(NULL, deliminiters, &saveptr);
575 el->type = IMAGE_CFG_NAND_ECC_MODE;
576 el->nandeccmode = image_nand_ecc_mode_id(value);
577 if (el->nandeccmode < 0) {
578 fprintf(stderr,
579 "Invalid NAND ECC mode '%s'\n", value);
580 return -1;
581 }
582 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
583 char *value = strtok_r(NULL, deliminiters, &saveptr);
584 el->type = IMAGE_CFG_NAND_PAGESZ;
585 el->nandpagesz = strtoul(value, NULL, 16);
586 } else if (!strcmp(keyword, "BINARY")) {
587 char *value = strtok_r(NULL, deliminiters, &saveptr);
588 int argi = 0;
589
590 el->type = IMAGE_CFG_BINARY;
591 el->binary.file = strdup(value);
592 while (1) {
593 value = strtok_r(NULL, deliminiters, &saveptr);
594 if (!value)
595 break;
596 el->binary.args[argi] = strtoul(value, NULL, 16);
597 argi++;
598 if (argi >= BINARY_MAX_ARGS) {
599 fprintf(stderr,
600 "Too many argument for binary\n");
601 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530602 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530603 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200604 el->binary.nargs = argi;
605 } else if (!strcmp(keyword, "DATA")) {
606 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
607 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
608
609 if (!value1 || !value2) {
610 fprintf(stderr,
611 "Invalid number of arguments for DATA\n");
612 return -1;
613 }
614
615 el->type = IMAGE_CFG_DATA;
616 el->regdata.raddr = strtoul(value1, NULL, 16);
617 el->regdata.rdata = strtoul(value2, NULL, 16);
618 } else {
619 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530620 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530621
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200622 return 0;
623}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530624
625/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200626 * Parse the configuration file 'fcfg' into the array of configuration
627 * elements 'image_cfg', and return the number of configuration
628 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530629 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200630static int image_create_config_parse(FILE *fcfg)
631{
632 int ret;
633 int cfgi = 0;
634
635 /* Parse the configuration file */
636 while (!feof(fcfg)) {
637 char *line;
638 char buf[256];
639
640 /* Read the current line */
641 memset(buf, 0, sizeof(buf));
642 line = fgets(buf, sizeof(buf), fcfg);
643 if (!line)
644 break;
645
646 /* Ignore useless lines */
647 if (line[0] == '\n' || line[0] == '#')
648 continue;
649
650 /* Strip final newline */
651 if (line[strlen(line) - 1] == '\n')
652 line[strlen(line) - 1] = 0;
653
654 /* Parse the current line */
655 ret = image_create_config_parse_oneline(line,
656 &image_cfg[cfgi]);
657 if (ret)
658 return ret;
659
660 cfgi++;
661
662 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
663 fprintf(stderr,
664 "Too many configuration elements in .cfg file\n");
665 return -1;
666 }
667 }
668
669 cfgn = cfgi;
670 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530671}
672
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200673static int image_get_version(void)
674{
675 struct image_cfg_element *e;
676
677 e = image_find_option(IMAGE_CFG_VERSION);
678 if (!e)
679 return -1;
680
681 return e->version;
682}
683
684static int image_version_file(const char *input)
685{
686 FILE *fcfg;
687 int version;
688 int ret;
689
690 fcfg = fopen(input, "r");
691 if (!fcfg) {
692 fprintf(stderr, "Could not open input file %s\n", input);
693 return -1;
694 }
695
696 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
697 sizeof(struct image_cfg_element));
698 if (!image_cfg) {
699 fprintf(stderr, "Cannot allocate memory\n");
700 fclose(fcfg);
701 return -1;
702 }
703
704 memset(image_cfg, 0,
705 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
706 rewind(fcfg);
707
708 ret = image_create_config_parse(fcfg);
709 fclose(fcfg);
710 if (ret) {
711 free(image_cfg);
712 return -1;
713 }
714
715 version = image_get_version();
716 /* Fallback to version 0 is no version is provided in the cfg file */
717 if (version == -1)
718 version = 0;
719
720 free(image_cfg);
721
722 return version;
723}
724
725static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700726 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530727{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200728 FILE *fcfg;
729 void *image = NULL;
730 int version;
731 size_t headersz;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530732 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200733 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530734 int size;
735
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200736 fcfg = fopen(params->imagename, "r");
737 if (!fcfg) {
738 fprintf(stderr, "Could not open input file %s\n",
739 params->imagename);
740 exit(EXIT_FAILURE);
741 }
742
743 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
744 sizeof(struct image_cfg_element));
745 if (!image_cfg) {
746 fprintf(stderr, "Cannot allocate memory\n");
747 fclose(fcfg);
748 exit(EXIT_FAILURE);
749 }
750
751 memset(image_cfg, 0,
752 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
753 rewind(fcfg);
754
755 ret = image_create_config_parse(fcfg);
756 fclose(fcfg);
757 if (ret) {
758 free(image_cfg);
759 exit(EXIT_FAILURE);
760 }
761
762 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100763 switch (version) {
764 /*
765 * Fallback to version 0 if no version is provided in the
766 * cfg file
767 */
768 case -1:
769 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200770 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100771 break;
772
773 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200774 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100775 break;
776
777 default:
778 fprintf(stderr, "Unsupported version %d\n", version);
779 free(image_cfg);
780 exit(EXIT_FAILURE);
781 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530782
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200783 if (!image) {
784 fprintf(stderr, "Could not create image\n");
785 free(image_cfg);
786 exit(EXIT_FAILURE);
787 }
788
789 free(image_cfg);
790
791 /* Build and add image checksum header */
792 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
793 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530794 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200795 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530796 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200797 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530798 }
799
800 sbuf->st_size += sizeof(uint32_t);
801
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200802 /* Finally copy the header into the image area */
803 memcpy(ptr, image, headersz);
804
805 free(image);
806}
807
808static void kwbimage_print_header(const void *ptr)
809{
810 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
811
812 printf("Image Type: MVEBU Boot from %s Image\n",
813 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200814 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100815 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200816 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
817 printf("Load Address: %08x\n", mhdr->destaddr);
818 printf("Entry Point: %08x\n", mhdr->execaddr);
819}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530820
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200821static int kwbimage_check_image_types(uint8_t type)
822{
823 if (type == IH_TYPE_KWBIMAGE)
824 return EXIT_SUCCESS;
825 else
826 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530827}
828
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200829static int kwbimage_verify_header(unsigned char *ptr, int image_size,
830 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530831{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200832 struct main_hdr_v0 *main_hdr;
833 struct ext_hdr_v0 *ext_hdr;
834 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530835
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200836 main_hdr = (void *)ptr;
837 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100838 sizeof(struct main_hdr_v0)
839 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200840 if (checksum != main_hdr->checksum)
841 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530842
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200843 /* Only version 0 extended header has checksum */
844 if (image_version((void *)ptr) == 0) {
845 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
846 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100847 sizeof(struct ext_hdr_v0)
848 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200849 if (checksum != ext_hdr->checksum)
850 return -FDT_ERR_BADSTRUCTURE;
851 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530852
853 return 0;
854}
855
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200856static int kwbimage_generate(struct image_tool_params *params,
857 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530858{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200859 int alloc_len;
860 void *hdr;
861 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530862
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200863 version = image_version_file(params->imagename);
864 if (version == 0) {
865 alloc_len = sizeof(struct main_hdr_v0) +
866 sizeof(struct ext_hdr_v0);
867 } else {
868 alloc_len = image_headersz_v1(params, NULL);
869 }
870
871 hdr = malloc(alloc_len);
872 if (!hdr) {
873 fprintf(stderr, "%s: malloc return failure: %s\n",
874 params->cmdname, strerror(errno));
875 exit(EXIT_FAILURE);
876 }
877
878 memset(hdr, 0, alloc_len);
879 tparams->header_size = alloc_len;
880 tparams->hdr = hdr;
881
882 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530883}
884
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200885/*
886 * Report Error if xflag is set in addition to default
887 */
888static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530889{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200890 if (!strlen(params->imagename)) {
891 fprintf(stderr, "Error:%s - Configuration file not specified, "
892 "it is needed for kwbimage generation\n",
893 params->cmdname);
894 return CFG_INVALID;
895 }
896
897 return (params->dflag && (params->fflag || params->lflag)) ||
898 (params->fflag && (params->dflag || params->lflag)) ||
899 (params->lflag && (params->dflag || params->fflag)) ||
900 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530901}
902
903/*
904 * kwbimage type parameters definition
905 */
906static struct image_type_params kwbimage_params = {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200907 .name = "Marvell MVEBU Boot Image support",
908 .header_size = 0, /* no fixed header size */
909 .hdr = NULL,
910 .vrec_header = kwbimage_generate,
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530911 .check_image_type = kwbimage_check_image_types,
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200912 .verify_header = kwbimage_verify_header,
913 .print_header = kwbimage_print_header,
914 .set_header = kwbimage_set_header,
915 .check_params = kwbimage_check_params,
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530916};
917
918void init_kwb_image_type (void)
919{
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700920 register_image_type(&kwbimage_params);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530921}