blob: 369aba7bcab9d00e6c965354ff05bb579d420809 [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 +020020static struct image_cfg_element *image_cfg;
21static int cfgn;
22
23struct boot_mode {
24 unsigned int id;
25 const char *name;
26};
27
28struct boot_mode boot_modes[] = {
29 { 0x4D, "i2c" },
30 { 0x5A, "spi" },
31 { 0x8B, "nand" },
32 { 0x78, "sata" },
33 { 0x9C, "pex" },
34 { 0x69, "uart" },
Stefan Roese539fe4a2015-07-20 11:20:37 +020035 { 0xAE, "sdio" },
Stefan Roese3b8b19d2014-10-22 12:13:23 +020036 {},
Prafulla Wadaskar07329412009-09-07 15:05:02 +053037};
38
Stefan Roese3b8b19d2014-10-22 12:13:23 +020039struct nand_ecc_mode {
40 unsigned int id;
41 const char *name;
42};
43
44struct nand_ecc_mode nand_ecc_modes[] = {
45 { 0x00, "default" },
46 { 0x01, "hamming" },
47 { 0x02, "rs" },
48 { 0x03, "disabled" },
49 {},
50};
51
52/* Used to identify an undefined execution or destination address */
53#define ADDR_INVALID ((uint32_t)-1)
54
55#define BINARY_MAX_ARGS 8
56
57/* In-memory representation of a line of the configuration file */
58struct image_cfg_element {
59 enum {
60 IMAGE_CFG_VERSION = 0x1,
61 IMAGE_CFG_BOOT_FROM,
62 IMAGE_CFG_DEST_ADDR,
63 IMAGE_CFG_EXEC_ADDR,
64 IMAGE_CFG_NAND_BLKSZ,
65 IMAGE_CFG_NAND_BADBLK_LOCATION,
66 IMAGE_CFG_NAND_ECC_MODE,
67 IMAGE_CFG_NAND_PAGESZ,
68 IMAGE_CFG_BINARY,
69 IMAGE_CFG_PAYLOAD,
70 IMAGE_CFG_DATA,
71 } type;
72 union {
73 unsigned int version;
74 unsigned int bootfrom;
75 struct {
76 const char *file;
77 unsigned int args[BINARY_MAX_ARGS];
78 unsigned int nargs;
79 } binary;
80 const char *payload;
81 unsigned int dstaddr;
82 unsigned int execaddr;
83 unsigned int nandblksz;
84 unsigned int nandbadblklocation;
85 unsigned int nandeccmode;
86 unsigned int nandpagesz;
87 struct ext_hdr_v0_reg regdata;
88 };
89};
90
91#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskar07329412009-09-07 15:05:02 +053092
93/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020094 * Utility functions to manipulate boot mode and ecc modes (convert
95 * them back and forth between description strings and the
96 * corresponding numerical identifiers).
97 */
98
99static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530100{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200101 int i;
102 for (i = 0; boot_modes[i].name; i++)
103 if (boot_modes[i].id == id)
104 return boot_modes[i].name;
105 return NULL;
106}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530107
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200108int image_boot_mode_id(const char *boot_mode_name)
109{
110 int i;
111 for (i = 0; boot_modes[i].name; i++)
112 if (!strcmp(boot_modes[i].name, boot_mode_name))
113 return boot_modes[i].id;
114
115 return -1;
116}
117
118int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
119{
120 int i;
121 for (i = 0; nand_ecc_modes[i].name; i++)
122 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
123 return nand_ecc_modes[i].id;
124 return -1;
125}
126
127static struct image_cfg_element *
128image_find_option(unsigned int optiontype)
129{
130 int i;
131
132 for (i = 0; i < cfgn; i++) {
133 if (image_cfg[i].type == optiontype)
134 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530135 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200136
137 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530138}
139
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200140static unsigned int
141image_count_options(unsigned int optiontype)
142{
143 int i;
144 unsigned int count = 0;
145
146 for (i = 0; i < cfgn; i++)
147 if (image_cfg[i].type == optiontype)
148 count++;
149
150 return count;
151}
152
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530153/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200154 * Compute a 8-bit checksum of a memory area. This algorithm follows
155 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530156 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200157static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530158{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200159 uint8_t csum = 0;
160 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530161
162 /* check len and return zero checksum if invalid */
163 if (!len)
164 return 0;
165
166 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200167 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530168 p++;
169 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200170
171 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530172}
173
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200174static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530175{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200176 uint32_t csum = 0;
177 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530178
179 /* check len and return zero checksum if invalid */
180 if (!len)
181 return 0;
182
183 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200184 fprintf(stderr, "Length %d is not in multiple of %zu\n",
185 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530186 return 0;
187 }
188
189 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200190 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530191 p++;
192 len -= sizeof(uint32_t);
193 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200194
195 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530196}
197
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200198static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
199 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530200{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200201 struct image_cfg_element *e;
202 size_t headersz;
203 struct main_hdr_v0 *main_hdr;
204 struct ext_hdr_v0 *ext_hdr;
205 void *image;
206 int has_ext = 0;
207
208 /*
209 * Calculate the size of the header and the size of the
210 * payload
211 */
212 headersz = sizeof(struct main_hdr_v0);
213
214 if (image_count_options(IMAGE_CFG_DATA) > 0) {
215 has_ext = 1;
216 headersz += sizeof(struct ext_hdr_v0);
217 }
218
219 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
220 fprintf(stderr, "More than one payload, not possible\n");
221 return NULL;
222 }
223
224 image = malloc(headersz);
225 if (!image) {
226 fprintf(stderr, "Cannot allocate memory for image\n");
227 return NULL;
228 }
229
230 memset(image, 0, headersz);
231
232 main_hdr = image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530233
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200234 /* Fill in the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100235 main_hdr->blocksize =
236 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
237 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200238 main_hdr->ext = has_ext;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100239 main_hdr->destaddr = cpu_to_le32(params->addr);
240 main_hdr->execaddr = cpu_to_le32(params->ep);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530241
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200242 e = image_find_option(IMAGE_CFG_BOOT_FROM);
243 if (e)
244 main_hdr->blockid = e->bootfrom;
245 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
246 if (e)
247 main_hdr->nandeccmode = e->nandeccmode;
248 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
249 if (e)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100250 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200251 main_hdr->checksum = image_checksum8(image,
252 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530253
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200254 /* Generate the ext header */
255 if (has_ext) {
256 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530257
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200258 ext_hdr = image + sizeof(struct main_hdr_v0);
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100259 ext_hdr->offset = cpu_to_le32(0x40);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530260
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200261 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
262 e = &image_cfg[cfgi];
263 if (e->type != IMAGE_CFG_DATA)
264 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530265
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100266 ext_hdr->rcfg[datai].raddr =
267 cpu_to_le32(e->regdata.raddr);
268 ext_hdr->rcfg[datai].rdata =
269 cpu_to_le32(e->regdata.rdata);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200270 datai++;
271 }
272
273 ext_hdr->checksum = image_checksum8(ext_hdr,
274 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530275 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530276
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200277 *imagesz = headersz;
278 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530279}
280
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200281static size_t image_headersz_v1(struct image_tool_params *params,
282 int *hasext)
283{
284 struct image_cfg_element *binarye;
285 size_t headersz;
286 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530287
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200288 /*
289 * Calculate the size of the header and the size of the
290 * payload
291 */
292 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530293
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200294 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
295 fprintf(stderr, "More than one binary blob, not supported\n");
296 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530297 }
298
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200299 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
300 fprintf(stderr, "More than one payload, not possible\n");
301 return 0;
302 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530303
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200304 binarye = image_find_option(IMAGE_CFG_BINARY);
305 if (binarye) {
306 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530307
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200308 ret = stat(binarye->binary.file, &s);
309 if (ret < 0) {
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200310 char cwd[PATH_MAX];
311 char *dir = cwd;
312
313 memset(cwd, 0, sizeof(cwd));
314 if (!getcwd(cwd, sizeof(cwd))) {
315 dir = "current working directory";
316 perror("getcwd() failed");
317 }
318
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200319 fprintf(stderr,
320 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
321 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
322 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200323 binarye->binary.file, dir);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200324 return 0;
325 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530326
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100327 headersz += sizeof(struct opt_hdr_v1) +
328 s.st_size +
329 (binarye->binary.nargs + 2) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200330 if (hasext)
331 *hasext = 1;
332 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530333
Stefan Roese69e9dde2015-07-20 11:20:38 +0200334#if defined(CONFIG_SYS_U_BOOT_OFFS)
335 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Kevin Smith88809492015-03-16 14:58:21 +0000336 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese69e9dde2015-07-20 11:20:38 +0200337 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
338 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
339 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smith88809492015-03-16 14:58:21 +0000340 return 0;
341 } else {
Stefan Roese69e9dde2015-07-20 11:20:38 +0200342 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smith88809492015-03-16 14:58:21 +0000343 }
344#endif
345
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200346 /*
347 * The payload should be aligned on some reasonable
348 * boundary
349 */
350 return ALIGN_SUP(headersz, 4096);
351}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530352
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200353static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
354 int payloadsz)
355{
356 struct image_cfg_element *e, *binarye;
357 struct main_hdr_v1 *main_hdr;
358 size_t headersz;
359 void *image, *cur;
360 int hasext = 0;
361 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530362
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200363 /*
364 * Calculate the size of the header and the size of the
365 * payload
366 */
367 headersz = image_headersz_v1(params, &hasext);
368 if (headersz == 0)
369 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530370
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200371 image = malloc(headersz);
372 if (!image) {
373 fprintf(stderr, "Cannot allocate memory for image\n");
374 return NULL;
375 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530376
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200377 memset(image, 0, headersz);
378
379 cur = main_hdr = image;
380 cur += sizeof(struct main_hdr_v1);
381
382 /* Fill the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100383 main_hdr->blocksize =
384 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
385 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200386 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100387 main_hdr->destaddr = cpu_to_le32(params->addr);
388 main_hdr->execaddr = cpu_to_le32(params->ep);
389 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200390 main_hdr->ext = hasext;
391 main_hdr->version = 1;
392 e = image_find_option(IMAGE_CFG_BOOT_FROM);
393 if (e)
394 main_hdr->blockid = e->bootfrom;
395 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
396 if (e)
397 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
398 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
399 if (e)
400 main_hdr->nandbadblklocation = e->nandbadblklocation;
401
402 binarye = image_find_option(IMAGE_CFG_BINARY);
403 if (binarye) {
404 struct opt_hdr_v1 *hdr = cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100405 uint32_t *args;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200406 size_t binhdrsz;
407 struct stat s;
408 int argi;
409 FILE *bin;
410
411 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
412
413 bin = fopen(binarye->binary.file, "r");
414 if (!bin) {
415 fprintf(stderr, "Cannot open binary file %s\n",
416 binarye->binary.file);
417 return NULL;
418 }
419
420 fstat(fileno(bin), &s);
421
422 binhdrsz = sizeof(struct opt_hdr_v1) +
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100423 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200424 s.st_size;
Stefan Roesea4279a52015-10-28 07:53:58 +0100425
426 /*
427 * The size includes the binary image size, rounded
428 * up to a 4-byte boundary. Plus 4 bytes for the
429 * next-header byte and 3-byte alignment at the end.
430 */
431 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100432 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200433 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
434
435 cur += sizeof(struct opt_hdr_v1);
436
437 args = cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100438 *args = cpu_to_le32(binarye->binary.nargs);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200439 args++;
440 for (argi = 0; argi < binarye->binary.nargs; argi++)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100441 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200442
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100443 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200444
445 ret = fread(cur, s.st_size, 1, bin);
446 if (ret != 1) {
447 fprintf(stderr,
448 "Could not read binary image %s\n",
449 binarye->binary.file);
450 return NULL;
451 }
452
453 fclose(bin);
454
Stefan Roesea4279a52015-10-28 07:53:58 +0100455 cur += ALIGN_SUP(s.st_size, 4);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200456
457 /*
458 * For now, we don't support more than one binary
459 * header, and no other header types are
460 * supported. So, the binary header is necessarily the
461 * last one
462 */
Stefan Roesea4279a52015-10-28 07:53:58 +0100463 *((uint32_t *)cur) = 0x00000000;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200464
465 cur += sizeof(uint32_t);
466 }
467
468 /* Calculate and set the header checksum */
469 main_hdr->checksum = image_checksum8(main_hdr, headersz);
470
471 *imagesz = headersz;
472 return image;
473}
474
475static int image_create_config_parse_oneline(char *line,
476 struct image_cfg_element *el)
477{
478 char *keyword, *saveptr;
479 char deliminiters[] = " \t";
480
481 keyword = strtok_r(line, deliminiters, &saveptr);
482 if (!strcmp(keyword, "VERSION")) {
483 char *value = strtok_r(NULL, deliminiters, &saveptr);
484 el->type = IMAGE_CFG_VERSION;
485 el->version = atoi(value);
486 } else if (!strcmp(keyword, "BOOT_FROM")) {
487 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200488 int ret = image_boot_mode_id(value);
489 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200490 fprintf(stderr,
491 "Invalid boot media '%s'\n", value);
492 return -1;
493 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200494 el->type = IMAGE_CFG_BOOT_FROM;
495 el->bootfrom = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200496 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
497 char *value = strtok_r(NULL, deliminiters, &saveptr);
498 el->type = IMAGE_CFG_NAND_BLKSZ;
499 el->nandblksz = strtoul(value, NULL, 16);
500 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
501 char *value = strtok_r(NULL, deliminiters, &saveptr);
502 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
503 el->nandbadblklocation =
504 strtoul(value, NULL, 16);
505 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
506 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200507 int ret = image_nand_ecc_mode_id(value);
508 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200509 fprintf(stderr,
510 "Invalid NAND ECC mode '%s'\n", value);
511 return -1;
512 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200513 el->type = IMAGE_CFG_NAND_ECC_MODE;
514 el->nandeccmode = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200515 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
516 char *value = strtok_r(NULL, deliminiters, &saveptr);
517 el->type = IMAGE_CFG_NAND_PAGESZ;
518 el->nandpagesz = strtoul(value, NULL, 16);
519 } else if (!strcmp(keyword, "BINARY")) {
520 char *value = strtok_r(NULL, deliminiters, &saveptr);
521 int argi = 0;
522
523 el->type = IMAGE_CFG_BINARY;
524 el->binary.file = strdup(value);
525 while (1) {
526 value = strtok_r(NULL, deliminiters, &saveptr);
527 if (!value)
528 break;
529 el->binary.args[argi] = strtoul(value, NULL, 16);
530 argi++;
531 if (argi >= BINARY_MAX_ARGS) {
532 fprintf(stderr,
533 "Too many argument for binary\n");
534 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530535 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530536 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200537 el->binary.nargs = argi;
538 } else if (!strcmp(keyword, "DATA")) {
539 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
540 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
541
542 if (!value1 || !value2) {
543 fprintf(stderr,
544 "Invalid number of arguments for DATA\n");
545 return -1;
546 }
547
548 el->type = IMAGE_CFG_DATA;
549 el->regdata.raddr = strtoul(value1, NULL, 16);
550 el->regdata.rdata = strtoul(value2, NULL, 16);
551 } else {
552 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530553 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530554
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200555 return 0;
556}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530557
558/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200559 * Parse the configuration file 'fcfg' into the array of configuration
560 * elements 'image_cfg', and return the number of configuration
561 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530562 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200563static int image_create_config_parse(FILE *fcfg)
564{
565 int ret;
566 int cfgi = 0;
567
568 /* Parse the configuration file */
569 while (!feof(fcfg)) {
570 char *line;
571 char buf[256];
572
573 /* Read the current line */
574 memset(buf, 0, sizeof(buf));
575 line = fgets(buf, sizeof(buf), fcfg);
576 if (!line)
577 break;
578
579 /* Ignore useless lines */
580 if (line[0] == '\n' || line[0] == '#')
581 continue;
582
583 /* Strip final newline */
584 if (line[strlen(line) - 1] == '\n')
585 line[strlen(line) - 1] = 0;
586
587 /* Parse the current line */
588 ret = image_create_config_parse_oneline(line,
589 &image_cfg[cfgi]);
590 if (ret)
591 return ret;
592
593 cfgi++;
594
595 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
596 fprintf(stderr,
597 "Too many configuration elements in .cfg file\n");
598 return -1;
599 }
600 }
601
602 cfgn = cfgi;
603 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530604}
605
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200606static int image_get_version(void)
607{
608 struct image_cfg_element *e;
609
610 e = image_find_option(IMAGE_CFG_VERSION);
611 if (!e)
612 return -1;
613
614 return e->version;
615}
616
617static int image_version_file(const char *input)
618{
619 FILE *fcfg;
620 int version;
621 int ret;
622
623 fcfg = fopen(input, "r");
624 if (!fcfg) {
625 fprintf(stderr, "Could not open input file %s\n", input);
626 return -1;
627 }
628
629 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
630 sizeof(struct image_cfg_element));
631 if (!image_cfg) {
632 fprintf(stderr, "Cannot allocate memory\n");
633 fclose(fcfg);
634 return -1;
635 }
636
637 memset(image_cfg, 0,
638 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
639 rewind(fcfg);
640
641 ret = image_create_config_parse(fcfg);
642 fclose(fcfg);
643 if (ret) {
644 free(image_cfg);
645 return -1;
646 }
647
648 version = image_get_version();
649 /* Fallback to version 0 is no version is provided in the cfg file */
650 if (version == -1)
651 version = 0;
652
653 free(image_cfg);
654
655 return version;
656}
657
658static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700659 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530660{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200661 FILE *fcfg;
662 void *image = NULL;
663 int version;
Łukasz Majewskif04dab42014-11-21 09:22:43 +0100664 size_t headersz = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530665 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200666 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530667 int size;
668
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200669 fcfg = fopen(params->imagename, "r");
670 if (!fcfg) {
671 fprintf(stderr, "Could not open input file %s\n",
672 params->imagename);
673 exit(EXIT_FAILURE);
674 }
675
676 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
677 sizeof(struct image_cfg_element));
678 if (!image_cfg) {
679 fprintf(stderr, "Cannot allocate memory\n");
680 fclose(fcfg);
681 exit(EXIT_FAILURE);
682 }
683
684 memset(image_cfg, 0,
685 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
686 rewind(fcfg);
687
688 ret = image_create_config_parse(fcfg);
689 fclose(fcfg);
690 if (ret) {
691 free(image_cfg);
692 exit(EXIT_FAILURE);
693 }
694
Stefan Roese48676a32015-09-01 13:46:35 +0200695 /* The MVEBU BootROM does not allow non word aligned payloads */
696 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
697
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200698 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100699 switch (version) {
700 /*
701 * Fallback to version 0 if no version is provided in the
702 * cfg file
703 */
704 case -1:
705 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200706 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100707 break;
708
709 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200710 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100711 break;
712
713 default:
714 fprintf(stderr, "Unsupported version %d\n", version);
715 free(image_cfg);
716 exit(EXIT_FAILURE);
717 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530718
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200719 if (!image) {
720 fprintf(stderr, "Could not create image\n");
721 free(image_cfg);
722 exit(EXIT_FAILURE);
723 }
724
725 free(image_cfg);
726
727 /* Build and add image checksum header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100728 checksum =
729 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200730 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530731 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200732 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530733 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200734 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530735 }
736
737 sbuf->st_size += sizeof(uint32_t);
738
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200739 /* Finally copy the header into the image area */
740 memcpy(ptr, image, headersz);
741
742 free(image);
743}
744
745static void kwbimage_print_header(const void *ptr)
746{
747 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
748
749 printf("Image Type: MVEBU Boot from %s Image\n",
750 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200751 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100752 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200753 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
754 printf("Load Address: %08x\n", mhdr->destaddr);
755 printf("Entry Point: %08x\n", mhdr->execaddr);
756}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530757
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200758static int kwbimage_check_image_types(uint8_t type)
759{
760 if (type == IH_TYPE_KWBIMAGE)
761 return EXIT_SUCCESS;
762 else
763 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530764}
765
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200766static int kwbimage_verify_header(unsigned char *ptr, int image_size,
767 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530768{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200769 struct main_hdr_v0 *main_hdr;
770 struct ext_hdr_v0 *ext_hdr;
771 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530772
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200773 main_hdr = (void *)ptr;
774 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100775 sizeof(struct main_hdr_v0)
776 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200777 if (checksum != main_hdr->checksum)
778 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530779
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200780 /* Only version 0 extended header has checksum */
781 if (image_version((void *)ptr) == 0) {
782 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
783 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100784 sizeof(struct ext_hdr_v0)
785 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200786 if (checksum != ext_hdr->checksum)
787 return -FDT_ERR_BADSTRUCTURE;
788 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530789
790 return 0;
791}
792
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200793static int kwbimage_generate(struct image_tool_params *params,
794 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530795{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200796 int alloc_len;
797 void *hdr;
798 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530799
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200800 version = image_version_file(params->imagename);
801 if (version == 0) {
802 alloc_len = sizeof(struct main_hdr_v0) +
803 sizeof(struct ext_hdr_v0);
804 } else {
805 alloc_len = image_headersz_v1(params, NULL);
806 }
807
808 hdr = malloc(alloc_len);
809 if (!hdr) {
810 fprintf(stderr, "%s: malloc return failure: %s\n",
811 params->cmdname, strerror(errno));
812 exit(EXIT_FAILURE);
813 }
814
815 memset(hdr, 0, alloc_len);
816 tparams->header_size = alloc_len;
817 tparams->hdr = hdr;
818
Stefan Roeseda43fd32015-11-24 09:14:59 +0100819 /*
820 * The resulting image needs to be 4-byte aligned. At least
821 * the Marvell hdrparser tool complains if its unaligned.
822 * By returning 1 here in this function, called via
823 * tparams->vrec_header() in mkimage.c, mkimage will
824 * automatically pad the the resulting image to a 4-byte
825 * size if necessary.
826 */
827 return 1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530828}
829
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200830/*
831 * Report Error if xflag is set in addition to default
832 */
833static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530834{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200835 if (!strlen(params->imagename)) {
836 fprintf(stderr, "Error:%s - Configuration file not specified, "
837 "it is needed for kwbimage generation\n",
838 params->cmdname);
839 return CFG_INVALID;
840 }
841
842 return (params->dflag && (params->fflag || params->lflag)) ||
843 (params->fflag && (params->dflag || params->lflag)) ||
844 (params->lflag && (params->dflag || params->fflag)) ||
845 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530846}
847
848/*
849 * kwbimage type parameters definition
850 */
Guilherme Maciel Ferreira28be1cf2015-01-15 02:48:07 -0200851U_BOOT_IMAGE_TYPE(
852 kwbimage,
853 "Marvell MVEBU Boot Image support",
854 0,
855 NULL,
856 kwbimage_check_params,
857 kwbimage_verify_header,
858 kwbimage_print_header,
859 kwbimage_set_header,
860 NULL,
861 kwbimage_check_image_types,
862 NULL,
863 kwbimage_generate
864);