blob: 28ce1e4f08f24230191e66009f2e07a41c55d40d [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"
Stefan Roese6e8e9b62015-01-19 11:33:44 +010019#include <config.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053020
Stefan Roese3b8b19d2014-10-22 12:13:23 +020021#define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
22
23/* Structure of the main header, version 0 (Kirkwood, Dove) */
24struct main_hdr_v0 {
25 uint8_t blockid; /*0 */
26 uint8_t nandeccmode; /*1 */
27 uint16_t nandpagesize; /*2-3 */
28 uint32_t blocksize; /*4-7 */
29 uint32_t rsvd1; /*8-11 */
30 uint32_t srcaddr; /*12-15 */
31 uint32_t destaddr; /*16-19 */
32 uint32_t execaddr; /*20-23 */
33 uint8_t satapiomode; /*24 */
34 uint8_t rsvd3; /*25 */
35 uint16_t ddrinitdelay; /*26-27 */
36 uint16_t rsvd2; /*28-29 */
37 uint8_t ext; /*30 */
38 uint8_t checksum; /*31 */
39};
40
41struct ext_hdr_v0_reg {
42 uint32_t raddr;
43 uint32_t rdata;
Prafulla Wadaskar07329412009-09-07 15:05:02 +053044};
45
Stefan Roese3b8b19d2014-10-22 12:13:23 +020046#define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
47
48struct ext_hdr_v0 {
49 uint32_t offset;
50 uint8_t reserved[0x20 - sizeof(uint32_t)];
51 struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
52 uint8_t reserved2[7];
53 uint8_t checksum;
54};
55
56/* Structure of the main header, version 1 (Armada 370, Armada XP) */
57struct main_hdr_v1 {
58 uint8_t blockid; /* 0 */
59 uint8_t reserved1; /* 1 */
60 uint16_t reserved2; /* 2-3 */
61 uint32_t blocksize; /* 4-7 */
62 uint8_t version; /* 8 */
63 uint8_t headersz_msb; /* 9 */
64 uint16_t headersz_lsb; /* A-B */
65 uint32_t srcaddr; /* C-F */
66 uint32_t destaddr; /* 10-13 */
67 uint32_t execaddr; /* 14-17 */
68 uint8_t reserved3; /* 18 */
69 uint8_t nandblocksize; /* 19 */
70 uint8_t nandbadblklocation; /* 1A */
71 uint8_t reserved4; /* 1B */
72 uint16_t reserved5; /* 1C-1D */
73 uint8_t ext; /* 1E */
74 uint8_t checksum; /* 1F */
75};
76
Prafulla Wadaskar07329412009-09-07 15:05:02 +053077/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020078 * Header for the optional headers, version 1 (Armada 370, Armada XP)
Prafulla Wadaskar07329412009-09-07 15:05:02 +053079 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +020080struct opt_hdr_v1 {
81 uint8_t headertype;
82 uint8_t headersz_msb;
83 uint16_t headersz_lsb;
84 char data[0];
Prafulla Wadaskar07329412009-09-07 15:05:02 +053085};
86
87/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020088 * Various values for the opt_hdr_v1->headertype field, describing the
89 * different types of optional headers. The "secure" header contains
90 * informations related to secure boot (encryption keys, etc.). The
91 * "binary" header contains ARM binary code to be executed prior to
92 * executing the main payload (usually the bootloader). This is
93 * typically used to execute DDR3 training code. The "register" header
94 * allows to describe a set of (address, value) tuples that are
95 * generally used to configure the DRAM controller.
Prafulla Wadaskar07329412009-09-07 15:05:02 +053096 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +020097#define OPT_HDR_V1_SECURE_TYPE 0x1
98#define OPT_HDR_V1_BINARY_TYPE 0x2
99#define OPT_HDR_V1_REGISTER_TYPE 0x3
100
101#define KWBHEADER_V1_SIZE(hdr) \
102 (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
103
104static struct image_cfg_element *image_cfg;
105static int cfgn;
106
107struct boot_mode {
108 unsigned int id;
109 const char *name;
110};
111
112struct boot_mode boot_modes[] = {
113 { 0x4D, "i2c" },
114 { 0x5A, "spi" },
115 { 0x8B, "nand" },
116 { 0x78, "sata" },
117 { 0x9C, "pex" },
118 { 0x69, "uart" },
119 {},
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 Roese3b8b19d2014-10-22 12:13:23 +0200424 /*
425 * The payload should be aligned on some reasonable
426 * boundary
427 */
428 return ALIGN_SUP(headersz, 4096);
429}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530430
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200431static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
432 int payloadsz)
433{
434 struct image_cfg_element *e, *binarye;
435 struct main_hdr_v1 *main_hdr;
436 size_t headersz;
437 void *image, *cur;
438 int hasext = 0;
439 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530440
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200441 /*
442 * Calculate the size of the header and the size of the
443 * payload
444 */
445 headersz = image_headersz_v1(params, &hasext);
446 if (headersz == 0)
447 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530448
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200449 image = malloc(headersz);
450 if (!image) {
451 fprintf(stderr, "Cannot allocate memory for image\n");
452 return NULL;
453 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530454
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200455 memset(image, 0, headersz);
456
457 cur = main_hdr = image;
458 cur += sizeof(struct main_hdr_v1);
459
460 /* Fill the main header */
461 main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t);
462 main_hdr->headersz_lsb = headersz & 0xFFFF;
463 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
464 main_hdr->destaddr = params->addr;
465 main_hdr->execaddr = params->ep;
466 main_hdr->srcaddr = headersz;
467 main_hdr->ext = hasext;
468 main_hdr->version = 1;
469 e = image_find_option(IMAGE_CFG_BOOT_FROM);
470 if (e)
471 main_hdr->blockid = e->bootfrom;
472 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
473 if (e)
474 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
475 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
476 if (e)
477 main_hdr->nandbadblklocation = e->nandbadblklocation;
478
479 binarye = image_find_option(IMAGE_CFG_BINARY);
480 if (binarye) {
481 struct opt_hdr_v1 *hdr = cur;
482 unsigned int *args;
483 size_t binhdrsz;
484 struct stat s;
485 int argi;
486 FILE *bin;
487
488 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
489
490 bin = fopen(binarye->binary.file, "r");
491 if (!bin) {
492 fprintf(stderr, "Cannot open binary file %s\n",
493 binarye->binary.file);
494 return NULL;
495 }
496
497 fstat(fileno(bin), &s);
498
499 binhdrsz = sizeof(struct opt_hdr_v1) +
500 (binarye->binary.nargs + 1) * sizeof(unsigned int) +
501 s.st_size;
502 hdr->headersz_lsb = binhdrsz & 0xFFFF;
503 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
504
505 cur += sizeof(struct opt_hdr_v1);
506
507 args = cur;
508 *args = binarye->binary.nargs;
509 args++;
510 for (argi = 0; argi < binarye->binary.nargs; argi++)
511 args[argi] = binarye->binary.args[argi];
512
513 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
514
515 ret = fread(cur, s.st_size, 1, bin);
516 if (ret != 1) {
517 fprintf(stderr,
518 "Could not read binary image %s\n",
519 binarye->binary.file);
520 return NULL;
521 }
522
523 fclose(bin);
524
525 cur += s.st_size;
526
527 /*
528 * For now, we don't support more than one binary
529 * header, and no other header types are
530 * supported. So, the binary header is necessarily the
531 * last one
532 */
533 *((unsigned char *)cur) = 0;
534
535 cur += sizeof(uint32_t);
536 }
537
538 /* Calculate and set the header checksum */
539 main_hdr->checksum = image_checksum8(main_hdr, headersz);
540
541 *imagesz = headersz;
542 return image;
543}
544
545static int image_create_config_parse_oneline(char *line,
546 struct image_cfg_element *el)
547{
548 char *keyword, *saveptr;
549 char deliminiters[] = " \t";
550
551 keyword = strtok_r(line, deliminiters, &saveptr);
552 if (!strcmp(keyword, "VERSION")) {
553 char *value = strtok_r(NULL, deliminiters, &saveptr);
554 el->type = IMAGE_CFG_VERSION;
555 el->version = atoi(value);
556 } else if (!strcmp(keyword, "BOOT_FROM")) {
557 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200558 int ret = image_boot_mode_id(value);
559 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200560 fprintf(stderr,
561 "Invalid boot media '%s'\n", value);
562 return -1;
563 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200564 el->type = IMAGE_CFG_BOOT_FROM;
565 el->bootfrom = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200566 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
567 char *value = strtok_r(NULL, deliminiters, &saveptr);
568 el->type = IMAGE_CFG_NAND_BLKSZ;
569 el->nandblksz = strtoul(value, NULL, 16);
570 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
571 char *value = strtok_r(NULL, deliminiters, &saveptr);
572 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
573 el->nandbadblklocation =
574 strtoul(value, NULL, 16);
575 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
576 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200577 int ret = image_nand_ecc_mode_id(value);
578 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200579 fprintf(stderr,
580 "Invalid NAND ECC mode '%s'\n", value);
581 return -1;
582 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200583 el->type = IMAGE_CFG_NAND_ECC_MODE;
584 el->nandeccmode = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200585 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
586 char *value = strtok_r(NULL, deliminiters, &saveptr);
587 el->type = IMAGE_CFG_NAND_PAGESZ;
588 el->nandpagesz = strtoul(value, NULL, 16);
589 } else if (!strcmp(keyword, "BINARY")) {
590 char *value = strtok_r(NULL, deliminiters, &saveptr);
591 int argi = 0;
592
593 el->type = IMAGE_CFG_BINARY;
594 el->binary.file = strdup(value);
595 while (1) {
596 value = strtok_r(NULL, deliminiters, &saveptr);
597 if (!value)
598 break;
599 el->binary.args[argi] = strtoul(value, NULL, 16);
600 argi++;
601 if (argi >= BINARY_MAX_ARGS) {
602 fprintf(stderr,
603 "Too many argument for binary\n");
604 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530605 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530606 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200607 el->binary.nargs = argi;
608 } else if (!strcmp(keyword, "DATA")) {
609 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
610 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
611
612 if (!value1 || !value2) {
613 fprintf(stderr,
614 "Invalid number of arguments for DATA\n");
615 return -1;
616 }
617
618 el->type = IMAGE_CFG_DATA;
619 el->regdata.raddr = strtoul(value1, NULL, 16);
620 el->regdata.rdata = strtoul(value2, NULL, 16);
621 } else {
622 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530623 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530624
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200625 return 0;
626}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530627
628/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200629 * Parse the configuration file 'fcfg' into the array of configuration
630 * elements 'image_cfg', and return the number of configuration
631 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530632 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200633static int image_create_config_parse(FILE *fcfg)
634{
635 int ret;
636 int cfgi = 0;
637
638 /* Parse the configuration file */
639 while (!feof(fcfg)) {
640 char *line;
641 char buf[256];
642
643 /* Read the current line */
644 memset(buf, 0, sizeof(buf));
645 line = fgets(buf, sizeof(buf), fcfg);
646 if (!line)
647 break;
648
649 /* Ignore useless lines */
650 if (line[0] == '\n' || line[0] == '#')
651 continue;
652
653 /* Strip final newline */
654 if (line[strlen(line) - 1] == '\n')
655 line[strlen(line) - 1] = 0;
656
657 /* Parse the current line */
658 ret = image_create_config_parse_oneline(line,
659 &image_cfg[cfgi]);
660 if (ret)
661 return ret;
662
663 cfgi++;
664
665 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
666 fprintf(stderr,
667 "Too many configuration elements in .cfg file\n");
668 return -1;
669 }
670 }
671
672 cfgn = cfgi;
673 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530674}
675
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200676static int image_get_version(void)
677{
678 struct image_cfg_element *e;
679
680 e = image_find_option(IMAGE_CFG_VERSION);
681 if (!e)
682 return -1;
683
684 return e->version;
685}
686
687static int image_version_file(const char *input)
688{
689 FILE *fcfg;
690 int version;
691 int ret;
692
693 fcfg = fopen(input, "r");
694 if (!fcfg) {
695 fprintf(stderr, "Could not open input file %s\n", input);
696 return -1;
697 }
698
699 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
700 sizeof(struct image_cfg_element));
701 if (!image_cfg) {
702 fprintf(stderr, "Cannot allocate memory\n");
703 fclose(fcfg);
704 return -1;
705 }
706
707 memset(image_cfg, 0,
708 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
709 rewind(fcfg);
710
711 ret = image_create_config_parse(fcfg);
712 fclose(fcfg);
713 if (ret) {
714 free(image_cfg);
715 return -1;
716 }
717
718 version = image_get_version();
719 /* Fallback to version 0 is no version is provided in the cfg file */
720 if (version == -1)
721 version = 0;
722
723 free(image_cfg);
724
725 return version;
726}
727
728static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700729 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530730{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200731 FILE *fcfg;
732 void *image = NULL;
733 int version;
Łukasz Majewskif04dab42014-11-21 09:22:43 +0100734 size_t headersz = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530735 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200736 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530737 int size;
738
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200739 fcfg = fopen(params->imagename, "r");
740 if (!fcfg) {
741 fprintf(stderr, "Could not open input file %s\n",
742 params->imagename);
743 exit(EXIT_FAILURE);
744 }
745
746 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
747 sizeof(struct image_cfg_element));
748 if (!image_cfg) {
749 fprintf(stderr, "Cannot allocate memory\n");
750 fclose(fcfg);
751 exit(EXIT_FAILURE);
752 }
753
754 memset(image_cfg, 0,
755 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
756 rewind(fcfg);
757
758 ret = image_create_config_parse(fcfg);
759 fclose(fcfg);
760 if (ret) {
761 free(image_cfg);
762 exit(EXIT_FAILURE);
763 }
764
765 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100766 switch (version) {
767 /*
768 * Fallback to version 0 if no version is provided in the
769 * cfg file
770 */
771 case -1:
772 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200773 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100774 break;
775
776 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200777 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100778 break;
779
780 default:
781 fprintf(stderr, "Unsupported version %d\n", version);
782 free(image_cfg);
783 exit(EXIT_FAILURE);
784 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530785
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200786 if (!image) {
787 fprintf(stderr, "Could not create image\n");
788 free(image_cfg);
789 exit(EXIT_FAILURE);
790 }
791
792 free(image_cfg);
793
794 /* Build and add image checksum header */
795 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
796 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530797 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200798 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530799 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200800 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530801 }
802
803 sbuf->st_size += sizeof(uint32_t);
804
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200805 /* Finally copy the header into the image area */
806 memcpy(ptr, image, headersz);
807
808 free(image);
809}
810
811static void kwbimage_print_header(const void *ptr)
812{
813 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
814
815 printf("Image Type: MVEBU Boot from %s Image\n",
816 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200817 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100818 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200819 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
820 printf("Load Address: %08x\n", mhdr->destaddr);
821 printf("Entry Point: %08x\n", mhdr->execaddr);
822}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530823
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200824static int kwbimage_check_image_types(uint8_t type)
825{
826 if (type == IH_TYPE_KWBIMAGE)
827 return EXIT_SUCCESS;
828 else
829 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530830}
831
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200832static int kwbimage_verify_header(unsigned char *ptr, int image_size,
833 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530834{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200835 struct main_hdr_v0 *main_hdr;
836 struct ext_hdr_v0 *ext_hdr;
837 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530838
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200839 main_hdr = (void *)ptr;
840 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100841 sizeof(struct main_hdr_v0)
842 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200843 if (checksum != main_hdr->checksum)
844 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530845
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200846 /* Only version 0 extended header has checksum */
847 if (image_version((void *)ptr) == 0) {
848 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
849 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100850 sizeof(struct ext_hdr_v0)
851 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200852 if (checksum != ext_hdr->checksum)
853 return -FDT_ERR_BADSTRUCTURE;
854 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530855
856 return 0;
857}
858
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200859static int kwbimage_generate(struct image_tool_params *params,
860 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530861{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200862 int alloc_len;
863 void *hdr;
864 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530865
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200866 version = image_version_file(params->imagename);
867 if (version == 0) {
868 alloc_len = sizeof(struct main_hdr_v0) +
869 sizeof(struct ext_hdr_v0);
870 } else {
871 alloc_len = image_headersz_v1(params, NULL);
Stefan Roese6e8e9b62015-01-19 11:33:44 +0100872#if defined(CONFIG_SYS_SPI_U_BOOT_OFFS)
873 if (alloc_len > CONFIG_SYS_SPI_U_BOOT_OFFS) {
874 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
875 fprintf(stderr, "header=0x%x CONFIG_SYS_SPI_U_BOOT_OFFS=0x%x!\n",
876 alloc_len, CONFIG_SYS_SPI_U_BOOT_OFFS);
877 fprintf(stderr, "Increase CONFIG_SYS_SPI_U_BOOT_OFFS!\n");
878 } else {
879 alloc_len = CONFIG_SYS_SPI_U_BOOT_OFFS;
880 }
881#endif
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200882 }
883
884 hdr = malloc(alloc_len);
885 if (!hdr) {
886 fprintf(stderr, "%s: malloc return failure: %s\n",
887 params->cmdname, strerror(errno));
888 exit(EXIT_FAILURE);
889 }
890
891 memset(hdr, 0, alloc_len);
892 tparams->header_size = alloc_len;
893 tparams->hdr = hdr;
894
895 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530896}
897
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200898/*
899 * Report Error if xflag is set in addition to default
900 */
901static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530902{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200903 if (!strlen(params->imagename)) {
904 fprintf(stderr, "Error:%s - Configuration file not specified, "
905 "it is needed for kwbimage generation\n",
906 params->cmdname);
907 return CFG_INVALID;
908 }
909
910 return (params->dflag && (params->fflag || params->lflag)) ||
911 (params->fflag && (params->dflag || params->lflag)) ||
912 (params->lflag && (params->dflag || params->fflag)) ||
913 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530914}
915
916/*
917 * kwbimage type parameters definition
918 */
Guilherme Maciel Ferreira28be1cf2015-01-15 02:48:07 -0200919U_BOOT_IMAGE_TYPE(
920 kwbimage,
921 "Marvell MVEBU Boot Image support",
922 0,
923 NULL,
924 kwbimage_check_params,
925 kwbimage_verify_header,
926 kwbimage_print_header,
927 kwbimage_set_header,
928 NULL,
929 kwbimage_check_image_types,
930 NULL,
931 kwbimage_generate
932);