blob: e04d31986fb5a379bb16c7288738e83ea494639e [file] [log] [blame]
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +05301/*
Stefan Roese4acd2d22014-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 Wadaskaraa0c7a82009-09-07 15:05:02 +05307 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
Stefan Roese4acd2d22014-10-22 12:13:23 +02009 *
10 * Not implemented: support for the register headers and secure
11 * headers in v1 images
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053012 */
13
Guilherme Maciel Ferreiraf86ed6a2013-12-01 12:43:10 -070014#include "imagetool.h"
Andreas Bießmanne5f1a582014-10-24 23:39:11 +020015#include <limits.h>
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053016#include <image.h>
Stefan Roese4acd2d22014-10-22 12:13:23 +020017#include <stdint.h>
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053018#include "kwbimage.h"
19
Stefan Roese4acd2d22014-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;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053026};
27
Stefan Roese4acd2d22014-10-22 12:13:23 +020028struct boot_mode boot_modes[] = {
29 { 0x4D, "i2c" },
30 { 0x5A, "spi" },
31 { 0x8B, "nand" },
32 { 0x78, "sata" },
33 { 0x9C, "pex" },
34 { 0x69, "uart" },
Stefan Roese1bbe63c2015-07-20 11:20:37 +020035 { 0xAE, "sdio" },
Stefan Roese4acd2d22014-10-22 12:13:23 +020036 {},
37};
38
39struct 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,
Chris Packham4bdb5472016-11-09 22:07:45 +130071 IMAGE_CFG_BAUDRATE,
Chris Packham2611c052016-11-09 22:21:45 +130072 IMAGE_CFG_DEBUG,
Stefan Roese4acd2d22014-10-22 12:13:23 +020073 } type;
74 union {
75 unsigned int version;
76 unsigned int bootfrom;
77 struct {
78 const char *file;
79 unsigned int args[BINARY_MAX_ARGS];
80 unsigned int nargs;
81 } binary;
82 const char *payload;
83 unsigned int dstaddr;
84 unsigned int execaddr;
85 unsigned int nandblksz;
86 unsigned int nandbadblklocation;
87 unsigned int nandeccmode;
88 unsigned int nandpagesz;
89 struct ext_hdr_v0_reg regdata;
Chris Packham4bdb5472016-11-09 22:07:45 +130090 unsigned int baudrate;
Chris Packham2611c052016-11-09 22:21:45 +130091 unsigned int debug;
Stefan Roese4acd2d22014-10-22 12:13:23 +020092 };
93};
94
95#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053096
97/*
Stefan Roese4acd2d22014-10-22 12:13:23 +020098 * Utility functions to manipulate boot mode and ecc modes (convert
99 * them back and forth between description strings and the
100 * corresponding numerical identifiers).
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530101 */
Stefan Roese4acd2d22014-10-22 12:13:23 +0200102
103static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530104{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200105 int i;
106 for (i = 0; boot_modes[i].name; i++)
107 if (boot_modes[i].id == id)
108 return boot_modes[i].name;
109 return NULL;
110}
111
112int image_boot_mode_id(const char *boot_mode_name)
113{
114 int i;
115 for (i = 0; boot_modes[i].name; i++)
116 if (!strcmp(boot_modes[i].name, boot_mode_name))
117 return boot_modes[i].id;
118
119 return -1;
120}
121
122int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
123{
124 int i;
125 for (i = 0; nand_ecc_modes[i].name; i++)
126 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
127 return nand_ecc_modes[i].id;
128 return -1;
129}
130
131static struct image_cfg_element *
132image_find_option(unsigned int optiontype)
133{
134 int i;
135
136 for (i = 0; i < cfgn; i++) {
137 if (image_cfg[i].type == optiontype)
138 return &image_cfg[i];
139 }
140
141 return NULL;
142}
143
144static unsigned int
145image_count_options(unsigned int optiontype)
146{
147 int i;
148 unsigned int count = 0;
149
150 for (i = 0; i < cfgn; i++)
151 if (image_cfg[i].type == optiontype)
152 count++;
153
154 return count;
155}
156
157/*
158 * Compute a 8-bit checksum of a memory area. This algorithm follows
159 * the requirements of the Marvell SoC BootROM specifications.
160 */
161static uint8_t image_checksum8(void *start, uint32_t len)
162{
163 uint8_t csum = 0;
164 uint8_t *p = start;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530165
166 /* check len and return zero checksum if invalid */
167 if (!len)
168 return 0;
169
170 do {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200171 csum += *p;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530172 p++;
173 } while (--len);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200174
175 return csum;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530176}
177
Stefan Roese4acd2d22014-10-22 12:13:23 +0200178static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530179{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200180 uint32_t csum = 0;
181 uint32_t *p = start;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530182
183 /* check len and return zero checksum if invalid */
184 if (!len)
185 return 0;
186
187 if (len % sizeof(uint32_t)) {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200188 fprintf(stderr, "Length %d is not in multiple of %zu\n",
189 len, sizeof(uint32_t));
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530190 return 0;
191 }
192
193 do {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200194 csum += *p;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530195 p++;
196 len -= sizeof(uint32_t);
197 } while (len > 0);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200198
199 return csum;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530200}
201
Chris Packham4bdb5472016-11-09 22:07:45 +1300202static uint8_t baudrate_to_option(unsigned int baudrate)
203{
204 switch (baudrate) {
205 case 2400:
206 return MAIN_HDR_V1_OPT_BAUD_2400;
207 case 4800:
208 return MAIN_HDR_V1_OPT_BAUD_4800;
209 case 9600:
210 return MAIN_HDR_V1_OPT_BAUD_9600;
211 case 19200:
212 return MAIN_HDR_V1_OPT_BAUD_19200;
213 case 38400:
214 return MAIN_HDR_V1_OPT_BAUD_38400;
215 case 57600:
216 return MAIN_HDR_V1_OPT_BAUD_57600;
217 case 115200:
218 return MAIN_HDR_V1_OPT_BAUD_115200;
219 default:
220 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
221 }
222}
223
Stefan Roese4acd2d22014-10-22 12:13:23 +0200224static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
225 int payloadsz)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530226{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200227 struct image_cfg_element *e;
228 size_t headersz;
229 struct main_hdr_v0 *main_hdr;
230 struct ext_hdr_v0 *ext_hdr;
231 void *image;
232 int has_ext = 0;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530233
Stefan Roese4acd2d22014-10-22 12:13:23 +0200234 /*
235 * Calculate the size of the header and the size of the
236 * payload
237 */
238 headersz = sizeof(struct main_hdr_v0);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530239
Stefan Roese4acd2d22014-10-22 12:13:23 +0200240 if (image_count_options(IMAGE_CFG_DATA) > 0) {
241 has_ext = 1;
242 headersz += sizeof(struct ext_hdr_v0);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530243 }
244
Stefan Roese4acd2d22014-10-22 12:13:23 +0200245 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
246 fprintf(stderr, "More than one payload, not possible\n");
247 return NULL;
248 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530249
Stefan Roese4acd2d22014-10-22 12:13:23 +0200250 image = malloc(headersz);
251 if (!image) {
252 fprintf(stderr, "Cannot allocate memory for image\n");
253 return NULL;
254 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530255
Stefan Roese4acd2d22014-10-22 12:13:23 +0200256 memset(image, 0, headersz);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530257
Stefan Roese4acd2d22014-10-22 12:13:23 +0200258 main_hdr = image;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530259
Stefan Roese4acd2d22014-10-22 12:13:23 +0200260 /* Fill in the main header */
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100261 main_hdr->blocksize =
262 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
263 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200264 main_hdr->ext = has_ext;
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100265 main_hdr->destaddr = cpu_to_le32(params->addr);
266 main_hdr->execaddr = cpu_to_le32(params->ep);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530267
Stefan Roese4acd2d22014-10-22 12:13:23 +0200268 e = image_find_option(IMAGE_CFG_BOOT_FROM);
269 if (e)
270 main_hdr->blockid = e->bootfrom;
271 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
272 if (e)
273 main_hdr->nandeccmode = e->nandeccmode;
274 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
275 if (e)
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100276 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200277 main_hdr->checksum = image_checksum8(image,
278 sizeof(struct main_hdr_v0));
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530279
Stefan Roese4acd2d22014-10-22 12:13:23 +0200280 /* Generate the ext header */
281 if (has_ext) {
282 int cfgi, datai;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530283
Stefan Roese4acd2d22014-10-22 12:13:23 +0200284 ext_hdr = image + sizeof(struct main_hdr_v0);
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100285 ext_hdr->offset = cpu_to_le32(0x40);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530286
Stefan Roese4acd2d22014-10-22 12:13:23 +0200287 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
288 e = &image_cfg[cfgi];
289 if (e->type != IMAGE_CFG_DATA)
290 continue;
291
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100292 ext_hdr->rcfg[datai].raddr =
293 cpu_to_le32(e->regdata.raddr);
294 ext_hdr->rcfg[datai].rdata =
295 cpu_to_le32(e->regdata.rdata);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200296 datai++;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530297 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530298
Stefan Roese4acd2d22014-10-22 12:13:23 +0200299 ext_hdr->checksum = image_checksum8(ext_hdr,
300 sizeof(struct ext_hdr_v0));
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530301 }
302
Stefan Roese4acd2d22014-10-22 12:13:23 +0200303 *imagesz = headersz;
304 return image;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530305}
306
Stefan Roese4acd2d22014-10-22 12:13:23 +0200307static size_t image_headersz_v1(struct image_tool_params *params,
308 int *hasext)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530309{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200310 struct image_cfg_element *binarye;
311 size_t headersz;
312 int ret;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530313
Stefan Roese4acd2d22014-10-22 12:13:23 +0200314 /*
315 * Calculate the size of the header and the size of the
316 * payload
317 */
318 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530319
Stefan Roese4acd2d22014-10-22 12:13:23 +0200320 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
321 fprintf(stderr, "More than one binary blob, not supported\n");
322 return 0;
323 }
324
325 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
326 fprintf(stderr, "More than one payload, not possible\n");
327 return 0;
328 }
329
330 binarye = image_find_option(IMAGE_CFG_BINARY);
331 if (binarye) {
332 struct stat s;
333
334 ret = stat(binarye->binary.file, &s);
335 if (ret < 0) {
Andreas Bießmanne5f1a582014-10-24 23:39:11 +0200336 char cwd[PATH_MAX];
337 char *dir = cwd;
338
339 memset(cwd, 0, sizeof(cwd));
340 if (!getcwd(cwd, sizeof(cwd))) {
341 dir = "current working directory";
342 perror("getcwd() failed");
343 }
344
Stefan Roese4acd2d22014-10-22 12:13:23 +0200345 fprintf(stderr,
346 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
347 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
348 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmanne5f1a582014-10-24 23:39:11 +0200349 binarye->binary.file, dir);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200350 return 0;
351 }
352
Reinhard Pfau76b391c2015-11-29 15:52:14 +0100353 headersz += sizeof(struct opt_hdr_v1) +
354 s.st_size +
355 (binarye->binary.nargs + 2) * sizeof(uint32_t);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200356 if (hasext)
357 *hasext = 1;
358 }
359
Stefan Roese7ddf8cf2015-07-20 11:20:38 +0200360#if defined(CONFIG_SYS_U_BOOT_OFFS)
361 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Kevin Smitha0aad122015-03-16 14:58:21 +0000362 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese7ddf8cf2015-07-20 11:20:38 +0200363 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
364 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
365 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smitha0aad122015-03-16 14:58:21 +0000366 return 0;
367 } else {
Stefan Roese7ddf8cf2015-07-20 11:20:38 +0200368 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smitha0aad122015-03-16 14:58:21 +0000369 }
370#endif
371
Stefan Roese4acd2d22014-10-22 12:13:23 +0200372 /*
373 * The payload should be aligned on some reasonable
374 * boundary
375 */
376 return ALIGN_SUP(headersz, 4096);
377}
378
379static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
380 int payloadsz)
381{
382 struct image_cfg_element *e, *binarye;
383 struct main_hdr_v1 *main_hdr;
384 size_t headersz;
385 void *image, *cur;
386 int hasext = 0;
387 int ret;
388
389 /*
390 * Calculate the size of the header and the size of the
391 * payload
392 */
393 headersz = image_headersz_v1(params, &hasext);
394 if (headersz == 0)
395 return NULL;
396
397 image = malloc(headersz);
398 if (!image) {
399 fprintf(stderr, "Cannot allocate memory for image\n");
400 return NULL;
401 }
402
403 memset(image, 0, headersz);
404
405 cur = main_hdr = image;
406 cur += sizeof(struct main_hdr_v1);
407
408 /* Fill the main header */
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100409 main_hdr->blocksize =
410 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
411 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200412 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
Mario Six94084ee2017-01-11 16:00:53 +0100413 main_hdr->destaddr = cpu_to_le32(params->addr)
414 - sizeof(image_header_t);
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100415 main_hdr->execaddr = cpu_to_le32(params->ep);
416 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200417 main_hdr->ext = hasext;
418 main_hdr->version = 1;
419 e = image_find_option(IMAGE_CFG_BOOT_FROM);
420 if (e)
421 main_hdr->blockid = e->bootfrom;
422 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
423 if (e)
424 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
425 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
426 if (e)
427 main_hdr->nandbadblklocation = e->nandbadblklocation;
Chris Packham4bdb5472016-11-09 22:07:45 +1300428 e = image_find_option(IMAGE_CFG_BAUDRATE);
429 if (e)
430 main_hdr->options = baudrate_to_option(e->baudrate);
Chris Packham2611c052016-11-09 22:21:45 +1300431 e = image_find_option(IMAGE_CFG_DEBUG);
432 if (e)
433 main_hdr->flags = e->debug ? 0x1 : 0;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200434
435 binarye = image_find_option(IMAGE_CFG_BINARY);
436 if (binarye) {
437 struct opt_hdr_v1 *hdr = cur;
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100438 uint32_t *args;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200439 size_t binhdrsz;
440 struct stat s;
441 int argi;
442 FILE *bin;
443
444 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
445
446 bin = fopen(binarye->binary.file, "r");
447 if (!bin) {
448 fprintf(stderr, "Cannot open binary file %s\n",
449 binarye->binary.file);
450 return NULL;
451 }
452
453 fstat(fileno(bin), &s);
454
455 binhdrsz = sizeof(struct opt_hdr_v1) +
Reinhard Pfau76b391c2015-11-29 15:52:14 +0100456 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
Stefan Roese4acd2d22014-10-22 12:13:23 +0200457 s.st_size;
Stefan Roeseea8b6872015-10-28 07:53:58 +0100458
459 /*
460 * The size includes the binary image size, rounded
461 * up to a 4-byte boundary. Plus 4 bytes for the
462 * next-header byte and 3-byte alignment at the end.
463 */
464 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100465 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200466 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
467
468 cur += sizeof(struct opt_hdr_v1);
469
470 args = cur;
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100471 *args = cpu_to_le32(binarye->binary.nargs);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200472 args++;
473 for (argi = 0; argi < binarye->binary.nargs; argi++)
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100474 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200475
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100476 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200477
478 ret = fread(cur, s.st_size, 1, bin);
479 if (ret != 1) {
480 fprintf(stderr,
481 "Could not read binary image %s\n",
482 binarye->binary.file);
483 return NULL;
484 }
485
486 fclose(bin);
487
Stefan Roeseea8b6872015-10-28 07:53:58 +0100488 cur += ALIGN_SUP(s.st_size, 4);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200489
490 /*
491 * For now, we don't support more than one binary
492 * header, and no other header types are
493 * supported. So, the binary header is necessarily the
494 * last one
495 */
Stefan Roeseea8b6872015-10-28 07:53:58 +0100496 *((uint32_t *)cur) = 0x00000000;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200497
498 cur += sizeof(uint32_t);
499 }
500
501 /* Calculate and set the header checksum */
502 main_hdr->checksum = image_checksum8(main_hdr, headersz);
503
504 *imagesz = headersz;
505 return image;
506}
507
508static int image_create_config_parse_oneline(char *line,
509 struct image_cfg_element *el)
510{
511 char *keyword, *saveptr;
512 char deliminiters[] = " \t";
513
514 keyword = strtok_r(line, deliminiters, &saveptr);
515 if (!strcmp(keyword, "VERSION")) {
516 char *value = strtok_r(NULL, deliminiters, &saveptr);
517 el->type = IMAGE_CFG_VERSION;
518 el->version = atoi(value);
519 } else if (!strcmp(keyword, "BOOT_FROM")) {
520 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200521 int ret = image_boot_mode_id(value);
522 if (ret < 0) {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200523 fprintf(stderr,
524 "Invalid boot media '%s'\n", value);
525 return -1;
526 }
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200527 el->type = IMAGE_CFG_BOOT_FROM;
528 el->bootfrom = ret;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200529 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
530 char *value = strtok_r(NULL, deliminiters, &saveptr);
531 el->type = IMAGE_CFG_NAND_BLKSZ;
532 el->nandblksz = strtoul(value, NULL, 16);
533 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
534 char *value = strtok_r(NULL, deliminiters, &saveptr);
535 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
536 el->nandbadblklocation =
537 strtoul(value, NULL, 16);
538 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
539 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200540 int ret = image_nand_ecc_mode_id(value);
541 if (ret < 0) {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200542 fprintf(stderr,
543 "Invalid NAND ECC mode '%s'\n", value);
544 return -1;
545 }
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200546 el->type = IMAGE_CFG_NAND_ECC_MODE;
547 el->nandeccmode = ret;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200548 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
549 char *value = strtok_r(NULL, deliminiters, &saveptr);
550 el->type = IMAGE_CFG_NAND_PAGESZ;
551 el->nandpagesz = strtoul(value, NULL, 16);
552 } else if (!strcmp(keyword, "BINARY")) {
553 char *value = strtok_r(NULL, deliminiters, &saveptr);
554 int argi = 0;
555
556 el->type = IMAGE_CFG_BINARY;
557 el->binary.file = strdup(value);
558 while (1) {
559 value = strtok_r(NULL, deliminiters, &saveptr);
560 if (!value)
561 break;
562 el->binary.args[argi] = strtoul(value, NULL, 16);
563 argi++;
564 if (argi >= BINARY_MAX_ARGS) {
565 fprintf(stderr,
566 "Too many argument for binary\n");
567 return -1;
568 }
569 }
570 el->binary.nargs = argi;
571 } else if (!strcmp(keyword, "DATA")) {
572 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
573 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
574
575 if (!value1 || !value2) {
576 fprintf(stderr,
577 "Invalid number of arguments for DATA\n");
578 return -1;
579 }
580
581 el->type = IMAGE_CFG_DATA;
582 el->regdata.raddr = strtoul(value1, NULL, 16);
583 el->regdata.rdata = strtoul(value2, NULL, 16);
Chris Packham4bdb5472016-11-09 22:07:45 +1300584 } else if (!strcmp(keyword, "BAUDRATE")) {
585 char *value = strtok_r(NULL, deliminiters, &saveptr);
586 el->type = IMAGE_CFG_BAUDRATE;
587 el->baudrate = strtoul(value, NULL, 10);
Chris Packham2611c052016-11-09 22:21:45 +1300588 } else if (!strcmp(keyword, "DEBUG")) {
589 char *value = strtok_r(NULL, deliminiters, &saveptr);
590 el->type = IMAGE_CFG_DEBUG;
591 el->debug = strtoul(value, NULL, 10);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200592 } else {
593 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
594 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530595
596 return 0;
597}
598
Stefan Roese4acd2d22014-10-22 12:13:23 +0200599/*
600 * Parse the configuration file 'fcfg' into the array of configuration
601 * elements 'image_cfg', and return the number of configuration
602 * elements in 'cfgn'.
603 */
604static int image_create_config_parse(FILE *fcfg)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530605{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200606 int ret;
607 int cfgi = 0;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530608
Stefan Roese4acd2d22014-10-22 12:13:23 +0200609 /* Parse the configuration file */
610 while (!feof(fcfg)) {
611 char *line;
612 char buf[256];
613
614 /* Read the current line */
615 memset(buf, 0, sizeof(buf));
616 line = fgets(buf, sizeof(buf), fcfg);
617 if (!line)
618 break;
619
620 /* Ignore useless lines */
621 if (line[0] == '\n' || line[0] == '#')
622 continue;
623
624 /* Strip final newline */
625 if (line[strlen(line) - 1] == '\n')
626 line[strlen(line) - 1] = 0;
627
628 /* Parse the current line */
629 ret = image_create_config_parse_oneline(line,
630 &image_cfg[cfgi]);
631 if (ret)
632 return ret;
633
634 cfgi++;
635
636 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
637 fprintf(stderr,
638 "Too many configuration elements in .cfg file\n");
639 return -1;
640 }
641 }
642
643 cfgn = cfgi;
644 return 0;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530645}
646
Stefan Roese4acd2d22014-10-22 12:13:23 +0200647static int image_get_version(void)
648{
649 struct image_cfg_element *e;
650
651 e = image_find_option(IMAGE_CFG_VERSION);
652 if (!e)
653 return -1;
654
655 return e->version;
656}
657
658static int image_version_file(const char *input)
659{
660 FILE *fcfg;
661 int version;
662 int ret;
663
664 fcfg = fopen(input, "r");
665 if (!fcfg) {
666 fprintf(stderr, "Could not open input file %s\n", input);
667 return -1;
668 }
669
670 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
671 sizeof(struct image_cfg_element));
672 if (!image_cfg) {
673 fprintf(stderr, "Cannot allocate memory\n");
674 fclose(fcfg);
675 return -1;
676 }
677
678 memset(image_cfg, 0,
679 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
680 rewind(fcfg);
681
682 ret = image_create_config_parse(fcfg);
683 fclose(fcfg);
684 if (ret) {
685 free(image_cfg);
686 return -1;
687 }
688
689 version = image_get_version();
690 /* Fallback to version 0 is no version is provided in the cfg file */
691 if (version == -1)
692 version = 0;
693
694 free(image_cfg);
695
696 return version;
697}
698
699static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
700 struct image_tool_params *params)
701{
702 FILE *fcfg;
703 void *image = NULL;
704 int version;
Łukasz Majewski93e93712014-11-21 09:22:43 +0100705 size_t headersz = 0;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200706 uint32_t checksum;
707 int ret;
708 int size;
709
710 fcfg = fopen(params->imagename, "r");
711 if (!fcfg) {
712 fprintf(stderr, "Could not open input file %s\n",
713 params->imagename);
714 exit(EXIT_FAILURE);
715 }
716
717 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
718 sizeof(struct image_cfg_element));
719 if (!image_cfg) {
720 fprintf(stderr, "Cannot allocate memory\n");
721 fclose(fcfg);
722 exit(EXIT_FAILURE);
723 }
724
725 memset(image_cfg, 0,
726 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
727 rewind(fcfg);
728
729 ret = image_create_config_parse(fcfg);
730 fclose(fcfg);
731 if (ret) {
732 free(image_cfg);
733 exit(EXIT_FAILURE);
734 }
735
Stefan Roese9b163d82015-09-01 13:46:35 +0200736 /* The MVEBU BootROM does not allow non word aligned payloads */
737 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
738
Stefan Roese4acd2d22014-10-22 12:13:23 +0200739 version = image_get_version();
Stefan Roese934a5292014-10-28 11:32:24 +0100740 switch (version) {
741 /*
742 * Fallback to version 0 if no version is provided in the
743 * cfg file
744 */
745 case -1:
746 case 0:
Stefan Roese4acd2d22014-10-22 12:13:23 +0200747 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese934a5292014-10-28 11:32:24 +0100748 break;
749
750 case 1:
Stefan Roese4acd2d22014-10-22 12:13:23 +0200751 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese934a5292014-10-28 11:32:24 +0100752 break;
753
754 default:
755 fprintf(stderr, "Unsupported version %d\n", version);
756 free(image_cfg);
757 exit(EXIT_FAILURE);
758 }
Stefan Roese4acd2d22014-10-22 12:13:23 +0200759
760 if (!image) {
761 fprintf(stderr, "Could not create image\n");
762 free(image_cfg);
763 exit(EXIT_FAILURE);
764 }
765
766 free(image_cfg);
767
768 /* Build and add image checksum header */
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100769 checksum =
770 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200771 size = write(ifd, &checksum, sizeof(uint32_t));
772 if (size != sizeof(uint32_t)) {
773 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
774 params->cmdname, size, params->imagefile);
775 exit(EXIT_FAILURE);
776 }
777
778 sbuf->st_size += sizeof(uint32_t);
779
780 /* Finally copy the header into the image area */
781 memcpy(ptr, image, headersz);
782
783 free(image);
784}
785
786static void kwbimage_print_header(const void *ptr)
787{
788 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
789
790 printf("Image Type: MVEBU Boot from %s Image\n",
791 image_boot_mode_name(mhdr->blockid));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200792 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma26f195c2014-10-31 01:03:27 +0100793 printf("Data Size: ");
Stefan Roese4acd2d22014-10-22 12:13:23 +0200794 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
795 printf("Load Address: %08x\n", mhdr->destaddr);
796 printf("Entry Point: %08x\n", mhdr->execaddr);
797}
798
799static int kwbimage_check_image_types(uint8_t type)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530800{
801 if (type == IH_TYPE_KWBIMAGE)
802 return EXIT_SUCCESS;
803 else
804 return EXIT_FAILURE;
805}
806
Stefan Roese4acd2d22014-10-22 12:13:23 +0200807static int kwbimage_verify_header(unsigned char *ptr, int image_size,
808 struct image_tool_params *params)
809{
810 struct main_hdr_v0 *main_hdr;
811 struct ext_hdr_v0 *ext_hdr;
812 uint8_t checksum;
813
814 main_hdr = (void *)ptr;
815 checksum = image_checksum8(ptr,
Gerald Kerma26f195c2014-10-31 01:03:27 +0100816 sizeof(struct main_hdr_v0)
817 - sizeof(uint8_t));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200818 if (checksum != main_hdr->checksum)
819 return -FDT_ERR_BADSTRUCTURE;
820
821 /* Only version 0 extended header has checksum */
822 if (image_version((void *)ptr) == 0) {
823 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
824 checksum = image_checksum8(ext_hdr,
Gerald Kerma26f195c2014-10-31 01:03:27 +0100825 sizeof(struct ext_hdr_v0)
826 - sizeof(uint8_t));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200827 if (checksum != ext_hdr->checksum)
828 return -FDT_ERR_BADSTRUCTURE;
829 }
830
831 return 0;
832}
833
834static int kwbimage_generate(struct image_tool_params *params,
835 struct image_type_params *tparams)
836{
837 int alloc_len;
838 void *hdr;
839 int version = 0;
840
841 version = image_version_file(params->imagename);
842 if (version == 0) {
843 alloc_len = sizeof(struct main_hdr_v0) +
844 sizeof(struct ext_hdr_v0);
845 } else {
846 alloc_len = image_headersz_v1(params, NULL);
847 }
848
849 hdr = malloc(alloc_len);
850 if (!hdr) {
851 fprintf(stderr, "%s: malloc return failure: %s\n",
852 params->cmdname, strerror(errno));
853 exit(EXIT_FAILURE);
854 }
855
856 memset(hdr, 0, alloc_len);
857 tparams->header_size = alloc_len;
858 tparams->hdr = hdr;
859
Stefan Roese77720852015-11-24 09:14:59 +0100860 /*
861 * The resulting image needs to be 4-byte aligned. At least
862 * the Marvell hdrparser tool complains if its unaligned.
863 * By returning 1 here in this function, called via
864 * tparams->vrec_header() in mkimage.c, mkimage will
865 * automatically pad the the resulting image to a 4-byte
866 * size if necessary.
867 */
868 return 1;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200869}
870
871/*
872 * Report Error if xflag is set in addition to default
873 */
874static int kwbimage_check_params(struct image_tool_params *params)
875{
876 if (!strlen(params->imagename)) {
877 fprintf(stderr, "Error:%s - Configuration file not specified, "
878 "it is needed for kwbimage generation\n",
879 params->cmdname);
880 return CFG_INVALID;
881 }
882
883 return (params->dflag && (params->fflag || params->lflag)) ||
884 (params->fflag && (params->dflag || params->lflag)) ||
885 (params->lflag && (params->dflag || params->fflag)) ||
886 (params->xflag) || !(strlen(params->imagename));
887}
888
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530889/*
890 * kwbimage type parameters definition
891 */
Guilherme Maciel Ferreiraa93648d2015-01-15 02:48:07 -0200892U_BOOT_IMAGE_TYPE(
893 kwbimage,
894 "Marvell MVEBU Boot Image support",
895 0,
896 NULL,
897 kwbimage_check_params,
898 kwbimage_verify_header,
899 kwbimage_print_header,
900 kwbimage_set_header,
901 NULL,
902 kwbimage_check_image_types,
903 NULL,
904 kwbimage_generate
905);