blob: 1120e9b3729024fc851ddba5a3410dcc92cf29d1 [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"
Prafulla Wadaskar07329412009-09-07 15:05:02 +053015#include <image.h>
Stefan Roese3b8b19d2014-10-22 12:13:23 +020016#include <stdint.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053017#include "kwbimage.h"
18
Stefan Roese3b8b19d2014-10-22 12:13:23 +020019#define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
20
21/* Structure of the main header, version 0 (Kirkwood, Dove) */
22struct main_hdr_v0 {
23 uint8_t blockid; /*0 */
24 uint8_t nandeccmode; /*1 */
25 uint16_t nandpagesize; /*2-3 */
26 uint32_t blocksize; /*4-7 */
27 uint32_t rsvd1; /*8-11 */
28 uint32_t srcaddr; /*12-15 */
29 uint32_t destaddr; /*16-19 */
30 uint32_t execaddr; /*20-23 */
31 uint8_t satapiomode; /*24 */
32 uint8_t rsvd3; /*25 */
33 uint16_t ddrinitdelay; /*26-27 */
34 uint16_t rsvd2; /*28-29 */
35 uint8_t ext; /*30 */
36 uint8_t checksum; /*31 */
37};
38
39struct ext_hdr_v0_reg {
40 uint32_t raddr;
41 uint32_t rdata;
Prafulla Wadaskar07329412009-09-07 15:05:02 +053042};
43
Stefan Roese3b8b19d2014-10-22 12:13:23 +020044#define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
45
46struct ext_hdr_v0 {
47 uint32_t offset;
48 uint8_t reserved[0x20 - sizeof(uint32_t)];
49 struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
50 uint8_t reserved2[7];
51 uint8_t checksum;
52};
53
54/* Structure of the main header, version 1 (Armada 370, Armada XP) */
55struct main_hdr_v1 {
56 uint8_t blockid; /* 0 */
57 uint8_t reserved1; /* 1 */
58 uint16_t reserved2; /* 2-3 */
59 uint32_t blocksize; /* 4-7 */
60 uint8_t version; /* 8 */
61 uint8_t headersz_msb; /* 9 */
62 uint16_t headersz_lsb; /* A-B */
63 uint32_t srcaddr; /* C-F */
64 uint32_t destaddr; /* 10-13 */
65 uint32_t execaddr; /* 14-17 */
66 uint8_t reserved3; /* 18 */
67 uint8_t nandblocksize; /* 19 */
68 uint8_t nandbadblklocation; /* 1A */
69 uint8_t reserved4; /* 1B */
70 uint16_t reserved5; /* 1C-1D */
71 uint8_t ext; /* 1E */
72 uint8_t checksum; /* 1F */
73};
74
Prafulla Wadaskar07329412009-09-07 15:05:02 +053075/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020076 * Header for the optional headers, version 1 (Armada 370, Armada XP)
Prafulla Wadaskar07329412009-09-07 15:05:02 +053077 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +020078struct opt_hdr_v1 {
79 uint8_t headertype;
80 uint8_t headersz_msb;
81 uint16_t headersz_lsb;
82 char data[0];
Prafulla Wadaskar07329412009-09-07 15:05:02 +053083};
84
85/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020086 * Various values for the opt_hdr_v1->headertype field, describing the
87 * different types of optional headers. The "secure" header contains
88 * informations related to secure boot (encryption keys, etc.). The
89 * "binary" header contains ARM binary code to be executed prior to
90 * executing the main payload (usually the bootloader). This is
91 * typically used to execute DDR3 training code. The "register" header
92 * allows to describe a set of (address, value) tuples that are
93 * generally used to configure the DRAM controller.
Prafulla Wadaskar07329412009-09-07 15:05:02 +053094 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +020095#define OPT_HDR_V1_SECURE_TYPE 0x1
96#define OPT_HDR_V1_BINARY_TYPE 0x2
97#define OPT_HDR_V1_REGISTER_TYPE 0x3
98
99#define KWBHEADER_V1_SIZE(hdr) \
100 (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
101
102static struct image_cfg_element *image_cfg;
103static int cfgn;
104
105struct boot_mode {
106 unsigned int id;
107 const char *name;
108};
109
110struct boot_mode boot_modes[] = {
111 { 0x4D, "i2c" },
112 { 0x5A, "spi" },
113 { 0x8B, "nand" },
114 { 0x78, "sata" },
115 { 0x9C, "pex" },
116 { 0x69, "uart" },
117 {},
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530118};
119
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200120struct nand_ecc_mode {
121 unsigned int id;
122 const char *name;
123};
124
125struct nand_ecc_mode nand_ecc_modes[] = {
126 { 0x00, "default" },
127 { 0x01, "hamming" },
128 { 0x02, "rs" },
129 { 0x03, "disabled" },
130 {},
131};
132
133/* Used to identify an undefined execution or destination address */
134#define ADDR_INVALID ((uint32_t)-1)
135
136#define BINARY_MAX_ARGS 8
137
138/* In-memory representation of a line of the configuration file */
139struct image_cfg_element {
140 enum {
141 IMAGE_CFG_VERSION = 0x1,
142 IMAGE_CFG_BOOT_FROM,
143 IMAGE_CFG_DEST_ADDR,
144 IMAGE_CFG_EXEC_ADDR,
145 IMAGE_CFG_NAND_BLKSZ,
146 IMAGE_CFG_NAND_BADBLK_LOCATION,
147 IMAGE_CFG_NAND_ECC_MODE,
148 IMAGE_CFG_NAND_PAGESZ,
149 IMAGE_CFG_BINARY,
150 IMAGE_CFG_PAYLOAD,
151 IMAGE_CFG_DATA,
152 } type;
153 union {
154 unsigned int version;
155 unsigned int bootfrom;
156 struct {
157 const char *file;
158 unsigned int args[BINARY_MAX_ARGS];
159 unsigned int nargs;
160 } binary;
161 const char *payload;
162 unsigned int dstaddr;
163 unsigned int execaddr;
164 unsigned int nandblksz;
165 unsigned int nandbadblklocation;
166 unsigned int nandeccmode;
167 unsigned int nandpagesz;
168 struct ext_hdr_v0_reg regdata;
169 };
170};
171
172#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530173
174/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200175 * Byte 8 of the image header contains the version number. In the v0
176 * header, byte 8 was reserved, and always set to 0. In the v1 header,
177 * byte 8 has been changed to a proper field, set to 1.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530178 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200179static unsigned int image_version(void *header)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530180{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200181 unsigned char *ptr = header;
182 return ptr[8];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530183}
184
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200185/*
186 * Utility functions to manipulate boot mode and ecc modes (convert
187 * them back and forth between description strings and the
188 * corresponding numerical identifiers).
189 */
190
191static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530192{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200193 int i;
194 for (i = 0; boot_modes[i].name; i++)
195 if (boot_modes[i].id == id)
196 return boot_modes[i].name;
197 return NULL;
198}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530199
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200200int image_boot_mode_id(const char *boot_mode_name)
201{
202 int i;
203 for (i = 0; boot_modes[i].name; i++)
204 if (!strcmp(boot_modes[i].name, boot_mode_name))
205 return boot_modes[i].id;
206
207 return -1;
208}
209
210int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
211{
212 int i;
213 for (i = 0; nand_ecc_modes[i].name; i++)
214 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
215 return nand_ecc_modes[i].id;
216 return -1;
217}
218
219static struct image_cfg_element *
220image_find_option(unsigned int optiontype)
221{
222 int i;
223
224 for (i = 0; i < cfgn; i++) {
225 if (image_cfg[i].type == optiontype)
226 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530227 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200228
229 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530230}
231
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200232static unsigned int
233image_count_options(unsigned int optiontype)
234{
235 int i;
236 unsigned int count = 0;
237
238 for (i = 0; i < cfgn; i++)
239 if (image_cfg[i].type == optiontype)
240 count++;
241
242 return count;
243}
244
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530245/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200246 * Compute a 8-bit checksum of a memory area. This algorithm follows
247 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530248 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200249static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530250{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200251 uint8_t csum = 0;
252 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530253
254 /* check len and return zero checksum if invalid */
255 if (!len)
256 return 0;
257
258 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200259 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530260 p++;
261 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200262
263 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530264}
265
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200266static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530267{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200268 uint32_t csum = 0;
269 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530270
271 /* check len and return zero checksum if invalid */
272 if (!len)
273 return 0;
274
275 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200276 fprintf(stderr, "Length %d is not in multiple of %zu\n",
277 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530278 return 0;
279 }
280
281 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200282 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530283 p++;
284 len -= sizeof(uint32_t);
285 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200286
287 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530288}
289
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200290static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
291 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530292{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200293 struct image_cfg_element *e;
294 size_t headersz;
295 struct main_hdr_v0 *main_hdr;
296 struct ext_hdr_v0 *ext_hdr;
297 void *image;
298 int has_ext = 0;
299
300 /*
301 * Calculate the size of the header and the size of the
302 * payload
303 */
304 headersz = sizeof(struct main_hdr_v0);
305
306 if (image_count_options(IMAGE_CFG_DATA) > 0) {
307 has_ext = 1;
308 headersz += sizeof(struct ext_hdr_v0);
309 }
310
311 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
312 fprintf(stderr, "More than one payload, not possible\n");
313 return NULL;
314 }
315
316 image = malloc(headersz);
317 if (!image) {
318 fprintf(stderr, "Cannot allocate memory for image\n");
319 return NULL;
320 }
321
322 memset(image, 0, headersz);
323
324 main_hdr = image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530325
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200326 /* Fill in the main header */
327 main_hdr->blocksize = payloadsz + sizeof(uint32_t);
328 main_hdr->srcaddr = headersz;
329 main_hdr->ext = has_ext;
330 main_hdr->destaddr = params->addr;
331 main_hdr->execaddr = params->ep;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530332
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200333 e = image_find_option(IMAGE_CFG_BOOT_FROM);
334 if (e)
335 main_hdr->blockid = e->bootfrom;
336 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
337 if (e)
338 main_hdr->nandeccmode = e->nandeccmode;
339 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
340 if (e)
341 main_hdr->nandpagesize = e->nandpagesz;
342 main_hdr->checksum = image_checksum8(image,
343 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530344
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200345 /* Generate the ext header */
346 if (has_ext) {
347 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530348
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200349 ext_hdr = image + sizeof(struct main_hdr_v0);
350 ext_hdr->offset = 0x40;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530351
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200352 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
353 e = &image_cfg[cfgi];
354 if (e->type != IMAGE_CFG_DATA)
355 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530356
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200357 ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
358 ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
359 datai++;
360 }
361
362 ext_hdr->checksum = image_checksum8(ext_hdr,
363 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530364 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530365
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200366 *imagesz = headersz;
367 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530368}
369
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200370static size_t image_headersz_v1(struct image_tool_params *params,
371 int *hasext)
372{
373 struct image_cfg_element *binarye;
374 size_t headersz;
375 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530376
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200377 /*
378 * Calculate the size of the header and the size of the
379 * payload
380 */
381 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530382
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200383 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
384 fprintf(stderr, "More than one binary blob, not supported\n");
385 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530386 }
387
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200388 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
389 fprintf(stderr, "More than one payload, not possible\n");
390 return 0;
391 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530392
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200393 binarye = image_find_option(IMAGE_CFG_BINARY);
394 if (binarye) {
395 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530396
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200397 ret = stat(binarye->binary.file, &s);
398 if (ret < 0) {
399 char *cwd = get_current_dir_name();
400 fprintf(stderr,
401 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
402 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
403 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
404 binarye->binary.file, cwd);
405 free(cwd);
406 return 0;
407 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530408
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200409 headersz += s.st_size +
410 binarye->binary.nargs * sizeof(unsigned int);
411 if (hasext)
412 *hasext = 1;
413 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530414
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200415 /*
416 * The payload should be aligned on some reasonable
417 * boundary
418 */
419 return ALIGN_SUP(headersz, 4096);
420}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530421
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200422static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
423 int payloadsz)
424{
425 struct image_cfg_element *e, *binarye;
426 struct main_hdr_v1 *main_hdr;
427 size_t headersz;
428 void *image, *cur;
429 int hasext = 0;
430 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530431
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200432 /*
433 * Calculate the size of the header and the size of the
434 * payload
435 */
436 headersz = image_headersz_v1(params, &hasext);
437 if (headersz == 0)
438 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530439
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200440 image = malloc(headersz);
441 if (!image) {
442 fprintf(stderr, "Cannot allocate memory for image\n");
443 return NULL;
444 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530445
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200446 memset(image, 0, headersz);
447
448 cur = main_hdr = image;
449 cur += sizeof(struct main_hdr_v1);
450
451 /* Fill the main header */
452 main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t);
453 main_hdr->headersz_lsb = headersz & 0xFFFF;
454 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
455 main_hdr->destaddr = params->addr;
456 main_hdr->execaddr = params->ep;
457 main_hdr->srcaddr = headersz;
458 main_hdr->ext = hasext;
459 main_hdr->version = 1;
460 e = image_find_option(IMAGE_CFG_BOOT_FROM);
461 if (e)
462 main_hdr->blockid = e->bootfrom;
463 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
464 if (e)
465 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
466 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
467 if (e)
468 main_hdr->nandbadblklocation = e->nandbadblklocation;
469
470 binarye = image_find_option(IMAGE_CFG_BINARY);
471 if (binarye) {
472 struct opt_hdr_v1 *hdr = cur;
473 unsigned int *args;
474 size_t binhdrsz;
475 struct stat s;
476 int argi;
477 FILE *bin;
478
479 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
480
481 bin = fopen(binarye->binary.file, "r");
482 if (!bin) {
483 fprintf(stderr, "Cannot open binary file %s\n",
484 binarye->binary.file);
485 return NULL;
486 }
487
488 fstat(fileno(bin), &s);
489
490 binhdrsz = sizeof(struct opt_hdr_v1) +
491 (binarye->binary.nargs + 1) * sizeof(unsigned int) +
492 s.st_size;
493 hdr->headersz_lsb = binhdrsz & 0xFFFF;
494 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
495
496 cur += sizeof(struct opt_hdr_v1);
497
498 args = cur;
499 *args = binarye->binary.nargs;
500 args++;
501 for (argi = 0; argi < binarye->binary.nargs; argi++)
502 args[argi] = binarye->binary.args[argi];
503
504 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
505
506 ret = fread(cur, s.st_size, 1, bin);
507 if (ret != 1) {
508 fprintf(stderr,
509 "Could not read binary image %s\n",
510 binarye->binary.file);
511 return NULL;
512 }
513
514 fclose(bin);
515
516 cur += s.st_size;
517
518 /*
519 * For now, we don't support more than one binary
520 * header, and no other header types are
521 * supported. So, the binary header is necessarily the
522 * last one
523 */
524 *((unsigned char *)cur) = 0;
525
526 cur += sizeof(uint32_t);
527 }
528
529 /* Calculate and set the header checksum */
530 main_hdr->checksum = image_checksum8(main_hdr, headersz);
531
532 *imagesz = headersz;
533 return image;
534}
535
536static int image_create_config_parse_oneline(char *line,
537 struct image_cfg_element *el)
538{
539 char *keyword, *saveptr;
540 char deliminiters[] = " \t";
541
542 keyword = strtok_r(line, deliminiters, &saveptr);
543 if (!strcmp(keyword, "VERSION")) {
544 char *value = strtok_r(NULL, deliminiters, &saveptr);
545 el->type = IMAGE_CFG_VERSION;
546 el->version = atoi(value);
547 } else if (!strcmp(keyword, "BOOT_FROM")) {
548 char *value = strtok_r(NULL, deliminiters, &saveptr);
549 el->type = IMAGE_CFG_BOOT_FROM;
550 el->bootfrom = image_boot_mode_id(value);
551 if (el->bootfrom < 0) {
552 fprintf(stderr,
553 "Invalid boot media '%s'\n", value);
554 return -1;
555 }
556 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
557 char *value = strtok_r(NULL, deliminiters, &saveptr);
558 el->type = IMAGE_CFG_NAND_BLKSZ;
559 el->nandblksz = strtoul(value, NULL, 16);
560 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
561 char *value = strtok_r(NULL, deliminiters, &saveptr);
562 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
563 el->nandbadblklocation =
564 strtoul(value, NULL, 16);
565 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
566 char *value = strtok_r(NULL, deliminiters, &saveptr);
567 el->type = IMAGE_CFG_NAND_ECC_MODE;
568 el->nandeccmode = image_nand_ecc_mode_id(value);
569 if (el->nandeccmode < 0) {
570 fprintf(stderr,
571 "Invalid NAND ECC mode '%s'\n", value);
572 return -1;
573 }
574 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
575 char *value = strtok_r(NULL, deliminiters, &saveptr);
576 el->type = IMAGE_CFG_NAND_PAGESZ;
577 el->nandpagesz = strtoul(value, NULL, 16);
578 } else if (!strcmp(keyword, "BINARY")) {
579 char *value = strtok_r(NULL, deliminiters, &saveptr);
580 int argi = 0;
581
582 el->type = IMAGE_CFG_BINARY;
583 el->binary.file = strdup(value);
584 while (1) {
585 value = strtok_r(NULL, deliminiters, &saveptr);
586 if (!value)
587 break;
588 el->binary.args[argi] = strtoul(value, NULL, 16);
589 argi++;
590 if (argi >= BINARY_MAX_ARGS) {
591 fprintf(stderr,
592 "Too many argument for binary\n");
593 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530594 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530595 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200596 el->binary.nargs = argi;
597 } else if (!strcmp(keyword, "DATA")) {
598 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
599 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
600
601 if (!value1 || !value2) {
602 fprintf(stderr,
603 "Invalid number of arguments for DATA\n");
604 return -1;
605 }
606
607 el->type = IMAGE_CFG_DATA;
608 el->regdata.raddr = strtoul(value1, NULL, 16);
609 el->regdata.rdata = strtoul(value2, NULL, 16);
610 } else {
611 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530612 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530613
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200614 return 0;
615}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530616
617/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200618 * Parse the configuration file 'fcfg' into the array of configuration
619 * elements 'image_cfg', and return the number of configuration
620 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530621 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200622static int image_create_config_parse(FILE *fcfg)
623{
624 int ret;
625 int cfgi = 0;
626
627 /* Parse the configuration file */
628 while (!feof(fcfg)) {
629 char *line;
630 char buf[256];
631
632 /* Read the current line */
633 memset(buf, 0, sizeof(buf));
634 line = fgets(buf, sizeof(buf), fcfg);
635 if (!line)
636 break;
637
638 /* Ignore useless lines */
639 if (line[0] == '\n' || line[0] == '#')
640 continue;
641
642 /* Strip final newline */
643 if (line[strlen(line) - 1] == '\n')
644 line[strlen(line) - 1] = 0;
645
646 /* Parse the current line */
647 ret = image_create_config_parse_oneline(line,
648 &image_cfg[cfgi]);
649 if (ret)
650 return ret;
651
652 cfgi++;
653
654 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
655 fprintf(stderr,
656 "Too many configuration elements in .cfg file\n");
657 return -1;
658 }
659 }
660
661 cfgn = cfgi;
662 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530663}
664
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200665static int image_get_version(void)
666{
667 struct image_cfg_element *e;
668
669 e = image_find_option(IMAGE_CFG_VERSION);
670 if (!e)
671 return -1;
672
673 return e->version;
674}
675
676static int image_version_file(const char *input)
677{
678 FILE *fcfg;
679 int version;
680 int ret;
681
682 fcfg = fopen(input, "r");
683 if (!fcfg) {
684 fprintf(stderr, "Could not open input file %s\n", input);
685 return -1;
686 }
687
688 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
689 sizeof(struct image_cfg_element));
690 if (!image_cfg) {
691 fprintf(stderr, "Cannot allocate memory\n");
692 fclose(fcfg);
693 return -1;
694 }
695
696 memset(image_cfg, 0,
697 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
698 rewind(fcfg);
699
700 ret = image_create_config_parse(fcfg);
701 fclose(fcfg);
702 if (ret) {
703 free(image_cfg);
704 return -1;
705 }
706
707 version = image_get_version();
708 /* Fallback to version 0 is no version is provided in the cfg file */
709 if (version == -1)
710 version = 0;
711
712 free(image_cfg);
713
714 return version;
715}
716
717static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700718 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530719{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200720 FILE *fcfg;
721 void *image = NULL;
722 int version;
723 size_t headersz;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530724 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200725 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530726 int size;
727
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200728 fcfg = fopen(params->imagename, "r");
729 if (!fcfg) {
730 fprintf(stderr, "Could not open input file %s\n",
731 params->imagename);
732 exit(EXIT_FAILURE);
733 }
734
735 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
736 sizeof(struct image_cfg_element));
737 if (!image_cfg) {
738 fprintf(stderr, "Cannot allocate memory\n");
739 fclose(fcfg);
740 exit(EXIT_FAILURE);
741 }
742
743 memset(image_cfg, 0,
744 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
745 rewind(fcfg);
746
747 ret = image_create_config_parse(fcfg);
748 fclose(fcfg);
749 if (ret) {
750 free(image_cfg);
751 exit(EXIT_FAILURE);
752 }
753
754 version = image_get_version();
755 /* Fallback to version 0 is no version is provided in the cfg file */
756 if (version == -1)
757 version = 0;
758
759 if (version == 0)
760 image = image_create_v0(&headersz, params, sbuf->st_size);
761 else if (version == 1)
762 image = image_create_v1(&headersz, params, sbuf->st_size);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530763
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200764 if (!image) {
765 fprintf(stderr, "Could not create image\n");
766 free(image_cfg);
767 exit(EXIT_FAILURE);
768 }
769
770 free(image_cfg);
771
772 /* Build and add image checksum header */
773 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
774 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530775 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200776 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530777 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200778 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530779 }
780
781 sbuf->st_size += sizeof(uint32_t);
782
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200783 /* Finally copy the header into the image area */
784 memcpy(ptr, image, headersz);
785
786 free(image);
787}
788
789static void kwbimage_print_header(const void *ptr)
790{
791 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
792
793 printf("Image Type: MVEBU Boot from %s Image\n",
794 image_boot_mode_name(mhdr->blockid));
795 printf("Data Size: ");
796 printf("Image version:%d\n", image_version((void *)ptr));
797 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
798 printf("Load Address: %08x\n", mhdr->destaddr);
799 printf("Entry Point: %08x\n", mhdr->execaddr);
800}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530801
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200802static int kwbimage_check_image_types(uint8_t type)
803{
804 if (type == IH_TYPE_KWBIMAGE)
805 return EXIT_SUCCESS;
806 else
807 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530808}
809
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200810static int kwbimage_verify_header(unsigned char *ptr, int image_size,
811 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530812{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200813 struct main_hdr_v0 *main_hdr;
814 struct ext_hdr_v0 *ext_hdr;
815 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530816
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200817 main_hdr = (void *)ptr;
818 checksum = image_checksum8(ptr,
819 sizeof(struct main_hdr_v0));
820 if (checksum != main_hdr->checksum)
821 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530822
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200823 /* Only version 0 extended header has checksum */
824 if (image_version((void *)ptr) == 0) {
825 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
826 checksum = image_checksum8(ext_hdr,
827 sizeof(struct ext_hdr_v0));
828 if (checksum != ext_hdr->checksum)
829 return -FDT_ERR_BADSTRUCTURE;
830 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530831
832 return 0;
833}
834
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200835static int kwbimage_generate(struct image_tool_params *params,
836 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530837{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200838 int alloc_len;
839 void *hdr;
840 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530841
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200842 version = image_version_file(params->imagename);
843 if (version == 0) {
844 alloc_len = sizeof(struct main_hdr_v0) +
845 sizeof(struct ext_hdr_v0);
846 } else {
847 alloc_len = image_headersz_v1(params, NULL);
848 }
849
850 hdr = malloc(alloc_len);
851 if (!hdr) {
852 fprintf(stderr, "%s: malloc return failure: %s\n",
853 params->cmdname, strerror(errno));
854 exit(EXIT_FAILURE);
855 }
856
857 memset(hdr, 0, alloc_len);
858 tparams->header_size = alloc_len;
859 tparams->hdr = hdr;
860
861 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530862}
863
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200864/*
865 * Report Error if xflag is set in addition to default
866 */
867static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530868{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200869 if (!strlen(params->imagename)) {
870 fprintf(stderr, "Error:%s - Configuration file not specified, "
871 "it is needed for kwbimage generation\n",
872 params->cmdname);
873 return CFG_INVALID;
874 }
875
876 return (params->dflag && (params->fflag || params->lflag)) ||
877 (params->fflag && (params->dflag || params->lflag)) ||
878 (params->lflag && (params->dflag || params->fflag)) ||
879 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530880}
881
882/*
883 * kwbimage type parameters definition
884 */
885static struct image_type_params kwbimage_params = {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200886 .name = "Marvell MVEBU Boot Image support",
887 .header_size = 0, /* no fixed header size */
888 .hdr = NULL,
889 .vrec_header = kwbimage_generate,
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530890 .check_image_type = kwbimage_check_image_types,
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200891 .verify_header = kwbimage_verify_header,
892 .print_header = kwbimage_print_header,
893 .set_header = kwbimage_set_header,
894 .check_params = kwbimage_check_params,
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530895};
896
897void init_kwb_image_type (void)
898{
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700899 register_image_type(&kwbimage_params);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530900}