blob: 9aa9c7491a39d78626179561d657917b64751e4c [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 */
Mario Six4991b4f2017-01-11 16:00:59 +010058
59enum image_cfg_type {
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 IMAGE_CFG_BAUDRATE,
72 IMAGE_CFG_DEBUG,
73
74 IMAGE_CFG_COUNT
75} type;
76
77static const char * const id_strs[] = {
78 [IMAGE_CFG_VERSION] = "VERSION",
79 [IMAGE_CFG_BOOT_FROM] = "BOOT_FROM",
80 [IMAGE_CFG_DEST_ADDR] = "DEST_ADDR",
81 [IMAGE_CFG_EXEC_ADDR] = "EXEC_ADDR",
82 [IMAGE_CFG_NAND_BLKSZ] = "NAND_BLKSZ",
83 [IMAGE_CFG_NAND_BADBLK_LOCATION] = "NAND_BADBLK_LOCATION",
84 [IMAGE_CFG_NAND_ECC_MODE] = "NAND_ECC_MODE",
85 [IMAGE_CFG_NAND_PAGESZ] = "NAND_PAGE_SIZE",
86 [IMAGE_CFG_BINARY] = "BINARY",
87 [IMAGE_CFG_PAYLOAD] = "PAYLOAD",
88 [IMAGE_CFG_DATA] = "DATA",
89 [IMAGE_CFG_BAUDRATE] = "BAUDRATE",
90 [IMAGE_CFG_DEBUG] = "DEBUG",
91};
92
Stefan Roese4acd2d22014-10-22 12:13:23 +020093struct image_cfg_element {
Mario Six4991b4f2017-01-11 16:00:59 +010094 enum image_cfg_type type;
Stefan Roese4acd2d22014-10-22 12:13:23 +020095 union {
96 unsigned int version;
97 unsigned int bootfrom;
98 struct {
99 const char *file;
100 unsigned int args[BINARY_MAX_ARGS];
101 unsigned int nargs;
102 } binary;
103 const char *payload;
104 unsigned int dstaddr;
105 unsigned int execaddr;
106 unsigned int nandblksz;
107 unsigned int nandbadblklocation;
108 unsigned int nandeccmode;
109 unsigned int nandpagesz;
110 struct ext_hdr_v0_reg regdata;
Chris Packham4bdb5472016-11-09 22:07:45 +1300111 unsigned int baudrate;
Chris Packham2611c052016-11-09 22:21:45 +1300112 unsigned int debug;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200113 };
114};
115
116#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530117
118/*
Stefan Roese4acd2d22014-10-22 12:13:23 +0200119 * Utility functions to manipulate boot mode and ecc modes (convert
120 * them back and forth between description strings and the
121 * corresponding numerical identifiers).
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530122 */
Stefan Roese4acd2d22014-10-22 12:13:23 +0200123
124static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530125{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200126 int i;
Mario Six94490a42017-01-11 16:00:54 +0100127
Stefan Roese4acd2d22014-10-22 12:13:23 +0200128 for (i = 0; boot_modes[i].name; i++)
129 if (boot_modes[i].id == id)
130 return boot_modes[i].name;
131 return NULL;
132}
133
134int image_boot_mode_id(const char *boot_mode_name)
135{
136 int i;
Mario Six94490a42017-01-11 16:00:54 +0100137
Stefan Roese4acd2d22014-10-22 12:13:23 +0200138 for (i = 0; boot_modes[i].name; i++)
139 if (!strcmp(boot_modes[i].name, boot_mode_name))
140 return boot_modes[i].id;
141
142 return -1;
143}
144
145int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
146{
147 int i;
Mario Six94490a42017-01-11 16:00:54 +0100148
Stefan Roese4acd2d22014-10-22 12:13:23 +0200149 for (i = 0; nand_ecc_modes[i].name; i++)
150 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
151 return nand_ecc_modes[i].id;
152 return -1;
153}
154
155static struct image_cfg_element *
156image_find_option(unsigned int optiontype)
157{
158 int i;
159
160 for (i = 0; i < cfgn; i++) {
161 if (image_cfg[i].type == optiontype)
162 return &image_cfg[i];
163 }
164
165 return NULL;
166}
167
168static unsigned int
169image_count_options(unsigned int optiontype)
170{
171 int i;
172 unsigned int count = 0;
173
174 for (i = 0; i < cfgn; i++)
175 if (image_cfg[i].type == optiontype)
176 count++;
177
178 return count;
179}
180
181/*
182 * Compute a 8-bit checksum of a memory area. This algorithm follows
183 * the requirements of the Marvell SoC BootROM specifications.
184 */
185static uint8_t image_checksum8(void *start, uint32_t len)
186{
187 uint8_t csum = 0;
188 uint8_t *p = start;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530189
190 /* check len and return zero checksum if invalid */
191 if (!len)
192 return 0;
193
194 do {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200195 csum += *p;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530196 p++;
197 } while (--len);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200198
199 return csum;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530200}
201
Stefan Roese4acd2d22014-10-22 12:13:23 +0200202static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530203{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200204 uint32_t csum = 0;
205 uint32_t *p = start;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530206
207 /* check len and return zero checksum if invalid */
208 if (!len)
209 return 0;
210
211 if (len % sizeof(uint32_t)) {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200212 fprintf(stderr, "Length %d is not in multiple of %zu\n",
213 len, sizeof(uint32_t));
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530214 return 0;
215 }
216
217 do {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200218 csum += *p;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530219 p++;
220 len -= sizeof(uint32_t);
221 } while (len > 0);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200222
223 return csum;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530224}
225
Chris Packham4bdb5472016-11-09 22:07:45 +1300226static uint8_t baudrate_to_option(unsigned int baudrate)
227{
228 switch (baudrate) {
229 case 2400:
230 return MAIN_HDR_V1_OPT_BAUD_2400;
231 case 4800:
232 return MAIN_HDR_V1_OPT_BAUD_4800;
233 case 9600:
234 return MAIN_HDR_V1_OPT_BAUD_9600;
235 case 19200:
236 return MAIN_HDR_V1_OPT_BAUD_19200;
237 case 38400:
238 return MAIN_HDR_V1_OPT_BAUD_38400;
239 case 57600:
240 return MAIN_HDR_V1_OPT_BAUD_57600;
241 case 115200:
242 return MAIN_HDR_V1_OPT_BAUD_115200;
243 default:
244 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
245 }
246}
247
Stefan Roese4acd2d22014-10-22 12:13:23 +0200248static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
249 int payloadsz)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530250{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200251 struct image_cfg_element *e;
252 size_t headersz;
253 struct main_hdr_v0 *main_hdr;
Mario Six885fba12017-01-11 16:00:55 +0100254 uint8_t *image;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200255 int has_ext = 0;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530256
Stefan Roese4acd2d22014-10-22 12:13:23 +0200257 /*
258 * Calculate the size of the header and the size of the
259 * payload
260 */
261 headersz = sizeof(struct main_hdr_v0);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530262
Stefan Roese4acd2d22014-10-22 12:13:23 +0200263 if (image_count_options(IMAGE_CFG_DATA) > 0) {
264 has_ext = 1;
265 headersz += sizeof(struct ext_hdr_v0);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530266 }
267
Stefan Roese4acd2d22014-10-22 12:13:23 +0200268 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
269 fprintf(stderr, "More than one payload, not possible\n");
270 return NULL;
271 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530272
Stefan Roese4acd2d22014-10-22 12:13:23 +0200273 image = malloc(headersz);
274 if (!image) {
275 fprintf(stderr, "Cannot allocate memory for image\n");
276 return NULL;
277 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530278
Stefan Roese4acd2d22014-10-22 12:13:23 +0200279 memset(image, 0, headersz);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530280
Mario Six885fba12017-01-11 16:00:55 +0100281 main_hdr = (struct main_hdr_v0 *)image;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530282
Stefan Roese4acd2d22014-10-22 12:13:23 +0200283 /* Fill in the main header */
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100284 main_hdr->blocksize =
285 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
286 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200287 main_hdr->ext = has_ext;
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100288 main_hdr->destaddr = cpu_to_le32(params->addr);
289 main_hdr->execaddr = cpu_to_le32(params->ep);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530290
Stefan Roese4acd2d22014-10-22 12:13:23 +0200291 e = image_find_option(IMAGE_CFG_BOOT_FROM);
292 if (e)
293 main_hdr->blockid = e->bootfrom;
294 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
295 if (e)
296 main_hdr->nandeccmode = e->nandeccmode;
297 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
298 if (e)
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100299 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200300 main_hdr->checksum = image_checksum8(image,
301 sizeof(struct main_hdr_v0));
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530302
Stefan Roese4acd2d22014-10-22 12:13:23 +0200303 /* Generate the ext header */
304 if (has_ext) {
Mario Sixe89016c2017-01-11 16:00:56 +0100305 struct ext_hdr_v0 *ext_hdr;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200306 int cfgi, datai;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530307
Mario Six885fba12017-01-11 16:00:55 +0100308 ext_hdr = (struct ext_hdr_v0 *)
309 (image + sizeof(struct main_hdr_v0));
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100310 ext_hdr->offset = cpu_to_le32(0x40);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530311
Stefan Roese4acd2d22014-10-22 12:13:23 +0200312 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
313 e = &image_cfg[cfgi];
314 if (e->type != IMAGE_CFG_DATA)
315 continue;
316
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100317 ext_hdr->rcfg[datai].raddr =
318 cpu_to_le32(e->regdata.raddr);
319 ext_hdr->rcfg[datai].rdata =
320 cpu_to_le32(e->regdata.rdata);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200321 datai++;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530322 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530323
Stefan Roese4acd2d22014-10-22 12:13:23 +0200324 ext_hdr->checksum = image_checksum8(ext_hdr,
325 sizeof(struct ext_hdr_v0));
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530326 }
327
Stefan Roese4acd2d22014-10-22 12:13:23 +0200328 *imagesz = headersz;
329 return image;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530330}
331
Mario Sixe93cf532017-01-11 16:00:57 +0100332static size_t image_headersz_v1(int *hasext)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530333{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200334 struct image_cfg_element *binarye;
335 size_t headersz;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530336
Stefan Roese4acd2d22014-10-22 12:13:23 +0200337 /*
338 * Calculate the size of the header and the size of the
339 * payload
340 */
341 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530342
Stefan Roese4acd2d22014-10-22 12:13:23 +0200343 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
344 fprintf(stderr, "More than one binary blob, not supported\n");
345 return 0;
346 }
347
348 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
349 fprintf(stderr, "More than one payload, not possible\n");
350 return 0;
351 }
352
353 binarye = image_find_option(IMAGE_CFG_BINARY);
354 if (binarye) {
Mario Sixe89016c2017-01-11 16:00:56 +0100355 int ret;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200356 struct stat s;
357
358 ret = stat(binarye->binary.file, &s);
359 if (ret < 0) {
Andreas Bießmanne5f1a582014-10-24 23:39:11 +0200360 char cwd[PATH_MAX];
361 char *dir = cwd;
362
363 memset(cwd, 0, sizeof(cwd));
364 if (!getcwd(cwd, sizeof(cwd))) {
365 dir = "current working directory";
366 perror("getcwd() failed");
367 }
368
Stefan Roese4acd2d22014-10-22 12:13:23 +0200369 fprintf(stderr,
370 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
371 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
372 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmanne5f1a582014-10-24 23:39:11 +0200373 binarye->binary.file, dir);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200374 return 0;
375 }
376
Reinhard Pfau76b391c2015-11-29 15:52:14 +0100377 headersz += sizeof(struct opt_hdr_v1) +
378 s.st_size +
379 (binarye->binary.nargs + 2) * sizeof(uint32_t);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200380 if (hasext)
381 *hasext = 1;
382 }
383
Stefan Roese7ddf8cf2015-07-20 11:20:38 +0200384#if defined(CONFIG_SYS_U_BOOT_OFFS)
385 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Mario Six94490a42017-01-11 16:00:54 +0100386 fprintf(stderr,
387 "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese7ddf8cf2015-07-20 11:20:38 +0200388 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
389 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
390 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smitha0aad122015-03-16 14:58:21 +0000391 return 0;
Kevin Smitha0aad122015-03-16 14:58:21 +0000392 }
Mario Six79066ef2017-01-11 16:00:58 +0100393
Mario Six94490a42017-01-11 16:00:54 +0100394 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smitha0aad122015-03-16 14:58:21 +0000395#endif
396
Stefan Roese4acd2d22014-10-22 12:13:23 +0200397 /*
398 * The payload should be aligned on some reasonable
399 * boundary
400 */
401 return ALIGN_SUP(headersz, 4096);
402}
403
Mario Six79066ef2017-01-11 16:00:58 +0100404int add_binary_header_v1(uint8_t *cur)
405{
406 struct image_cfg_element *binarye;
407 struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;
408 uint32_t *args;
409 size_t binhdrsz;
410 struct stat s;
411 int argi;
412 FILE *bin;
413 int ret;
414
415 binarye = image_find_option(IMAGE_CFG_BINARY);
416
417 if (!binarye)
418 return 0;
419
420 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
421
422 bin = fopen(binarye->binary.file, "r");
423 if (!bin) {
424 fprintf(stderr, "Cannot open binary file %s\n",
425 binarye->binary.file);
426 return -1;
427 }
428
429 fstat(fileno(bin), &s);
430
431 binhdrsz = sizeof(struct opt_hdr_v1) +
432 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
433 s.st_size;
434
435 /*
436 * The size includes the binary image size, rounded
437 * up to a 4-byte boundary. Plus 4 bytes for the
438 * next-header byte and 3-byte alignment at the end.
439 */
440 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
441 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
442 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
443
444 cur += sizeof(struct opt_hdr_v1);
445
446 args = (uint32_t *)cur;
447 *args = cpu_to_le32(binarye->binary.nargs);
448 args++;
449 for (argi = 0; argi < binarye->binary.nargs; argi++)
450 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
451
452 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
453
454 ret = fread(cur, s.st_size, 1, bin);
455 if (ret != 1) {
456 fprintf(stderr,
457 "Could not read binary image %s\n",
458 binarye->binary.file);
459 return -1;
460 }
461
462 fclose(bin);
463
464 cur += ALIGN_SUP(s.st_size, 4);
465
466 /*
467 * For now, we don't support more than one binary
468 * header, and no other header types are
469 * supported. So, the binary header is necessarily the
470 * last one
471 */
472 *((uint32_t *)cur) = 0x00000000;
473
474 cur += sizeof(uint32_t);
475
476 return 0;
477}
478
Stefan Roese4acd2d22014-10-22 12:13:23 +0200479static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
480 int payloadsz)
481{
Mario Six79066ef2017-01-11 16:00:58 +0100482 struct image_cfg_element *e;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200483 struct main_hdr_v1 *main_hdr;
484 size_t headersz;
Mario Six885fba12017-01-11 16:00:55 +0100485 uint8_t *image, *cur;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200486 int hasext = 0;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200487
488 /*
489 * Calculate the size of the header and the size of the
490 * payload
491 */
Mario Sixe93cf532017-01-11 16:00:57 +0100492 headersz = image_headersz_v1(&hasext);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200493 if (headersz == 0)
494 return NULL;
495
496 image = malloc(headersz);
497 if (!image) {
498 fprintf(stderr, "Cannot allocate memory for image\n");
499 return NULL;
500 }
501
502 memset(image, 0, headersz);
503
Mario Six885fba12017-01-11 16:00:55 +0100504 main_hdr = (struct main_hdr_v1 *)image;
505 cur = image + sizeof(struct main_hdr_v1);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200506
507 /* Fill the main header */
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100508 main_hdr->blocksize =
509 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
510 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200511 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
Mario Six94084ee2017-01-11 16:00:53 +0100512 main_hdr->destaddr = cpu_to_le32(params->addr)
513 - sizeof(image_header_t);
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100514 main_hdr->execaddr = cpu_to_le32(params->ep);
515 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200516 main_hdr->ext = hasext;
517 main_hdr->version = 1;
518 e = image_find_option(IMAGE_CFG_BOOT_FROM);
519 if (e)
520 main_hdr->blockid = e->bootfrom;
521 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
522 if (e)
523 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
524 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
525 if (e)
526 main_hdr->nandbadblklocation = e->nandbadblklocation;
Chris Packham4bdb5472016-11-09 22:07:45 +1300527 e = image_find_option(IMAGE_CFG_BAUDRATE);
528 if (e)
529 main_hdr->options = baudrate_to_option(e->baudrate);
Chris Packham2611c052016-11-09 22:21:45 +1300530 e = image_find_option(IMAGE_CFG_DEBUG);
531 if (e)
532 main_hdr->flags = e->debug ? 0x1 : 0;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200533
Mario Six79066ef2017-01-11 16:00:58 +0100534 if (add_binary_header_v1(cur))
535 return NULL;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200536
537 /* Calculate and set the header checksum */
538 main_hdr->checksum = image_checksum8(main_hdr, headersz);
539
540 *imagesz = headersz;
541 return image;
542}
543
Mario Six4991b4f2017-01-11 16:00:59 +0100544int recognize_keyword(char *keyword)
545{
546 int kw_id;
547
548 for (kw_id = 1; kw_id < IMAGE_CFG_COUNT; ++kw_id)
549 if (!strcmp(keyword, id_strs[kw_id]))
550 return kw_id;
551
552 return 0;
553}
554
Stefan Roese4acd2d22014-10-22 12:13:23 +0200555static int image_create_config_parse_oneline(char *line,
556 struct image_cfg_element *el)
557{
Mario Six4991b4f2017-01-11 16:00:59 +0100558 char *keyword, *saveptr, *value1, *value2;
559 char delimiters[] = " \t";
560 int keyword_id, ret, argi;
561 char *unknown_msg = "Ignoring unknown line '%s'\n";
Stefan Roese4acd2d22014-10-22 12:13:23 +0200562
Mario Six4991b4f2017-01-11 16:00:59 +0100563 keyword = strtok_r(line, delimiters, &saveptr);
564 keyword_id = recognize_keyword(keyword);
Mario Six94490a42017-01-11 16:00:54 +0100565
Mario Six4991b4f2017-01-11 16:00:59 +0100566 if (!keyword_id) {
567 fprintf(stderr, unknown_msg, line);
568 return 0;
569 }
570
571 el->type = keyword_id;
572
573 value1 = strtok_r(NULL, delimiters, &saveptr);
574
575 if (!value1) {
576 fprintf(stderr, "Parameter missing in line '%s'\n", line);
577 return -1;
578 }
579
580 switch (keyword_id) {
581 case IMAGE_CFG_VERSION:
582 el->version = atoi(value1);
583 break;
584 case IMAGE_CFG_BOOT_FROM:
585 ret = image_boot_mode_id(value1);
Mario Six94490a42017-01-11 16:00:54 +0100586
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200587 if (ret < 0) {
Mario Six4991b4f2017-01-11 16:00:59 +0100588 fprintf(stderr, "Invalid boot media '%s'\n", value1);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200589 return -1;
590 }
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200591 el->bootfrom = ret;
Mario Six4991b4f2017-01-11 16:00:59 +0100592 break;
593 case IMAGE_CFG_NAND_BLKSZ:
594 el->nandblksz = strtoul(value1, NULL, 16);
595 break;
596 case IMAGE_CFG_NAND_BADBLK_LOCATION:
597 el->nandbadblklocation = strtoul(value1, NULL, 16);
598 break;
599 case IMAGE_CFG_NAND_ECC_MODE:
600 ret = image_nand_ecc_mode_id(value1);
Mario Six94490a42017-01-11 16:00:54 +0100601
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200602 if (ret < 0) {
Mario Six4991b4f2017-01-11 16:00:59 +0100603 fprintf(stderr, "Invalid NAND ECC mode '%s'\n", value1);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200604 return -1;
605 }
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200606 el->nandeccmode = ret;
Mario Six4991b4f2017-01-11 16:00:59 +0100607 break;
608 case IMAGE_CFG_NAND_PAGESZ:
609 el->nandpagesz = strtoul(value1, NULL, 16);
610 break;
611 case IMAGE_CFG_BINARY:
612 argi = 0;
Mario Six94490a42017-01-11 16:00:54 +0100613
Mario Six4991b4f2017-01-11 16:00:59 +0100614 el->binary.file = strdup(value1);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200615 while (1) {
Mario Six4991b4f2017-01-11 16:00:59 +0100616 char *value = strtok_r(NULL, delimiters, &saveptr);
617
Stefan Roese4acd2d22014-10-22 12:13:23 +0200618 if (!value)
619 break;
620 el->binary.args[argi] = strtoul(value, NULL, 16);
621 argi++;
622 if (argi >= BINARY_MAX_ARGS) {
623 fprintf(stderr,
Mario Six4991b4f2017-01-11 16:00:59 +0100624 "Too many arguments for BINARY\n");
Stefan Roese4acd2d22014-10-22 12:13:23 +0200625 return -1;
626 }
627 }
628 el->binary.nargs = argi;
Mario Six4991b4f2017-01-11 16:00:59 +0100629 break;
630 case IMAGE_CFG_DATA:
631 value2 = strtok_r(NULL, delimiters, &saveptr);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200632
633 if (!value1 || !value2) {
634 fprintf(stderr,
635 "Invalid number of arguments for DATA\n");
636 return -1;
637 }
638
Stefan Roese4acd2d22014-10-22 12:13:23 +0200639 el->regdata.raddr = strtoul(value1, NULL, 16);
640 el->regdata.rdata = strtoul(value2, NULL, 16);
Mario Six4991b4f2017-01-11 16:00:59 +0100641 break;
642 case IMAGE_CFG_BAUDRATE:
643 el->baudrate = strtoul(value1, NULL, 10);
644 break;
645 case IMAGE_CFG_DEBUG:
646 el->debug = strtoul(value1, NULL, 10);
647 break;
648 default:
649 fprintf(stderr, unknown_msg, line);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200650 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530651
652 return 0;
653}
654
Stefan Roese4acd2d22014-10-22 12:13:23 +0200655/*
656 * Parse the configuration file 'fcfg' into the array of configuration
657 * elements 'image_cfg', and return the number of configuration
658 * elements in 'cfgn'.
659 */
660static int image_create_config_parse(FILE *fcfg)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530661{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200662 int ret;
663 int cfgi = 0;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530664
Stefan Roese4acd2d22014-10-22 12:13:23 +0200665 /* Parse the configuration file */
666 while (!feof(fcfg)) {
667 char *line;
668 char buf[256];
669
670 /* Read the current line */
671 memset(buf, 0, sizeof(buf));
672 line = fgets(buf, sizeof(buf), fcfg);
673 if (!line)
674 break;
675
676 /* Ignore useless lines */
677 if (line[0] == '\n' || line[0] == '#')
678 continue;
679
680 /* Strip final newline */
681 if (line[strlen(line) - 1] == '\n')
682 line[strlen(line) - 1] = 0;
683
684 /* Parse the current line */
685 ret = image_create_config_parse_oneline(line,
686 &image_cfg[cfgi]);
687 if (ret)
688 return ret;
689
690 cfgi++;
691
692 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
693 fprintf(stderr,
694 "Too many configuration elements in .cfg file\n");
695 return -1;
696 }
697 }
698
699 cfgn = cfgi;
700 return 0;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530701}
702
Stefan Roese4acd2d22014-10-22 12:13:23 +0200703static int image_get_version(void)
704{
705 struct image_cfg_element *e;
706
707 e = image_find_option(IMAGE_CFG_VERSION);
708 if (!e)
709 return -1;
710
711 return e->version;
712}
713
714static int image_version_file(const char *input)
715{
716 FILE *fcfg;
717 int version;
718 int ret;
719
720 fcfg = fopen(input, "r");
721 if (!fcfg) {
722 fprintf(stderr, "Could not open input file %s\n", input);
723 return -1;
724 }
725
726 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
727 sizeof(struct image_cfg_element));
728 if (!image_cfg) {
729 fprintf(stderr, "Cannot allocate memory\n");
730 fclose(fcfg);
731 return -1;
732 }
733
734 memset(image_cfg, 0,
735 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
736 rewind(fcfg);
737
738 ret = image_create_config_parse(fcfg);
739 fclose(fcfg);
740 if (ret) {
741 free(image_cfg);
742 return -1;
743 }
744
745 version = image_get_version();
746 /* Fallback to version 0 is no version is provided in the cfg file */
747 if (version == -1)
748 version = 0;
749
750 free(image_cfg);
751
752 return version;
753}
754
755static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
756 struct image_tool_params *params)
757{
758 FILE *fcfg;
759 void *image = NULL;
760 int version;
Łukasz Majewski93e93712014-11-21 09:22:43 +0100761 size_t headersz = 0;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200762 uint32_t checksum;
763 int ret;
764 int size;
765
766 fcfg = fopen(params->imagename, "r");
767 if (!fcfg) {
768 fprintf(stderr, "Could not open input file %s\n",
769 params->imagename);
770 exit(EXIT_FAILURE);
771 }
772
773 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
774 sizeof(struct image_cfg_element));
775 if (!image_cfg) {
776 fprintf(stderr, "Cannot allocate memory\n");
777 fclose(fcfg);
778 exit(EXIT_FAILURE);
779 }
780
781 memset(image_cfg, 0,
782 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
783 rewind(fcfg);
784
785 ret = image_create_config_parse(fcfg);
786 fclose(fcfg);
787 if (ret) {
788 free(image_cfg);
789 exit(EXIT_FAILURE);
790 }
791
Stefan Roese9b163d82015-09-01 13:46:35 +0200792 /* The MVEBU BootROM does not allow non word aligned payloads */
793 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
794
Stefan Roese4acd2d22014-10-22 12:13:23 +0200795 version = image_get_version();
Stefan Roese934a5292014-10-28 11:32:24 +0100796 switch (version) {
797 /*
798 * Fallback to version 0 if no version is provided in the
799 * cfg file
800 */
801 case -1:
802 case 0:
Stefan Roese4acd2d22014-10-22 12:13:23 +0200803 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese934a5292014-10-28 11:32:24 +0100804 break;
805
806 case 1:
Stefan Roese4acd2d22014-10-22 12:13:23 +0200807 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese934a5292014-10-28 11:32:24 +0100808 break;
809
810 default:
811 fprintf(stderr, "Unsupported version %d\n", version);
812 free(image_cfg);
813 exit(EXIT_FAILURE);
814 }
Stefan Roese4acd2d22014-10-22 12:13:23 +0200815
816 if (!image) {
817 fprintf(stderr, "Could not create image\n");
818 free(image_cfg);
819 exit(EXIT_FAILURE);
820 }
821
822 free(image_cfg);
823
824 /* Build and add image checksum header */
Reinhard Pfaua8840dc2015-11-29 15:48:25 +0100825 checksum =
826 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200827 size = write(ifd, &checksum, sizeof(uint32_t));
828 if (size != sizeof(uint32_t)) {
829 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
830 params->cmdname, size, params->imagefile);
831 exit(EXIT_FAILURE);
832 }
833
834 sbuf->st_size += sizeof(uint32_t);
835
836 /* Finally copy the header into the image area */
837 memcpy(ptr, image, headersz);
838
839 free(image);
840}
841
842static void kwbimage_print_header(const void *ptr)
843{
844 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
845
846 printf("Image Type: MVEBU Boot from %s Image\n",
847 image_boot_mode_name(mhdr->blockid));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200848 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma26f195c2014-10-31 01:03:27 +0100849 printf("Data Size: ");
Stefan Roese4acd2d22014-10-22 12:13:23 +0200850 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
851 printf("Load Address: %08x\n", mhdr->destaddr);
852 printf("Entry Point: %08x\n", mhdr->execaddr);
853}
854
855static int kwbimage_check_image_types(uint8_t type)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530856{
857 if (type == IH_TYPE_KWBIMAGE)
858 return EXIT_SUCCESS;
Mario Six94490a42017-01-11 16:00:54 +0100859
860 return EXIT_FAILURE;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530861}
862
Stefan Roese4acd2d22014-10-22 12:13:23 +0200863static int kwbimage_verify_header(unsigned char *ptr, int image_size,
864 struct image_tool_params *params)
865{
866 struct main_hdr_v0 *main_hdr;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200867 uint8_t checksum;
868
Mario Six885fba12017-01-11 16:00:55 +0100869 main_hdr = (struct main_hdr_v0 *)ptr;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200870 checksum = image_checksum8(ptr,
Gerald Kerma26f195c2014-10-31 01:03:27 +0100871 sizeof(struct main_hdr_v0)
872 - sizeof(uint8_t));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200873 if (checksum != main_hdr->checksum)
874 return -FDT_ERR_BADSTRUCTURE;
875
876 /* Only version 0 extended header has checksum */
877 if (image_version((void *)ptr) == 0) {
Mario Sixe89016c2017-01-11 16:00:56 +0100878 struct ext_hdr_v0 *ext_hdr;
879
Mario Six885fba12017-01-11 16:00:55 +0100880 ext_hdr = (struct ext_hdr_v0 *)
881 (ptr + sizeof(struct main_hdr_v0));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200882 checksum = image_checksum8(ext_hdr,
Gerald Kerma26f195c2014-10-31 01:03:27 +0100883 sizeof(struct ext_hdr_v0)
884 - sizeof(uint8_t));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200885 if (checksum != ext_hdr->checksum)
886 return -FDT_ERR_BADSTRUCTURE;
887 }
888
889 return 0;
890}
891
892static int kwbimage_generate(struct image_tool_params *params,
893 struct image_type_params *tparams)
894{
895 int alloc_len;
896 void *hdr;
897 int version = 0;
898
899 version = image_version_file(params->imagename);
900 if (version == 0) {
901 alloc_len = sizeof(struct main_hdr_v0) +
902 sizeof(struct ext_hdr_v0);
903 } else {
Mario Sixe93cf532017-01-11 16:00:57 +0100904 alloc_len = image_headersz_v1(NULL);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200905 }
906
907 hdr = malloc(alloc_len);
908 if (!hdr) {
909 fprintf(stderr, "%s: malloc return failure: %s\n",
910 params->cmdname, strerror(errno));
911 exit(EXIT_FAILURE);
912 }
913
914 memset(hdr, 0, alloc_len);
915 tparams->header_size = alloc_len;
916 tparams->hdr = hdr;
917
Stefan Roese77720852015-11-24 09:14:59 +0100918 /*
919 * The resulting image needs to be 4-byte aligned. At least
920 * the Marvell hdrparser tool complains if its unaligned.
921 * By returning 1 here in this function, called via
922 * tparams->vrec_header() in mkimage.c, mkimage will
923 * automatically pad the the resulting image to a 4-byte
924 * size if necessary.
925 */
926 return 1;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200927}
928
929/*
930 * Report Error if xflag is set in addition to default
931 */
932static int kwbimage_check_params(struct image_tool_params *params)
933{
934 if (!strlen(params->imagename)) {
Mario Six94490a42017-01-11 16:00:54 +0100935 char *msg = "Configuration file for kwbimage creation omitted";
936
937 fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200938 return CFG_INVALID;
939 }
940
941 return (params->dflag && (params->fflag || params->lflag)) ||
942 (params->fflag && (params->dflag || params->lflag)) ||
943 (params->lflag && (params->dflag || params->fflag)) ||
944 (params->xflag) || !(strlen(params->imagename));
945}
946
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530947/*
948 * kwbimage type parameters definition
949 */
Guilherme Maciel Ferreiraa93648d2015-01-15 02:48:07 -0200950U_BOOT_IMAGE_TYPE(
951 kwbimage,
952 "Marvell MVEBU Boot Image support",
953 0,
954 NULL,
955 kwbimage_check_params,
956 kwbimage_verify_header,
957 kwbimage_print_header,
958 kwbimage_set_header,
959 NULL,
960 kwbimage_check_image_types,
961 NULL,
962 kwbimage_generate
963);