blob: 3fa90d3a758ab407206773fa3fd932d696794a8d [file] [log] [blame]
Prafulla Wadaskar07329412009-09-07 15:05:02 +05301/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +02002 * Image manipulator for Marvell SoCs
3 * supports Kirkwood, Dove, Armada 370, and Armada XP
4 *
5 * (C) Copyright 2013 Thomas Petazzoni
6 * <thomas.petazzoni@free-electrons.com>
Prafulla Wadaskar07329412009-09-07 15:05:02 +05307 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
Stefan Roese3b8b19d2014-10-22 12:13:23 +02009 *
10 * Not implemented: support for the register headers and secure
11 * headers in v1 images
Prafulla Wadaskar07329412009-09-07 15:05:02 +053012 */
13
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -070014#include "imagetool.h"
Andreas Bießmann7abec5b2014-10-24 23:39:11 +020015#include <limits.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053016#include <image.h>
Stefan Roese3b8b19d2014-10-22 12:13:23 +020017#include <stdint.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053018#include "kwbimage.h"
19
Stefan Roese3b8b19d2014-10-22 12:13:23 +020020#define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
21
22/* Structure of the main header, version 0 (Kirkwood, Dove) */
23struct main_hdr_v0 {
24 uint8_t blockid; /*0 */
25 uint8_t nandeccmode; /*1 */
26 uint16_t nandpagesize; /*2-3 */
27 uint32_t blocksize; /*4-7 */
28 uint32_t rsvd1; /*8-11 */
29 uint32_t srcaddr; /*12-15 */
30 uint32_t destaddr; /*16-19 */
31 uint32_t execaddr; /*20-23 */
32 uint8_t satapiomode; /*24 */
33 uint8_t rsvd3; /*25 */
34 uint16_t ddrinitdelay; /*26-27 */
35 uint16_t rsvd2; /*28-29 */
36 uint8_t ext; /*30 */
37 uint8_t checksum; /*31 */
38};
39
40struct ext_hdr_v0_reg {
41 uint32_t raddr;
42 uint32_t rdata;
Prafulla Wadaskar07329412009-09-07 15:05:02 +053043};
44
Stefan Roese3b8b19d2014-10-22 12:13:23 +020045#define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
46
47struct ext_hdr_v0 {
48 uint32_t offset;
49 uint8_t reserved[0x20 - sizeof(uint32_t)];
50 struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
51 uint8_t reserved2[7];
52 uint8_t checksum;
53};
54
55/* Structure of the main header, version 1 (Armada 370, Armada XP) */
56struct main_hdr_v1 {
57 uint8_t blockid; /* 0 */
58 uint8_t reserved1; /* 1 */
59 uint16_t reserved2; /* 2-3 */
60 uint32_t blocksize; /* 4-7 */
61 uint8_t version; /* 8 */
62 uint8_t headersz_msb; /* 9 */
63 uint16_t headersz_lsb; /* A-B */
64 uint32_t srcaddr; /* C-F */
65 uint32_t destaddr; /* 10-13 */
66 uint32_t execaddr; /* 14-17 */
67 uint8_t reserved3; /* 18 */
68 uint8_t nandblocksize; /* 19 */
69 uint8_t nandbadblklocation; /* 1A */
70 uint8_t reserved4; /* 1B */
71 uint16_t reserved5; /* 1C-1D */
72 uint8_t ext; /* 1E */
73 uint8_t checksum; /* 1F */
74};
75
Prafulla Wadaskar07329412009-09-07 15:05:02 +053076/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020077 * Header for the optional headers, version 1 (Armada 370, Armada XP)
Prafulla Wadaskar07329412009-09-07 15:05:02 +053078 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +020079struct opt_hdr_v1 {
80 uint8_t headertype;
81 uint8_t headersz_msb;
82 uint16_t headersz_lsb;
83 char data[0];
Prafulla Wadaskar07329412009-09-07 15:05:02 +053084};
85
86/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020087 * Various values for the opt_hdr_v1->headertype field, describing the
88 * different types of optional headers. The "secure" header contains
89 * informations related to secure boot (encryption keys, etc.). The
90 * "binary" header contains ARM binary code to be executed prior to
91 * executing the main payload (usually the bootloader). This is
92 * typically used to execute DDR3 training code. The "register" header
93 * allows to describe a set of (address, value) tuples that are
94 * generally used to configure the DRAM controller.
Prafulla Wadaskar07329412009-09-07 15:05:02 +053095 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +020096#define OPT_HDR_V1_SECURE_TYPE 0x1
97#define OPT_HDR_V1_BINARY_TYPE 0x2
98#define OPT_HDR_V1_REGISTER_TYPE 0x3
99
100#define KWBHEADER_V1_SIZE(hdr) \
101 (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
102
103static struct image_cfg_element *image_cfg;
104static int cfgn;
105
106struct boot_mode {
107 unsigned int id;
108 const char *name;
109};
110
111struct boot_mode boot_modes[] = {
112 { 0x4D, "i2c" },
113 { 0x5A, "spi" },
114 { 0x8B, "nand" },
115 { 0x78, "sata" },
116 { 0x9C, "pex" },
117 { 0x69, "uart" },
Stefan Roese539fe4a2015-07-20 11:20:37 +0200118 { 0xAE, "sdio" },
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200119 {},
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530120};
121
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200122struct nand_ecc_mode {
123 unsigned int id;
124 const char *name;
125};
126
127struct nand_ecc_mode nand_ecc_modes[] = {
128 { 0x00, "default" },
129 { 0x01, "hamming" },
130 { 0x02, "rs" },
131 { 0x03, "disabled" },
132 {},
133};
134
135/* Used to identify an undefined execution or destination address */
136#define ADDR_INVALID ((uint32_t)-1)
137
138#define BINARY_MAX_ARGS 8
139
140/* In-memory representation of a line of the configuration file */
141struct image_cfg_element {
142 enum {
143 IMAGE_CFG_VERSION = 0x1,
144 IMAGE_CFG_BOOT_FROM,
145 IMAGE_CFG_DEST_ADDR,
146 IMAGE_CFG_EXEC_ADDR,
147 IMAGE_CFG_NAND_BLKSZ,
148 IMAGE_CFG_NAND_BADBLK_LOCATION,
149 IMAGE_CFG_NAND_ECC_MODE,
150 IMAGE_CFG_NAND_PAGESZ,
151 IMAGE_CFG_BINARY,
152 IMAGE_CFG_PAYLOAD,
153 IMAGE_CFG_DATA,
154 } type;
155 union {
156 unsigned int version;
157 unsigned int bootfrom;
158 struct {
159 const char *file;
160 unsigned int args[BINARY_MAX_ARGS];
161 unsigned int nargs;
162 } binary;
163 const char *payload;
164 unsigned int dstaddr;
165 unsigned int execaddr;
166 unsigned int nandblksz;
167 unsigned int nandbadblklocation;
168 unsigned int nandeccmode;
169 unsigned int nandpagesz;
170 struct ext_hdr_v0_reg regdata;
171 };
172};
173
174#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530175
176/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200177 * Byte 8 of the image header contains the version number. In the v0
178 * header, byte 8 was reserved, and always set to 0. In the v1 header,
179 * byte 8 has been changed to a proper field, set to 1.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530180 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200181static unsigned int image_version(void *header)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530182{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200183 unsigned char *ptr = header;
184 return ptr[8];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530185}
186
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200187/*
188 * Utility functions to manipulate boot mode and ecc modes (convert
189 * them back and forth between description strings and the
190 * corresponding numerical identifiers).
191 */
192
193static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530194{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200195 int i;
196 for (i = 0; boot_modes[i].name; i++)
197 if (boot_modes[i].id == id)
198 return boot_modes[i].name;
199 return NULL;
200}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530201
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200202int image_boot_mode_id(const char *boot_mode_name)
203{
204 int i;
205 for (i = 0; boot_modes[i].name; i++)
206 if (!strcmp(boot_modes[i].name, boot_mode_name))
207 return boot_modes[i].id;
208
209 return -1;
210}
211
212int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
213{
214 int i;
215 for (i = 0; nand_ecc_modes[i].name; i++)
216 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
217 return nand_ecc_modes[i].id;
218 return -1;
219}
220
221static struct image_cfg_element *
222image_find_option(unsigned int optiontype)
223{
224 int i;
225
226 for (i = 0; i < cfgn; i++) {
227 if (image_cfg[i].type == optiontype)
228 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530229 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200230
231 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530232}
233
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200234static unsigned int
235image_count_options(unsigned int optiontype)
236{
237 int i;
238 unsigned int count = 0;
239
240 for (i = 0; i < cfgn; i++)
241 if (image_cfg[i].type == optiontype)
242 count++;
243
244 return count;
245}
246
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530247/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200248 * Compute a 8-bit checksum of a memory area. This algorithm follows
249 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530250 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200251static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530252{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200253 uint8_t csum = 0;
254 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530255
256 /* check len and return zero checksum if invalid */
257 if (!len)
258 return 0;
259
260 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200261 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530262 p++;
263 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200264
265 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530266}
267
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200268static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530269{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200270 uint32_t csum = 0;
271 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530272
273 /* check len and return zero checksum if invalid */
274 if (!len)
275 return 0;
276
277 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200278 fprintf(stderr, "Length %d is not in multiple of %zu\n",
279 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530280 return 0;
281 }
282
283 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200284 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530285 p++;
286 len -= sizeof(uint32_t);
287 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200288
289 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530290}
291
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200292static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
293 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530294{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200295 struct image_cfg_element *e;
296 size_t headersz;
297 struct main_hdr_v0 *main_hdr;
298 struct ext_hdr_v0 *ext_hdr;
299 void *image;
300 int has_ext = 0;
301
302 /*
303 * Calculate the size of the header and the size of the
304 * payload
305 */
306 headersz = sizeof(struct main_hdr_v0);
307
308 if (image_count_options(IMAGE_CFG_DATA) > 0) {
309 has_ext = 1;
310 headersz += sizeof(struct ext_hdr_v0);
311 }
312
313 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
314 fprintf(stderr, "More than one payload, not possible\n");
315 return NULL;
316 }
317
318 image = malloc(headersz);
319 if (!image) {
320 fprintf(stderr, "Cannot allocate memory for image\n");
321 return NULL;
322 }
323
324 memset(image, 0, headersz);
325
326 main_hdr = image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530327
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200328 /* Fill in the main header */
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100329 main_hdr->blocksize = payloadsz + sizeof(uint32_t) - headersz;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200330 main_hdr->srcaddr = headersz;
331 main_hdr->ext = has_ext;
332 main_hdr->destaddr = params->addr;
333 main_hdr->execaddr = params->ep;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530334
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200335 e = image_find_option(IMAGE_CFG_BOOT_FROM);
336 if (e)
337 main_hdr->blockid = e->bootfrom;
338 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
339 if (e)
340 main_hdr->nandeccmode = e->nandeccmode;
341 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
342 if (e)
343 main_hdr->nandpagesize = e->nandpagesz;
344 main_hdr->checksum = image_checksum8(image,
345 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530346
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200347 /* Generate the ext header */
348 if (has_ext) {
349 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530350
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200351 ext_hdr = image + sizeof(struct main_hdr_v0);
352 ext_hdr->offset = 0x40;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530353
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200354 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
355 e = &image_cfg[cfgi];
356 if (e->type != IMAGE_CFG_DATA)
357 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530358
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200359 ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
360 ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
361 datai++;
362 }
363
364 ext_hdr->checksum = image_checksum8(ext_hdr,
365 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530366 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530367
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200368 *imagesz = headersz;
369 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530370}
371
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200372static size_t image_headersz_v1(struct image_tool_params *params,
373 int *hasext)
374{
375 struct image_cfg_element *binarye;
376 size_t headersz;
377 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530378
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200379 /*
380 * Calculate the size of the header and the size of the
381 * payload
382 */
383 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530384
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200385 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
386 fprintf(stderr, "More than one binary blob, not supported\n");
387 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530388 }
389
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200390 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
391 fprintf(stderr, "More than one payload, not possible\n");
392 return 0;
393 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530394
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200395 binarye = image_find_option(IMAGE_CFG_BINARY);
396 if (binarye) {
397 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530398
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200399 ret = stat(binarye->binary.file, &s);
400 if (ret < 0) {
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200401 char cwd[PATH_MAX];
402 char *dir = cwd;
403
404 memset(cwd, 0, sizeof(cwd));
405 if (!getcwd(cwd, sizeof(cwd))) {
406 dir = "current working directory";
407 perror("getcwd() failed");
408 }
409
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200410 fprintf(stderr,
411 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
412 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
413 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200414 binarye->binary.file, dir);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200415 return 0;
416 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530417
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200418 headersz += s.st_size +
419 binarye->binary.nargs * sizeof(unsigned int);
420 if (hasext)
421 *hasext = 1;
422 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530423
Stefan Roese69e9dde2015-07-20 11:20:38 +0200424#if defined(CONFIG_SYS_U_BOOT_OFFS)
425 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Kevin Smith88809492015-03-16 14:58:21 +0000426 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese69e9dde2015-07-20 11:20:38 +0200427 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
428 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
429 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smith88809492015-03-16 14:58:21 +0000430 return 0;
431 } else {
Stefan Roese69e9dde2015-07-20 11:20:38 +0200432 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smith88809492015-03-16 14:58:21 +0000433 }
434#endif
435
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200436 /*
437 * The payload should be aligned on some reasonable
438 * boundary
439 */
440 return ALIGN_SUP(headersz, 4096);
441}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530442
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200443static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
444 int payloadsz)
445{
446 struct image_cfg_element *e, *binarye;
447 struct main_hdr_v1 *main_hdr;
448 size_t headersz;
449 void *image, *cur;
450 int hasext = 0;
451 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530452
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200453 /*
454 * Calculate the size of the header and the size of the
455 * payload
456 */
457 headersz = image_headersz_v1(params, &hasext);
458 if (headersz == 0)
459 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530460
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200461 image = malloc(headersz);
462 if (!image) {
463 fprintf(stderr, "Cannot allocate memory for image\n");
464 return NULL;
465 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530466
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200467 memset(image, 0, headersz);
468
469 cur = main_hdr = image;
470 cur += sizeof(struct main_hdr_v1);
471
472 /* Fill the main header */
473 main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t);
474 main_hdr->headersz_lsb = headersz & 0xFFFF;
475 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
476 main_hdr->destaddr = params->addr;
477 main_hdr->execaddr = params->ep;
478 main_hdr->srcaddr = headersz;
479 main_hdr->ext = hasext;
480 main_hdr->version = 1;
481 e = image_find_option(IMAGE_CFG_BOOT_FROM);
482 if (e)
483 main_hdr->blockid = e->bootfrom;
484 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
485 if (e)
486 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
487 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
488 if (e)
489 main_hdr->nandbadblklocation = e->nandbadblklocation;
490
491 binarye = image_find_option(IMAGE_CFG_BINARY);
492 if (binarye) {
493 struct opt_hdr_v1 *hdr = cur;
494 unsigned int *args;
495 size_t binhdrsz;
496 struct stat s;
497 int argi;
498 FILE *bin;
499
500 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
501
502 bin = fopen(binarye->binary.file, "r");
503 if (!bin) {
504 fprintf(stderr, "Cannot open binary file %s\n",
505 binarye->binary.file);
506 return NULL;
507 }
508
509 fstat(fileno(bin), &s);
510
511 binhdrsz = sizeof(struct opt_hdr_v1) +
512 (binarye->binary.nargs + 1) * sizeof(unsigned int) +
513 s.st_size;
Chris Packham3a1fc232015-02-23 11:25:20 +1300514 binhdrsz = ALIGN_SUP(binhdrsz, 32);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200515 hdr->headersz_lsb = binhdrsz & 0xFFFF;
516 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
517
518 cur += sizeof(struct opt_hdr_v1);
519
520 args = cur;
521 *args = binarye->binary.nargs;
522 args++;
523 for (argi = 0; argi < binarye->binary.nargs; argi++)
524 args[argi] = binarye->binary.args[argi];
525
526 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
527
528 ret = fread(cur, s.st_size, 1, bin);
529 if (ret != 1) {
530 fprintf(stderr,
531 "Could not read binary image %s\n",
532 binarye->binary.file);
533 return NULL;
534 }
535
536 fclose(bin);
537
538 cur += s.st_size;
539
540 /*
541 * For now, we don't support more than one binary
542 * header, and no other header types are
543 * supported. So, the binary header is necessarily the
544 * last one
545 */
546 *((unsigned char *)cur) = 0;
547
548 cur += sizeof(uint32_t);
549 }
550
551 /* Calculate and set the header checksum */
552 main_hdr->checksum = image_checksum8(main_hdr, headersz);
553
554 *imagesz = headersz;
555 return image;
556}
557
558static int image_create_config_parse_oneline(char *line,
559 struct image_cfg_element *el)
560{
561 char *keyword, *saveptr;
562 char deliminiters[] = " \t";
563
564 keyword = strtok_r(line, deliminiters, &saveptr);
565 if (!strcmp(keyword, "VERSION")) {
566 char *value = strtok_r(NULL, deliminiters, &saveptr);
567 el->type = IMAGE_CFG_VERSION;
568 el->version = atoi(value);
569 } else if (!strcmp(keyword, "BOOT_FROM")) {
570 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200571 int ret = image_boot_mode_id(value);
572 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200573 fprintf(stderr,
574 "Invalid boot media '%s'\n", value);
575 return -1;
576 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200577 el->type = IMAGE_CFG_BOOT_FROM;
578 el->bootfrom = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200579 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
580 char *value = strtok_r(NULL, deliminiters, &saveptr);
581 el->type = IMAGE_CFG_NAND_BLKSZ;
582 el->nandblksz = strtoul(value, NULL, 16);
583 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
584 char *value = strtok_r(NULL, deliminiters, &saveptr);
585 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
586 el->nandbadblklocation =
587 strtoul(value, NULL, 16);
588 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
589 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200590 int ret = image_nand_ecc_mode_id(value);
591 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200592 fprintf(stderr,
593 "Invalid NAND ECC mode '%s'\n", value);
594 return -1;
595 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200596 el->type = IMAGE_CFG_NAND_ECC_MODE;
597 el->nandeccmode = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200598 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
599 char *value = strtok_r(NULL, deliminiters, &saveptr);
600 el->type = IMAGE_CFG_NAND_PAGESZ;
601 el->nandpagesz = strtoul(value, NULL, 16);
602 } else if (!strcmp(keyword, "BINARY")) {
603 char *value = strtok_r(NULL, deliminiters, &saveptr);
604 int argi = 0;
605
606 el->type = IMAGE_CFG_BINARY;
607 el->binary.file = strdup(value);
608 while (1) {
609 value = strtok_r(NULL, deliminiters, &saveptr);
610 if (!value)
611 break;
612 el->binary.args[argi] = strtoul(value, NULL, 16);
613 argi++;
614 if (argi >= BINARY_MAX_ARGS) {
615 fprintf(stderr,
616 "Too many argument for binary\n");
617 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530618 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530619 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200620 el->binary.nargs = argi;
621 } else if (!strcmp(keyword, "DATA")) {
622 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
623 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
624
625 if (!value1 || !value2) {
626 fprintf(stderr,
627 "Invalid number of arguments for DATA\n");
628 return -1;
629 }
630
631 el->type = IMAGE_CFG_DATA;
632 el->regdata.raddr = strtoul(value1, NULL, 16);
633 el->regdata.rdata = strtoul(value2, NULL, 16);
634 } else {
635 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530636 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530637
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200638 return 0;
639}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530640
641/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200642 * Parse the configuration file 'fcfg' into the array of configuration
643 * elements 'image_cfg', and return the number of configuration
644 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530645 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200646static int image_create_config_parse(FILE *fcfg)
647{
648 int ret;
649 int cfgi = 0;
650
651 /* Parse the configuration file */
652 while (!feof(fcfg)) {
653 char *line;
654 char buf[256];
655
656 /* Read the current line */
657 memset(buf, 0, sizeof(buf));
658 line = fgets(buf, sizeof(buf), fcfg);
659 if (!line)
660 break;
661
662 /* Ignore useless lines */
663 if (line[0] == '\n' || line[0] == '#')
664 continue;
665
666 /* Strip final newline */
667 if (line[strlen(line) - 1] == '\n')
668 line[strlen(line) - 1] = 0;
669
670 /* Parse the current line */
671 ret = image_create_config_parse_oneline(line,
672 &image_cfg[cfgi]);
673 if (ret)
674 return ret;
675
676 cfgi++;
677
678 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
679 fprintf(stderr,
680 "Too many configuration elements in .cfg file\n");
681 return -1;
682 }
683 }
684
685 cfgn = cfgi;
686 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530687}
688
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200689static int image_get_version(void)
690{
691 struct image_cfg_element *e;
692
693 e = image_find_option(IMAGE_CFG_VERSION);
694 if (!e)
695 return -1;
696
697 return e->version;
698}
699
700static int image_version_file(const char *input)
701{
702 FILE *fcfg;
703 int version;
704 int ret;
705
706 fcfg = fopen(input, "r");
707 if (!fcfg) {
708 fprintf(stderr, "Could not open input file %s\n", input);
709 return -1;
710 }
711
712 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
713 sizeof(struct image_cfg_element));
714 if (!image_cfg) {
715 fprintf(stderr, "Cannot allocate memory\n");
716 fclose(fcfg);
717 return -1;
718 }
719
720 memset(image_cfg, 0,
721 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
722 rewind(fcfg);
723
724 ret = image_create_config_parse(fcfg);
725 fclose(fcfg);
726 if (ret) {
727 free(image_cfg);
728 return -1;
729 }
730
731 version = image_get_version();
732 /* Fallback to version 0 is no version is provided in the cfg file */
733 if (version == -1)
734 version = 0;
735
736 free(image_cfg);
737
738 return version;
739}
740
741static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700742 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530743{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200744 FILE *fcfg;
745 void *image = NULL;
746 int version;
Łukasz Majewskif04dab42014-11-21 09:22:43 +0100747 size_t headersz = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530748 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200749 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530750 int size;
751
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200752 fcfg = fopen(params->imagename, "r");
753 if (!fcfg) {
754 fprintf(stderr, "Could not open input file %s\n",
755 params->imagename);
756 exit(EXIT_FAILURE);
757 }
758
759 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
760 sizeof(struct image_cfg_element));
761 if (!image_cfg) {
762 fprintf(stderr, "Cannot allocate memory\n");
763 fclose(fcfg);
764 exit(EXIT_FAILURE);
765 }
766
767 memset(image_cfg, 0,
768 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
769 rewind(fcfg);
770
771 ret = image_create_config_parse(fcfg);
772 fclose(fcfg);
773 if (ret) {
774 free(image_cfg);
775 exit(EXIT_FAILURE);
776 }
777
778 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100779 switch (version) {
780 /*
781 * Fallback to version 0 if no version is provided in the
782 * cfg file
783 */
784 case -1:
785 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200786 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100787 break;
788
789 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200790 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100791 break;
792
793 default:
794 fprintf(stderr, "Unsupported version %d\n", version);
795 free(image_cfg);
796 exit(EXIT_FAILURE);
797 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530798
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200799 if (!image) {
800 fprintf(stderr, "Could not create image\n");
801 free(image_cfg);
802 exit(EXIT_FAILURE);
803 }
804
805 free(image_cfg);
806
807 /* Build and add image checksum header */
808 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
809 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530810 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200811 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530812 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200813 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530814 }
815
816 sbuf->st_size += sizeof(uint32_t);
817
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200818 /* Finally copy the header into the image area */
819 memcpy(ptr, image, headersz);
820
821 free(image);
822}
823
824static void kwbimage_print_header(const void *ptr)
825{
826 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
827
828 printf("Image Type: MVEBU Boot from %s Image\n",
829 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200830 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100831 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200832 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
833 printf("Load Address: %08x\n", mhdr->destaddr);
834 printf("Entry Point: %08x\n", mhdr->execaddr);
835}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530836
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200837static int kwbimage_check_image_types(uint8_t type)
838{
839 if (type == IH_TYPE_KWBIMAGE)
840 return EXIT_SUCCESS;
841 else
842 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530843}
844
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200845static int kwbimage_verify_header(unsigned char *ptr, int image_size,
846 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530847{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200848 struct main_hdr_v0 *main_hdr;
849 struct ext_hdr_v0 *ext_hdr;
850 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530851
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200852 main_hdr = (void *)ptr;
853 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100854 sizeof(struct main_hdr_v0)
855 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200856 if (checksum != main_hdr->checksum)
857 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530858
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200859 /* Only version 0 extended header has checksum */
860 if (image_version((void *)ptr) == 0) {
861 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
862 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100863 sizeof(struct ext_hdr_v0)
864 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200865 if (checksum != ext_hdr->checksum)
866 return -FDT_ERR_BADSTRUCTURE;
867 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530868
869 return 0;
870}
871
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200872static int kwbimage_generate(struct image_tool_params *params,
873 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530874{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200875 int alloc_len;
876 void *hdr;
877 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530878
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200879 version = image_version_file(params->imagename);
880 if (version == 0) {
881 alloc_len = sizeof(struct main_hdr_v0) +
882 sizeof(struct ext_hdr_v0);
883 } else {
884 alloc_len = image_headersz_v1(params, NULL);
885 }
886
887 hdr = malloc(alloc_len);
888 if (!hdr) {
889 fprintf(stderr, "%s: malloc return failure: %s\n",
890 params->cmdname, strerror(errno));
891 exit(EXIT_FAILURE);
892 }
893
894 memset(hdr, 0, alloc_len);
895 tparams->header_size = alloc_len;
896 tparams->hdr = hdr;
897
898 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530899}
900
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200901/*
902 * Report Error if xflag is set in addition to default
903 */
904static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530905{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200906 if (!strlen(params->imagename)) {
907 fprintf(stderr, "Error:%s - Configuration file not specified, "
908 "it is needed for kwbimage generation\n",
909 params->cmdname);
910 return CFG_INVALID;
911 }
912
913 return (params->dflag && (params->fflag || params->lflag)) ||
914 (params->fflag && (params->dflag || params->lflag)) ||
915 (params->lflag && (params->dflag || params->fflag)) ||
916 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530917}
918
919/*
920 * kwbimage type parameters definition
921 */
Guilherme Maciel Ferreira28be1cf2015-01-15 02:48:07 -0200922U_BOOT_IMAGE_TYPE(
923 kwbimage,
924 "Marvell MVEBU Boot Image support",
925 0,
926 NULL,
927 kwbimage_check_params,
928 kwbimage_verify_header,
929 kwbimage_print_header,
930 kwbimage_set_header,
931 NULL,
932 kwbimage_check_image_types,
933 NULL,
934 kwbimage_generate
935);