blob: 69844d91696563cb5607184ff283b0cc01a18a05 [file] [log] [blame]
Prafulla Wadaskar07329412009-09-07 15:05:02 +05301/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +02002 * Image manipulator for Marvell SoCs
3 * supports Kirkwood, Dove, Armada 370, and Armada XP
4 *
5 * (C) Copyright 2013 Thomas Petazzoni
6 * <thomas.petazzoni@free-electrons.com>
Prafulla Wadaskar07329412009-09-07 15:05:02 +05307 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
Stefan Roese3b8b19d2014-10-22 12:13:23 +02009 *
10 * Not implemented: support for the register headers and secure
11 * headers in v1 images
Prafulla Wadaskar07329412009-09-07 15:05:02 +053012 */
13
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -070014#include "imagetool.h"
Andreas Bießmann7abec5b2014-10-24 23:39:11 +020015#include <limits.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053016#include <image.h>
Stefan Roese3b8b19d2014-10-22 12:13:23 +020017#include <stdint.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053018#include "kwbimage.h"
19
Stefan Roese3b8b19d2014-10-22 12:13:23 +020020static struct image_cfg_element *image_cfg;
21static int cfgn;
22
23struct boot_mode {
24 unsigned int id;
25 const char *name;
26};
27
28struct boot_mode boot_modes[] = {
29 { 0x4D, "i2c" },
30 { 0x5A, "spi" },
31 { 0x8B, "nand" },
32 { 0x78, "sata" },
33 { 0x9C, "pex" },
34 { 0x69, "uart" },
Stefan Roese539fe4a2015-07-20 11:20:37 +020035 { 0xAE, "sdio" },
Stefan Roese3b8b19d2014-10-22 12:13:23 +020036 {},
Prafulla Wadaskar07329412009-09-07 15:05:02 +053037};
38
Stefan Roese3b8b19d2014-10-22 12:13:23 +020039struct nand_ecc_mode {
40 unsigned int id;
41 const char *name;
42};
43
44struct nand_ecc_mode nand_ecc_modes[] = {
45 { 0x00, "default" },
46 { 0x01, "hamming" },
47 { 0x02, "rs" },
48 { 0x03, "disabled" },
49 {},
50};
51
52/* Used to identify an undefined execution or destination address */
53#define ADDR_INVALID ((uint32_t)-1)
54
55#define BINARY_MAX_ARGS 8
56
57/* In-memory representation of a line of the configuration file */
58struct image_cfg_element {
59 enum {
60 IMAGE_CFG_VERSION = 0x1,
61 IMAGE_CFG_BOOT_FROM,
62 IMAGE_CFG_DEST_ADDR,
63 IMAGE_CFG_EXEC_ADDR,
64 IMAGE_CFG_NAND_BLKSZ,
65 IMAGE_CFG_NAND_BADBLK_LOCATION,
66 IMAGE_CFG_NAND_ECC_MODE,
67 IMAGE_CFG_NAND_PAGESZ,
68 IMAGE_CFG_BINARY,
69 IMAGE_CFG_PAYLOAD,
70 IMAGE_CFG_DATA,
Chris Packham883bf452016-11-09 22:07:45 +130071 IMAGE_CFG_BAUDRATE,
Chris Packham1e0728a2016-11-09 22:21:45 +130072 IMAGE_CFG_DEBUG,
Stefan Roese3b8b19d2014-10-22 12:13:23 +020073 } type;
74 union {
75 unsigned int version;
76 unsigned int bootfrom;
77 struct {
78 const char *file;
79 unsigned int args[BINARY_MAX_ARGS];
80 unsigned int nargs;
81 } binary;
82 const char *payload;
83 unsigned int dstaddr;
84 unsigned int execaddr;
85 unsigned int nandblksz;
86 unsigned int nandbadblklocation;
87 unsigned int nandeccmode;
88 unsigned int nandpagesz;
89 struct ext_hdr_v0_reg regdata;
Chris Packham883bf452016-11-09 22:07:45 +130090 unsigned int baudrate;
Chris Packham1e0728a2016-11-09 22:21:45 +130091 unsigned int debug;
Stefan Roese3b8b19d2014-10-22 12:13:23 +020092 };
93};
94
95#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskar07329412009-09-07 15:05:02 +053096
97/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020098 * Utility functions to manipulate boot mode and ecc modes (convert
99 * them back and forth between description strings and the
100 * corresponding numerical identifiers).
101 */
102
103static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530104{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200105 int i;
106 for (i = 0; boot_modes[i].name; i++)
107 if (boot_modes[i].id == id)
108 return boot_modes[i].name;
109 return NULL;
110}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530111
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200112int image_boot_mode_id(const char *boot_mode_name)
113{
114 int i;
115 for (i = 0; boot_modes[i].name; i++)
116 if (!strcmp(boot_modes[i].name, boot_mode_name))
117 return boot_modes[i].id;
118
119 return -1;
120}
121
122int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
123{
124 int i;
125 for (i = 0; nand_ecc_modes[i].name; i++)
126 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
127 return nand_ecc_modes[i].id;
128 return -1;
129}
130
131static struct image_cfg_element *
132image_find_option(unsigned int optiontype)
133{
134 int i;
135
136 for (i = 0; i < cfgn; i++) {
137 if (image_cfg[i].type == optiontype)
138 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530139 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200140
141 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530142}
143
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200144static unsigned int
145image_count_options(unsigned int optiontype)
146{
147 int i;
148 unsigned int count = 0;
149
150 for (i = 0; i < cfgn; i++)
151 if (image_cfg[i].type == optiontype)
152 count++;
153
154 return count;
155}
156
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530157/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200158 * Compute a 8-bit checksum of a memory area. This algorithm follows
159 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530160 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200161static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530162{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200163 uint8_t csum = 0;
164 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530165
166 /* check len and return zero checksum if invalid */
167 if (!len)
168 return 0;
169
170 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200171 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530172 p++;
173 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200174
175 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530176}
177
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200178static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530179{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200180 uint32_t csum = 0;
181 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530182
183 /* check len and return zero checksum if invalid */
184 if (!len)
185 return 0;
186
187 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200188 fprintf(stderr, "Length %d is not in multiple of %zu\n",
189 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530190 return 0;
191 }
192
193 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200194 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530195 p++;
196 len -= sizeof(uint32_t);
197 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200198
199 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530200}
201
Chris Packham883bf452016-11-09 22:07:45 +1300202static uint8_t baudrate_to_option(unsigned int baudrate)
203{
204 switch (baudrate) {
205 case 2400:
206 return MAIN_HDR_V1_OPT_BAUD_2400;
207 case 4800:
208 return MAIN_HDR_V1_OPT_BAUD_4800;
209 case 9600:
210 return MAIN_HDR_V1_OPT_BAUD_9600;
211 case 19200:
212 return MAIN_HDR_V1_OPT_BAUD_19200;
213 case 38400:
214 return MAIN_HDR_V1_OPT_BAUD_38400;
215 case 57600:
216 return MAIN_HDR_V1_OPT_BAUD_57600;
217 case 115200:
218 return MAIN_HDR_V1_OPT_BAUD_115200;
219 default:
220 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
221 }
222}
223
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200224static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
225 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530226{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200227 struct image_cfg_element *e;
228 size_t headersz;
229 struct main_hdr_v0 *main_hdr;
230 struct ext_hdr_v0 *ext_hdr;
231 void *image;
232 int has_ext = 0;
233
234 /*
235 * Calculate the size of the header and the size of the
236 * payload
237 */
238 headersz = sizeof(struct main_hdr_v0);
239
240 if (image_count_options(IMAGE_CFG_DATA) > 0) {
241 has_ext = 1;
242 headersz += sizeof(struct ext_hdr_v0);
243 }
244
245 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
246 fprintf(stderr, "More than one payload, not possible\n");
247 return NULL;
248 }
249
250 image = malloc(headersz);
251 if (!image) {
252 fprintf(stderr, "Cannot allocate memory for image\n");
253 return NULL;
254 }
255
256 memset(image, 0, headersz);
257
258 main_hdr = image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530259
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200260 /* Fill in the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100261 main_hdr->blocksize =
262 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
263 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200264 main_hdr->ext = has_ext;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100265 main_hdr->destaddr = cpu_to_le32(params->addr);
266 main_hdr->execaddr = cpu_to_le32(params->ep);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530267
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200268 e = image_find_option(IMAGE_CFG_BOOT_FROM);
269 if (e)
270 main_hdr->blockid = e->bootfrom;
271 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
272 if (e)
273 main_hdr->nandeccmode = e->nandeccmode;
274 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
275 if (e)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100276 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200277 main_hdr->checksum = image_checksum8(image,
278 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530279
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200280 /* Generate the ext header */
281 if (has_ext) {
282 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530283
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200284 ext_hdr = image + sizeof(struct main_hdr_v0);
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100285 ext_hdr->offset = cpu_to_le32(0x40);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530286
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200287 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
288 e = &image_cfg[cfgi];
289 if (e->type != IMAGE_CFG_DATA)
290 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530291
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100292 ext_hdr->rcfg[datai].raddr =
293 cpu_to_le32(e->regdata.raddr);
294 ext_hdr->rcfg[datai].rdata =
295 cpu_to_le32(e->regdata.rdata);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200296 datai++;
297 }
298
299 ext_hdr->checksum = image_checksum8(ext_hdr,
300 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530301 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530302
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200303 *imagesz = headersz;
304 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530305}
306
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200307static size_t image_headersz_v1(struct image_tool_params *params,
308 int *hasext)
309{
310 struct image_cfg_element *binarye;
311 size_t headersz;
312 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530313
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200314 /*
315 * Calculate the size of the header and the size of the
316 * payload
317 */
318 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530319
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200320 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
321 fprintf(stderr, "More than one binary blob, not supported\n");
322 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530323 }
324
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200325 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
326 fprintf(stderr, "More than one payload, not possible\n");
327 return 0;
328 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530329
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200330 binarye = image_find_option(IMAGE_CFG_BINARY);
331 if (binarye) {
332 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530333
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200334 ret = stat(binarye->binary.file, &s);
335 if (ret < 0) {
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200336 char cwd[PATH_MAX];
337 char *dir = cwd;
338
339 memset(cwd, 0, sizeof(cwd));
340 if (!getcwd(cwd, sizeof(cwd))) {
341 dir = "current working directory";
342 perror("getcwd() failed");
343 }
344
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200345 fprintf(stderr,
346 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
347 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
348 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200349 binarye->binary.file, dir);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200350 return 0;
351 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530352
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100353 headersz += sizeof(struct opt_hdr_v1) +
354 s.st_size +
355 (binarye->binary.nargs + 2) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200356 if (hasext)
357 *hasext = 1;
358 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530359
Stefan Roese69e9dde2015-07-20 11:20:38 +0200360#if defined(CONFIG_SYS_U_BOOT_OFFS)
361 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Kevin Smith88809492015-03-16 14:58:21 +0000362 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese69e9dde2015-07-20 11:20:38 +0200363 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
364 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
365 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smith88809492015-03-16 14:58:21 +0000366 return 0;
367 } else {
Stefan Roese69e9dde2015-07-20 11:20:38 +0200368 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smith88809492015-03-16 14:58:21 +0000369 }
370#endif
371
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200372 /*
373 * The payload should be aligned on some reasonable
374 * boundary
375 */
376 return ALIGN_SUP(headersz, 4096);
377}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530378
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200379static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
380 int payloadsz)
381{
382 struct image_cfg_element *e, *binarye;
383 struct main_hdr_v1 *main_hdr;
384 size_t headersz;
385 void *image, *cur;
386 int hasext = 0;
387 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530388
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200389 /*
390 * Calculate the size of the header and the size of the
391 * payload
392 */
393 headersz = image_headersz_v1(params, &hasext);
394 if (headersz == 0)
395 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530396
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200397 image = malloc(headersz);
398 if (!image) {
399 fprintf(stderr, "Cannot allocate memory for image\n");
400 return NULL;
401 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530402
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200403 memset(image, 0, headersz);
404
405 cur = main_hdr = image;
406 cur += sizeof(struct main_hdr_v1);
407
408 /* Fill the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100409 main_hdr->blocksize =
410 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
411 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200412 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100413 main_hdr->destaddr = cpu_to_le32(params->addr);
414 main_hdr->execaddr = cpu_to_le32(params->ep);
415 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200416 main_hdr->ext = hasext;
417 main_hdr->version = 1;
418 e = image_find_option(IMAGE_CFG_BOOT_FROM);
419 if (e)
420 main_hdr->blockid = e->bootfrom;
421 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
422 if (e)
423 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
424 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
425 if (e)
426 main_hdr->nandbadblklocation = e->nandbadblklocation;
Chris Packham883bf452016-11-09 22:07:45 +1300427 e = image_find_option(IMAGE_CFG_BAUDRATE);
428 if (e)
429 main_hdr->options = baudrate_to_option(e->baudrate);
Chris Packham1e0728a2016-11-09 22:21:45 +1300430 e = image_find_option(IMAGE_CFG_DEBUG);
431 if (e)
432 main_hdr->flags = e->debug ? 0x1 : 0;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200433
434 binarye = image_find_option(IMAGE_CFG_BINARY);
435 if (binarye) {
436 struct opt_hdr_v1 *hdr = cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100437 uint32_t *args;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200438 size_t binhdrsz;
439 struct stat s;
440 int argi;
441 FILE *bin;
442
443 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
444
445 bin = fopen(binarye->binary.file, "r");
446 if (!bin) {
447 fprintf(stderr, "Cannot open binary file %s\n",
448 binarye->binary.file);
449 return NULL;
450 }
451
452 fstat(fileno(bin), &s);
453
454 binhdrsz = sizeof(struct opt_hdr_v1) +
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100455 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200456 s.st_size;
Stefan Roesea4279a52015-10-28 07:53:58 +0100457
458 /*
459 * The size includes the binary image size, rounded
460 * up to a 4-byte boundary. Plus 4 bytes for the
461 * next-header byte and 3-byte alignment at the end.
462 */
463 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100464 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200465 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
466
467 cur += sizeof(struct opt_hdr_v1);
468
469 args = cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100470 *args = cpu_to_le32(binarye->binary.nargs);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200471 args++;
472 for (argi = 0; argi < binarye->binary.nargs; argi++)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100473 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200474
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100475 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200476
477 ret = fread(cur, s.st_size, 1, bin);
478 if (ret != 1) {
479 fprintf(stderr,
480 "Could not read binary image %s\n",
481 binarye->binary.file);
482 return NULL;
483 }
484
485 fclose(bin);
486
Stefan Roesea4279a52015-10-28 07:53:58 +0100487 cur += ALIGN_SUP(s.st_size, 4);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200488
489 /*
490 * For now, we don't support more than one binary
491 * header, and no other header types are
492 * supported. So, the binary header is necessarily the
493 * last one
494 */
Stefan Roesea4279a52015-10-28 07:53:58 +0100495 *((uint32_t *)cur) = 0x00000000;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200496
497 cur += sizeof(uint32_t);
498 }
499
500 /* Calculate and set the header checksum */
501 main_hdr->checksum = image_checksum8(main_hdr, headersz);
502
503 *imagesz = headersz;
504 return image;
505}
506
507static int image_create_config_parse_oneline(char *line,
508 struct image_cfg_element *el)
509{
510 char *keyword, *saveptr;
511 char deliminiters[] = " \t";
512
513 keyword = strtok_r(line, deliminiters, &saveptr);
514 if (!strcmp(keyword, "VERSION")) {
515 char *value = strtok_r(NULL, deliminiters, &saveptr);
516 el->type = IMAGE_CFG_VERSION;
517 el->version = atoi(value);
518 } else if (!strcmp(keyword, "BOOT_FROM")) {
519 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200520 int ret = image_boot_mode_id(value);
521 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200522 fprintf(stderr,
523 "Invalid boot media '%s'\n", value);
524 return -1;
525 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200526 el->type = IMAGE_CFG_BOOT_FROM;
527 el->bootfrom = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200528 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
529 char *value = strtok_r(NULL, deliminiters, &saveptr);
530 el->type = IMAGE_CFG_NAND_BLKSZ;
531 el->nandblksz = strtoul(value, NULL, 16);
532 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
533 char *value = strtok_r(NULL, deliminiters, &saveptr);
534 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
535 el->nandbadblklocation =
536 strtoul(value, NULL, 16);
537 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
538 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200539 int ret = image_nand_ecc_mode_id(value);
540 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200541 fprintf(stderr,
542 "Invalid NAND ECC mode '%s'\n", value);
543 return -1;
544 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200545 el->type = IMAGE_CFG_NAND_ECC_MODE;
546 el->nandeccmode = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200547 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
548 char *value = strtok_r(NULL, deliminiters, &saveptr);
549 el->type = IMAGE_CFG_NAND_PAGESZ;
550 el->nandpagesz = strtoul(value, NULL, 16);
551 } else if (!strcmp(keyword, "BINARY")) {
552 char *value = strtok_r(NULL, deliminiters, &saveptr);
553 int argi = 0;
554
555 el->type = IMAGE_CFG_BINARY;
556 el->binary.file = strdup(value);
557 while (1) {
558 value = strtok_r(NULL, deliminiters, &saveptr);
559 if (!value)
560 break;
561 el->binary.args[argi] = strtoul(value, NULL, 16);
562 argi++;
563 if (argi >= BINARY_MAX_ARGS) {
564 fprintf(stderr,
565 "Too many argument for binary\n");
566 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530567 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530568 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200569 el->binary.nargs = argi;
570 } else if (!strcmp(keyword, "DATA")) {
571 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
572 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
573
574 if (!value1 || !value2) {
575 fprintf(stderr,
576 "Invalid number of arguments for DATA\n");
577 return -1;
578 }
579
580 el->type = IMAGE_CFG_DATA;
581 el->regdata.raddr = strtoul(value1, NULL, 16);
582 el->regdata.rdata = strtoul(value2, NULL, 16);
Chris Packham883bf452016-11-09 22:07:45 +1300583 } else if (!strcmp(keyword, "BAUDRATE")) {
584 char *value = strtok_r(NULL, deliminiters, &saveptr);
585 el->type = IMAGE_CFG_BAUDRATE;
586 el->baudrate = strtoul(value, NULL, 10);
Chris Packham1e0728a2016-11-09 22:21:45 +1300587 } else if (!strcmp(keyword, "DEBUG")) {
588 char *value = strtok_r(NULL, deliminiters, &saveptr);
589 el->type = IMAGE_CFG_DEBUG;
590 el->debug = strtoul(value, NULL, 10);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200591 } else {
592 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530593 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530594
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200595 return 0;
596}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530597
598/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200599 * Parse the configuration file 'fcfg' into the array of configuration
600 * elements 'image_cfg', and return the number of configuration
601 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530602 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200603static int image_create_config_parse(FILE *fcfg)
604{
605 int ret;
606 int cfgi = 0;
607
608 /* Parse the configuration file */
609 while (!feof(fcfg)) {
610 char *line;
611 char buf[256];
612
613 /* Read the current line */
614 memset(buf, 0, sizeof(buf));
615 line = fgets(buf, sizeof(buf), fcfg);
616 if (!line)
617 break;
618
619 /* Ignore useless lines */
620 if (line[0] == '\n' || line[0] == '#')
621 continue;
622
623 /* Strip final newline */
624 if (line[strlen(line) - 1] == '\n')
625 line[strlen(line) - 1] = 0;
626
627 /* Parse the current line */
628 ret = image_create_config_parse_oneline(line,
629 &image_cfg[cfgi]);
630 if (ret)
631 return ret;
632
633 cfgi++;
634
635 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
636 fprintf(stderr,
637 "Too many configuration elements in .cfg file\n");
638 return -1;
639 }
640 }
641
642 cfgn = cfgi;
643 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530644}
645
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200646static int image_get_version(void)
647{
648 struct image_cfg_element *e;
649
650 e = image_find_option(IMAGE_CFG_VERSION);
651 if (!e)
652 return -1;
653
654 return e->version;
655}
656
657static int image_version_file(const char *input)
658{
659 FILE *fcfg;
660 int version;
661 int ret;
662
663 fcfg = fopen(input, "r");
664 if (!fcfg) {
665 fprintf(stderr, "Could not open input file %s\n", input);
666 return -1;
667 }
668
669 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
670 sizeof(struct image_cfg_element));
671 if (!image_cfg) {
672 fprintf(stderr, "Cannot allocate memory\n");
673 fclose(fcfg);
674 return -1;
675 }
676
677 memset(image_cfg, 0,
678 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
679 rewind(fcfg);
680
681 ret = image_create_config_parse(fcfg);
682 fclose(fcfg);
683 if (ret) {
684 free(image_cfg);
685 return -1;
686 }
687
688 version = image_get_version();
689 /* Fallback to version 0 is no version is provided in the cfg file */
690 if (version == -1)
691 version = 0;
692
693 free(image_cfg);
694
695 return version;
696}
697
698static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700699 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530700{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200701 FILE *fcfg;
702 void *image = NULL;
703 int version;
Łukasz Majewskif04dab42014-11-21 09:22:43 +0100704 size_t headersz = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530705 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200706 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530707 int size;
708
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200709 fcfg = fopen(params->imagename, "r");
710 if (!fcfg) {
711 fprintf(stderr, "Could not open input file %s\n",
712 params->imagename);
713 exit(EXIT_FAILURE);
714 }
715
716 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
717 sizeof(struct image_cfg_element));
718 if (!image_cfg) {
719 fprintf(stderr, "Cannot allocate memory\n");
720 fclose(fcfg);
721 exit(EXIT_FAILURE);
722 }
723
724 memset(image_cfg, 0,
725 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
726 rewind(fcfg);
727
728 ret = image_create_config_parse(fcfg);
729 fclose(fcfg);
730 if (ret) {
731 free(image_cfg);
732 exit(EXIT_FAILURE);
733 }
734
Stefan Roese48676a32015-09-01 13:46:35 +0200735 /* The MVEBU BootROM does not allow non word aligned payloads */
736 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
737
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200738 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100739 switch (version) {
740 /*
741 * Fallback to version 0 if no version is provided in the
742 * cfg file
743 */
744 case -1:
745 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200746 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100747 break;
748
749 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200750 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100751 break;
752
753 default:
754 fprintf(stderr, "Unsupported version %d\n", version);
755 free(image_cfg);
756 exit(EXIT_FAILURE);
757 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530758
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200759 if (!image) {
760 fprintf(stderr, "Could not create image\n");
761 free(image_cfg);
762 exit(EXIT_FAILURE);
763 }
764
765 free(image_cfg);
766
767 /* Build and add image checksum header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100768 checksum =
769 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200770 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530771 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200772 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530773 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200774 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530775 }
776
777 sbuf->st_size += sizeof(uint32_t);
778
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200779 /* Finally copy the header into the image area */
780 memcpy(ptr, image, headersz);
781
782 free(image);
783}
784
785static void kwbimage_print_header(const void *ptr)
786{
787 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
788
789 printf("Image Type: MVEBU Boot from %s Image\n",
790 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200791 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100792 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200793 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
794 printf("Load Address: %08x\n", mhdr->destaddr);
795 printf("Entry Point: %08x\n", mhdr->execaddr);
796}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530797
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200798static int kwbimage_check_image_types(uint8_t type)
799{
800 if (type == IH_TYPE_KWBIMAGE)
801 return EXIT_SUCCESS;
802 else
803 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530804}
805
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200806static int kwbimage_verify_header(unsigned char *ptr, int image_size,
807 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530808{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200809 struct main_hdr_v0 *main_hdr;
810 struct ext_hdr_v0 *ext_hdr;
811 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530812
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200813 main_hdr = (void *)ptr;
814 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100815 sizeof(struct main_hdr_v0)
816 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200817 if (checksum != main_hdr->checksum)
818 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530819
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200820 /* Only version 0 extended header has checksum */
821 if (image_version((void *)ptr) == 0) {
822 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
823 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100824 sizeof(struct ext_hdr_v0)
825 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200826 if (checksum != ext_hdr->checksum)
827 return -FDT_ERR_BADSTRUCTURE;
828 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530829
830 return 0;
831}
832
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200833static int kwbimage_generate(struct image_tool_params *params,
834 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530835{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200836 int alloc_len;
837 void *hdr;
838 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530839
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200840 version = image_version_file(params->imagename);
841 if (version == 0) {
842 alloc_len = sizeof(struct main_hdr_v0) +
843 sizeof(struct ext_hdr_v0);
844 } else {
845 alloc_len = image_headersz_v1(params, NULL);
846 }
847
848 hdr = malloc(alloc_len);
849 if (!hdr) {
850 fprintf(stderr, "%s: malloc return failure: %s\n",
851 params->cmdname, strerror(errno));
852 exit(EXIT_FAILURE);
853 }
854
855 memset(hdr, 0, alloc_len);
856 tparams->header_size = alloc_len;
857 tparams->hdr = hdr;
858
Stefan Roeseda43fd32015-11-24 09:14:59 +0100859 /*
860 * The resulting image needs to be 4-byte aligned. At least
861 * the Marvell hdrparser tool complains if its unaligned.
862 * By returning 1 here in this function, called via
863 * tparams->vrec_header() in mkimage.c, mkimage will
864 * automatically pad the the resulting image to a 4-byte
865 * size if necessary.
866 */
867 return 1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530868}
869
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200870/*
871 * Report Error if xflag is set in addition to default
872 */
873static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530874{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200875 if (!strlen(params->imagename)) {
876 fprintf(stderr, "Error:%s - Configuration file not specified, "
877 "it is needed for kwbimage generation\n",
878 params->cmdname);
879 return CFG_INVALID;
880 }
881
882 return (params->dflag && (params->fflag || params->lflag)) ||
883 (params->fflag && (params->dflag || params->lflag)) ||
884 (params->lflag && (params->dflag || params->fflag)) ||
885 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530886}
887
888/*
889 * kwbimage type parameters definition
890 */
Guilherme Maciel Ferreira28be1cf2015-01-15 02:48:07 -0200891U_BOOT_IMAGE_TYPE(
892 kwbimage,
893 "Marvell MVEBU Boot Image support",
894 0,
895 NULL,
896 kwbimage_check_params,
897 kwbimage_verify_header,
898 kwbimage_print_header,
899 kwbimage_set_header,
900 NULL,
901 kwbimage_check_image_types,
902 NULL,
903 kwbimage_generate
904);