blob: ad182c5c5d9af5f57cfbf42d129162dd47fce18e [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,
Stefan Roese3b8b19d2014-10-22 12:13:23 +020072 } type;
73 union {
74 unsigned int version;
75 unsigned int bootfrom;
76 struct {
77 const char *file;
78 unsigned int args[BINARY_MAX_ARGS];
79 unsigned int nargs;
80 } binary;
81 const char *payload;
82 unsigned int dstaddr;
83 unsigned int execaddr;
84 unsigned int nandblksz;
85 unsigned int nandbadblklocation;
86 unsigned int nandeccmode;
87 unsigned int nandpagesz;
88 struct ext_hdr_v0_reg regdata;
Chris Packham883bf452016-11-09 22:07:45 +130089 unsigned int baudrate;
Stefan Roese3b8b19d2014-10-22 12:13:23 +020090 };
91};
92
93#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskar07329412009-09-07 15:05:02 +053094
95/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020096 * Utility functions to manipulate boot mode and ecc modes (convert
97 * them back and forth between description strings and the
98 * corresponding numerical identifiers).
99 */
100
101static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530102{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200103 int i;
104 for (i = 0; boot_modes[i].name; i++)
105 if (boot_modes[i].id == id)
106 return boot_modes[i].name;
107 return NULL;
108}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530109
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200110int image_boot_mode_id(const char *boot_mode_name)
111{
112 int i;
113 for (i = 0; boot_modes[i].name; i++)
114 if (!strcmp(boot_modes[i].name, boot_mode_name))
115 return boot_modes[i].id;
116
117 return -1;
118}
119
120int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
121{
122 int i;
123 for (i = 0; nand_ecc_modes[i].name; i++)
124 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
125 return nand_ecc_modes[i].id;
126 return -1;
127}
128
129static struct image_cfg_element *
130image_find_option(unsigned int optiontype)
131{
132 int i;
133
134 for (i = 0; i < cfgn; i++) {
135 if (image_cfg[i].type == optiontype)
136 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530137 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200138
139 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530140}
141
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200142static unsigned int
143image_count_options(unsigned int optiontype)
144{
145 int i;
146 unsigned int count = 0;
147
148 for (i = 0; i < cfgn; i++)
149 if (image_cfg[i].type == optiontype)
150 count++;
151
152 return count;
153}
154
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530155/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200156 * Compute a 8-bit checksum of a memory area. This algorithm follows
157 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530158 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200159static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530160{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200161 uint8_t csum = 0;
162 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530163
164 /* check len and return zero checksum if invalid */
165 if (!len)
166 return 0;
167
168 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200169 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530170 p++;
171 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200172
173 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530174}
175
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200176static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530177{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200178 uint32_t csum = 0;
179 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530180
181 /* check len and return zero checksum if invalid */
182 if (!len)
183 return 0;
184
185 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200186 fprintf(stderr, "Length %d is not in multiple of %zu\n",
187 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530188 return 0;
189 }
190
191 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200192 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530193 p++;
194 len -= sizeof(uint32_t);
195 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200196
197 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530198}
199
Chris Packham883bf452016-11-09 22:07:45 +1300200static uint8_t baudrate_to_option(unsigned int baudrate)
201{
202 switch (baudrate) {
203 case 2400:
204 return MAIN_HDR_V1_OPT_BAUD_2400;
205 case 4800:
206 return MAIN_HDR_V1_OPT_BAUD_4800;
207 case 9600:
208 return MAIN_HDR_V1_OPT_BAUD_9600;
209 case 19200:
210 return MAIN_HDR_V1_OPT_BAUD_19200;
211 case 38400:
212 return MAIN_HDR_V1_OPT_BAUD_38400;
213 case 57600:
214 return MAIN_HDR_V1_OPT_BAUD_57600;
215 case 115200:
216 return MAIN_HDR_V1_OPT_BAUD_115200;
217 default:
218 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
219 }
220}
221
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200222static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
223 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530224{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200225 struct image_cfg_element *e;
226 size_t headersz;
227 struct main_hdr_v0 *main_hdr;
228 struct ext_hdr_v0 *ext_hdr;
229 void *image;
230 int has_ext = 0;
231
232 /*
233 * Calculate the size of the header and the size of the
234 * payload
235 */
236 headersz = sizeof(struct main_hdr_v0);
237
238 if (image_count_options(IMAGE_CFG_DATA) > 0) {
239 has_ext = 1;
240 headersz += sizeof(struct ext_hdr_v0);
241 }
242
243 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
244 fprintf(stderr, "More than one payload, not possible\n");
245 return NULL;
246 }
247
248 image = malloc(headersz);
249 if (!image) {
250 fprintf(stderr, "Cannot allocate memory for image\n");
251 return NULL;
252 }
253
254 memset(image, 0, headersz);
255
256 main_hdr = image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530257
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200258 /* Fill in the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100259 main_hdr->blocksize =
260 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
261 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200262 main_hdr->ext = has_ext;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100263 main_hdr->destaddr = cpu_to_le32(params->addr);
264 main_hdr->execaddr = cpu_to_le32(params->ep);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530265
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200266 e = image_find_option(IMAGE_CFG_BOOT_FROM);
267 if (e)
268 main_hdr->blockid = e->bootfrom;
269 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
270 if (e)
271 main_hdr->nandeccmode = e->nandeccmode;
272 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
273 if (e)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100274 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200275 main_hdr->checksum = image_checksum8(image,
276 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530277
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200278 /* Generate the ext header */
279 if (has_ext) {
280 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530281
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200282 ext_hdr = image + sizeof(struct main_hdr_v0);
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100283 ext_hdr->offset = cpu_to_le32(0x40);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530284
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200285 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
286 e = &image_cfg[cfgi];
287 if (e->type != IMAGE_CFG_DATA)
288 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530289
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100290 ext_hdr->rcfg[datai].raddr =
291 cpu_to_le32(e->regdata.raddr);
292 ext_hdr->rcfg[datai].rdata =
293 cpu_to_le32(e->regdata.rdata);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200294 datai++;
295 }
296
297 ext_hdr->checksum = image_checksum8(ext_hdr,
298 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530299 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530300
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200301 *imagesz = headersz;
302 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530303}
304
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200305static size_t image_headersz_v1(struct image_tool_params *params,
306 int *hasext)
307{
308 struct image_cfg_element *binarye;
309 size_t headersz;
310 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530311
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200312 /*
313 * Calculate the size of the header and the size of the
314 * payload
315 */
316 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530317
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200318 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
319 fprintf(stderr, "More than one binary blob, not supported\n");
320 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530321 }
322
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200323 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
324 fprintf(stderr, "More than one payload, not possible\n");
325 return 0;
326 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530327
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200328 binarye = image_find_option(IMAGE_CFG_BINARY);
329 if (binarye) {
330 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530331
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200332 ret = stat(binarye->binary.file, &s);
333 if (ret < 0) {
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200334 char cwd[PATH_MAX];
335 char *dir = cwd;
336
337 memset(cwd, 0, sizeof(cwd));
338 if (!getcwd(cwd, sizeof(cwd))) {
339 dir = "current working directory";
340 perror("getcwd() failed");
341 }
342
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200343 fprintf(stderr,
344 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
345 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
346 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200347 binarye->binary.file, dir);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200348 return 0;
349 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530350
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100351 headersz += sizeof(struct opt_hdr_v1) +
352 s.st_size +
353 (binarye->binary.nargs + 2) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200354 if (hasext)
355 *hasext = 1;
356 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530357
Stefan Roese69e9dde2015-07-20 11:20:38 +0200358#if defined(CONFIG_SYS_U_BOOT_OFFS)
359 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Kevin Smith88809492015-03-16 14:58:21 +0000360 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese69e9dde2015-07-20 11:20:38 +0200361 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
362 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
363 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smith88809492015-03-16 14:58:21 +0000364 return 0;
365 } else {
Stefan Roese69e9dde2015-07-20 11:20:38 +0200366 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smith88809492015-03-16 14:58:21 +0000367 }
368#endif
369
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200370 /*
371 * The payload should be aligned on some reasonable
372 * boundary
373 */
374 return ALIGN_SUP(headersz, 4096);
375}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530376
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200377static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
378 int payloadsz)
379{
380 struct image_cfg_element *e, *binarye;
381 struct main_hdr_v1 *main_hdr;
382 size_t headersz;
383 void *image, *cur;
384 int hasext = 0;
385 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530386
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200387 /*
388 * Calculate the size of the header and the size of the
389 * payload
390 */
391 headersz = image_headersz_v1(params, &hasext);
392 if (headersz == 0)
393 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530394
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200395 image = malloc(headersz);
396 if (!image) {
397 fprintf(stderr, "Cannot allocate memory for image\n");
398 return NULL;
399 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530400
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200401 memset(image, 0, headersz);
402
403 cur = main_hdr = image;
404 cur += sizeof(struct main_hdr_v1);
405
406 /* Fill the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100407 main_hdr->blocksize =
408 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
409 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200410 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100411 main_hdr->destaddr = cpu_to_le32(params->addr);
412 main_hdr->execaddr = cpu_to_le32(params->ep);
413 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200414 main_hdr->ext = hasext;
415 main_hdr->version = 1;
416 e = image_find_option(IMAGE_CFG_BOOT_FROM);
417 if (e)
418 main_hdr->blockid = e->bootfrom;
419 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
420 if (e)
421 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
422 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
423 if (e)
424 main_hdr->nandbadblklocation = e->nandbadblklocation;
Chris Packham883bf452016-11-09 22:07:45 +1300425 e = image_find_option(IMAGE_CFG_BAUDRATE);
426 if (e)
427 main_hdr->options = baudrate_to_option(e->baudrate);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200428
429 binarye = image_find_option(IMAGE_CFG_BINARY);
430 if (binarye) {
431 struct opt_hdr_v1 *hdr = cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100432 uint32_t *args;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200433 size_t binhdrsz;
434 struct stat s;
435 int argi;
436 FILE *bin;
437
438 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
439
440 bin = fopen(binarye->binary.file, "r");
441 if (!bin) {
442 fprintf(stderr, "Cannot open binary file %s\n",
443 binarye->binary.file);
444 return NULL;
445 }
446
447 fstat(fileno(bin), &s);
448
449 binhdrsz = sizeof(struct opt_hdr_v1) +
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100450 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200451 s.st_size;
Stefan Roesea4279a52015-10-28 07:53:58 +0100452
453 /*
454 * The size includes the binary image size, rounded
455 * up to a 4-byte boundary. Plus 4 bytes for the
456 * next-header byte and 3-byte alignment at the end.
457 */
458 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100459 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200460 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
461
462 cur += sizeof(struct opt_hdr_v1);
463
464 args = cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100465 *args = cpu_to_le32(binarye->binary.nargs);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200466 args++;
467 for (argi = 0; argi < binarye->binary.nargs; argi++)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100468 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200469
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100470 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200471
472 ret = fread(cur, s.st_size, 1, bin);
473 if (ret != 1) {
474 fprintf(stderr,
475 "Could not read binary image %s\n",
476 binarye->binary.file);
477 return NULL;
478 }
479
480 fclose(bin);
481
Stefan Roesea4279a52015-10-28 07:53:58 +0100482 cur += ALIGN_SUP(s.st_size, 4);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200483
484 /*
485 * For now, we don't support more than one binary
486 * header, and no other header types are
487 * supported. So, the binary header is necessarily the
488 * last one
489 */
Stefan Roesea4279a52015-10-28 07:53:58 +0100490 *((uint32_t *)cur) = 0x00000000;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200491
492 cur += sizeof(uint32_t);
493 }
494
495 /* Calculate and set the header checksum */
496 main_hdr->checksum = image_checksum8(main_hdr, headersz);
497
498 *imagesz = headersz;
499 return image;
500}
501
502static int image_create_config_parse_oneline(char *line,
503 struct image_cfg_element *el)
504{
505 char *keyword, *saveptr;
506 char deliminiters[] = " \t";
507
508 keyword = strtok_r(line, deliminiters, &saveptr);
509 if (!strcmp(keyword, "VERSION")) {
510 char *value = strtok_r(NULL, deliminiters, &saveptr);
511 el->type = IMAGE_CFG_VERSION;
512 el->version = atoi(value);
513 } else if (!strcmp(keyword, "BOOT_FROM")) {
514 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200515 int ret = image_boot_mode_id(value);
516 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200517 fprintf(stderr,
518 "Invalid boot media '%s'\n", value);
519 return -1;
520 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200521 el->type = IMAGE_CFG_BOOT_FROM;
522 el->bootfrom = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200523 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
524 char *value = strtok_r(NULL, deliminiters, &saveptr);
525 el->type = IMAGE_CFG_NAND_BLKSZ;
526 el->nandblksz = strtoul(value, NULL, 16);
527 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
528 char *value = strtok_r(NULL, deliminiters, &saveptr);
529 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
530 el->nandbadblklocation =
531 strtoul(value, NULL, 16);
532 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
533 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200534 int ret = image_nand_ecc_mode_id(value);
535 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200536 fprintf(stderr,
537 "Invalid NAND ECC mode '%s'\n", value);
538 return -1;
539 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200540 el->type = IMAGE_CFG_NAND_ECC_MODE;
541 el->nandeccmode = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200542 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
543 char *value = strtok_r(NULL, deliminiters, &saveptr);
544 el->type = IMAGE_CFG_NAND_PAGESZ;
545 el->nandpagesz = strtoul(value, NULL, 16);
546 } else if (!strcmp(keyword, "BINARY")) {
547 char *value = strtok_r(NULL, deliminiters, &saveptr);
548 int argi = 0;
549
550 el->type = IMAGE_CFG_BINARY;
551 el->binary.file = strdup(value);
552 while (1) {
553 value = strtok_r(NULL, deliminiters, &saveptr);
554 if (!value)
555 break;
556 el->binary.args[argi] = strtoul(value, NULL, 16);
557 argi++;
558 if (argi >= BINARY_MAX_ARGS) {
559 fprintf(stderr,
560 "Too many argument for binary\n");
561 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530562 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530563 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200564 el->binary.nargs = argi;
565 } else if (!strcmp(keyword, "DATA")) {
566 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
567 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
568
569 if (!value1 || !value2) {
570 fprintf(stderr,
571 "Invalid number of arguments for DATA\n");
572 return -1;
573 }
574
575 el->type = IMAGE_CFG_DATA;
576 el->regdata.raddr = strtoul(value1, NULL, 16);
577 el->regdata.rdata = strtoul(value2, NULL, 16);
Chris Packham883bf452016-11-09 22:07:45 +1300578 } else if (!strcmp(keyword, "BAUDRATE")) {
579 char *value = strtok_r(NULL, deliminiters, &saveptr);
580 el->type = IMAGE_CFG_BAUDRATE;
581 el->baudrate = strtoul(value, NULL, 10);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200582 } else {
583 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530584 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530585
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200586 return 0;
587}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530588
589/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200590 * Parse the configuration file 'fcfg' into the array of configuration
591 * elements 'image_cfg', and return the number of configuration
592 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530593 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200594static int image_create_config_parse(FILE *fcfg)
595{
596 int ret;
597 int cfgi = 0;
598
599 /* Parse the configuration file */
600 while (!feof(fcfg)) {
601 char *line;
602 char buf[256];
603
604 /* Read the current line */
605 memset(buf, 0, sizeof(buf));
606 line = fgets(buf, sizeof(buf), fcfg);
607 if (!line)
608 break;
609
610 /* Ignore useless lines */
611 if (line[0] == '\n' || line[0] == '#')
612 continue;
613
614 /* Strip final newline */
615 if (line[strlen(line) - 1] == '\n')
616 line[strlen(line) - 1] = 0;
617
618 /* Parse the current line */
619 ret = image_create_config_parse_oneline(line,
620 &image_cfg[cfgi]);
621 if (ret)
622 return ret;
623
624 cfgi++;
625
626 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
627 fprintf(stderr,
628 "Too many configuration elements in .cfg file\n");
629 return -1;
630 }
631 }
632
633 cfgn = cfgi;
634 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530635}
636
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200637static int image_get_version(void)
638{
639 struct image_cfg_element *e;
640
641 e = image_find_option(IMAGE_CFG_VERSION);
642 if (!e)
643 return -1;
644
645 return e->version;
646}
647
648static int image_version_file(const char *input)
649{
650 FILE *fcfg;
651 int version;
652 int ret;
653
654 fcfg = fopen(input, "r");
655 if (!fcfg) {
656 fprintf(stderr, "Could not open input file %s\n", input);
657 return -1;
658 }
659
660 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
661 sizeof(struct image_cfg_element));
662 if (!image_cfg) {
663 fprintf(stderr, "Cannot allocate memory\n");
664 fclose(fcfg);
665 return -1;
666 }
667
668 memset(image_cfg, 0,
669 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
670 rewind(fcfg);
671
672 ret = image_create_config_parse(fcfg);
673 fclose(fcfg);
674 if (ret) {
675 free(image_cfg);
676 return -1;
677 }
678
679 version = image_get_version();
680 /* Fallback to version 0 is no version is provided in the cfg file */
681 if (version == -1)
682 version = 0;
683
684 free(image_cfg);
685
686 return version;
687}
688
689static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700690 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530691{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200692 FILE *fcfg;
693 void *image = NULL;
694 int version;
Łukasz Majewskif04dab42014-11-21 09:22:43 +0100695 size_t headersz = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530696 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200697 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530698 int size;
699
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200700 fcfg = fopen(params->imagename, "r");
701 if (!fcfg) {
702 fprintf(stderr, "Could not open input file %s\n",
703 params->imagename);
704 exit(EXIT_FAILURE);
705 }
706
707 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
708 sizeof(struct image_cfg_element));
709 if (!image_cfg) {
710 fprintf(stderr, "Cannot allocate memory\n");
711 fclose(fcfg);
712 exit(EXIT_FAILURE);
713 }
714
715 memset(image_cfg, 0,
716 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
717 rewind(fcfg);
718
719 ret = image_create_config_parse(fcfg);
720 fclose(fcfg);
721 if (ret) {
722 free(image_cfg);
723 exit(EXIT_FAILURE);
724 }
725
Stefan Roese48676a32015-09-01 13:46:35 +0200726 /* The MVEBU BootROM does not allow non word aligned payloads */
727 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
728
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200729 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100730 switch (version) {
731 /*
732 * Fallback to version 0 if no version is provided in the
733 * cfg file
734 */
735 case -1:
736 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200737 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100738 break;
739
740 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200741 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100742 break;
743
744 default:
745 fprintf(stderr, "Unsupported version %d\n", version);
746 free(image_cfg);
747 exit(EXIT_FAILURE);
748 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530749
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200750 if (!image) {
751 fprintf(stderr, "Could not create image\n");
752 free(image_cfg);
753 exit(EXIT_FAILURE);
754 }
755
756 free(image_cfg);
757
758 /* Build and add image checksum header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100759 checksum =
760 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200761 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530762 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200763 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530764 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200765 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530766 }
767
768 sbuf->st_size += sizeof(uint32_t);
769
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200770 /* Finally copy the header into the image area */
771 memcpy(ptr, image, headersz);
772
773 free(image);
774}
775
776static void kwbimage_print_header(const void *ptr)
777{
778 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
779
780 printf("Image Type: MVEBU Boot from %s Image\n",
781 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200782 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100783 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200784 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
785 printf("Load Address: %08x\n", mhdr->destaddr);
786 printf("Entry Point: %08x\n", mhdr->execaddr);
787}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530788
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200789static int kwbimage_check_image_types(uint8_t type)
790{
791 if (type == IH_TYPE_KWBIMAGE)
792 return EXIT_SUCCESS;
793 else
794 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530795}
796
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200797static int kwbimage_verify_header(unsigned char *ptr, int image_size,
798 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530799{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200800 struct main_hdr_v0 *main_hdr;
801 struct ext_hdr_v0 *ext_hdr;
802 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530803
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200804 main_hdr = (void *)ptr;
805 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100806 sizeof(struct main_hdr_v0)
807 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200808 if (checksum != main_hdr->checksum)
809 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530810
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200811 /* Only version 0 extended header has checksum */
812 if (image_version((void *)ptr) == 0) {
813 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
814 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100815 sizeof(struct ext_hdr_v0)
816 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200817 if (checksum != ext_hdr->checksum)
818 return -FDT_ERR_BADSTRUCTURE;
819 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530820
821 return 0;
822}
823
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200824static int kwbimage_generate(struct image_tool_params *params,
825 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530826{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200827 int alloc_len;
828 void *hdr;
829 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530830
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200831 version = image_version_file(params->imagename);
832 if (version == 0) {
833 alloc_len = sizeof(struct main_hdr_v0) +
834 sizeof(struct ext_hdr_v0);
835 } else {
836 alloc_len = image_headersz_v1(params, NULL);
837 }
838
839 hdr = malloc(alloc_len);
840 if (!hdr) {
841 fprintf(stderr, "%s: malloc return failure: %s\n",
842 params->cmdname, strerror(errno));
843 exit(EXIT_FAILURE);
844 }
845
846 memset(hdr, 0, alloc_len);
847 tparams->header_size = alloc_len;
848 tparams->hdr = hdr;
849
Stefan Roeseda43fd32015-11-24 09:14:59 +0100850 /*
851 * The resulting image needs to be 4-byte aligned. At least
852 * the Marvell hdrparser tool complains if its unaligned.
853 * By returning 1 here in this function, called via
854 * tparams->vrec_header() in mkimage.c, mkimage will
855 * automatically pad the the resulting image to a 4-byte
856 * size if necessary.
857 */
858 return 1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530859}
860
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200861/*
862 * Report Error if xflag is set in addition to default
863 */
864static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530865{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200866 if (!strlen(params->imagename)) {
867 fprintf(stderr, "Error:%s - Configuration file not specified, "
868 "it is needed for kwbimage generation\n",
869 params->cmdname);
870 return CFG_INVALID;
871 }
872
873 return (params->dflag && (params->fflag || params->lflag)) ||
874 (params->fflag && (params->dflag || params->lflag)) ||
875 (params->lflag && (params->dflag || params->fflag)) ||
876 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530877}
878
879/*
880 * kwbimage type parameters definition
881 */
Guilherme Maciel Ferreira28be1cf2015-01-15 02:48:07 -0200882U_BOOT_IMAGE_TYPE(
883 kwbimage,
884 "Marvell MVEBU Boot Image support",
885 0,
886 NULL,
887 kwbimage_check_params,
888 kwbimage_verify_header,
889 kwbimage_print_header,
890 kwbimage_set_header,
891 NULL,
892 kwbimage_check_image_types,
893 NULL,
894 kwbimage_generate
895);