blob: 87587f85c5becc8018a9f6fb37e4f51bb9cf09cb [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;
Mario Sixd6009d72017-01-11 16:00:54 +0100106
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200107 for (i = 0; boot_modes[i].name; i++)
108 if (boot_modes[i].id == id)
109 return boot_modes[i].name;
110 return NULL;
111}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530112
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200113int image_boot_mode_id(const char *boot_mode_name)
114{
115 int i;
Mario Sixd6009d72017-01-11 16:00:54 +0100116
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200117 for (i = 0; boot_modes[i].name; i++)
118 if (!strcmp(boot_modes[i].name, boot_mode_name))
119 return boot_modes[i].id;
120
121 return -1;
122}
123
124int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
125{
126 int i;
Mario Sixd6009d72017-01-11 16:00:54 +0100127
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200128 for (i = 0; nand_ecc_modes[i].name; i++)
129 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
130 return nand_ecc_modes[i].id;
131 return -1;
132}
133
134static struct image_cfg_element *
135image_find_option(unsigned int optiontype)
136{
137 int i;
138
139 for (i = 0; i < cfgn; i++) {
140 if (image_cfg[i].type == optiontype)
141 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530142 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200143
144 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530145}
146
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200147static unsigned int
148image_count_options(unsigned int optiontype)
149{
150 int i;
151 unsigned int count = 0;
152
153 for (i = 0; i < cfgn; i++)
154 if (image_cfg[i].type == optiontype)
155 count++;
156
157 return count;
158}
159
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530160/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200161 * Compute a 8-bit checksum of a memory area. This algorithm follows
162 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530163 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200164static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530165{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200166 uint8_t csum = 0;
167 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530168
169 /* check len and return zero checksum if invalid */
170 if (!len)
171 return 0;
172
173 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200174 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530175 p++;
176 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200177
178 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530179}
180
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200181static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530182{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200183 uint32_t csum = 0;
184 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530185
186 /* check len and return zero checksum if invalid */
187 if (!len)
188 return 0;
189
190 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200191 fprintf(stderr, "Length %d is not in multiple of %zu\n",
192 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530193 return 0;
194 }
195
196 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200197 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530198 p++;
199 len -= sizeof(uint32_t);
200 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200201
202 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530203}
204
Chris Packham883bf452016-11-09 22:07:45 +1300205static uint8_t baudrate_to_option(unsigned int baudrate)
206{
207 switch (baudrate) {
208 case 2400:
209 return MAIN_HDR_V1_OPT_BAUD_2400;
210 case 4800:
211 return MAIN_HDR_V1_OPT_BAUD_4800;
212 case 9600:
213 return MAIN_HDR_V1_OPT_BAUD_9600;
214 case 19200:
215 return MAIN_HDR_V1_OPT_BAUD_19200;
216 case 38400:
217 return MAIN_HDR_V1_OPT_BAUD_38400;
218 case 57600:
219 return MAIN_HDR_V1_OPT_BAUD_57600;
220 case 115200:
221 return MAIN_HDR_V1_OPT_BAUD_115200;
222 default:
223 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
224 }
225}
226
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200227static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
228 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530229{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200230 struct image_cfg_element *e;
231 size_t headersz;
232 struct main_hdr_v0 *main_hdr;
Mario Six7497cd62017-01-11 16:00:55 +0100233 uint8_t *image;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200234 int has_ext = 0;
235
236 /*
237 * Calculate the size of the header and the size of the
238 * payload
239 */
240 headersz = sizeof(struct main_hdr_v0);
241
242 if (image_count_options(IMAGE_CFG_DATA) > 0) {
243 has_ext = 1;
244 headersz += sizeof(struct ext_hdr_v0);
245 }
246
247 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
248 fprintf(stderr, "More than one payload, not possible\n");
249 return NULL;
250 }
251
252 image = malloc(headersz);
253 if (!image) {
254 fprintf(stderr, "Cannot allocate memory for image\n");
255 return NULL;
256 }
257
258 memset(image, 0, headersz);
259
Mario Six7497cd62017-01-11 16:00:55 +0100260 main_hdr = (struct main_hdr_v0 *)image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530261
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200262 /* Fill in the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100263 main_hdr->blocksize =
264 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
265 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200266 main_hdr->ext = has_ext;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100267 main_hdr->destaddr = cpu_to_le32(params->addr);
268 main_hdr->execaddr = cpu_to_le32(params->ep);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530269
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200270 e = image_find_option(IMAGE_CFG_BOOT_FROM);
271 if (e)
272 main_hdr->blockid = e->bootfrom;
273 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
274 if (e)
275 main_hdr->nandeccmode = e->nandeccmode;
276 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
277 if (e)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100278 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200279 main_hdr->checksum = image_checksum8(image,
280 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530281
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200282 /* Generate the ext header */
283 if (has_ext) {
Mario Six6f273632017-01-11 16:00:56 +0100284 struct ext_hdr_v0 *ext_hdr;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200285 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530286
Mario Six7497cd62017-01-11 16:00:55 +0100287 ext_hdr = (struct ext_hdr_v0 *)
288 (image + sizeof(struct main_hdr_v0));
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100289 ext_hdr->offset = cpu_to_le32(0x40);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530290
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200291 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
292 e = &image_cfg[cfgi];
293 if (e->type != IMAGE_CFG_DATA)
294 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530295
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100296 ext_hdr->rcfg[datai].raddr =
297 cpu_to_le32(e->regdata.raddr);
298 ext_hdr->rcfg[datai].rdata =
299 cpu_to_le32(e->regdata.rdata);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200300 datai++;
301 }
302
303 ext_hdr->checksum = image_checksum8(ext_hdr,
304 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530305 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530306
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200307 *imagesz = headersz;
308 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530309}
310
Mario Six855cf9e2017-01-11 16:00:57 +0100311static size_t image_headersz_v1(int *hasext)
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200312{
313 struct image_cfg_element *binarye;
314 size_t headersz;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530315
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200316 /*
317 * Calculate the size of the header and the size of the
318 * payload
319 */
320 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530321
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200322 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
323 fprintf(stderr, "More than one binary blob, not supported\n");
324 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530325 }
326
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200327 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
328 fprintf(stderr, "More than one payload, not possible\n");
329 return 0;
330 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530331
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200332 binarye = image_find_option(IMAGE_CFG_BINARY);
333 if (binarye) {
Mario Six6f273632017-01-11 16:00:56 +0100334 int ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200335 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530336
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200337 ret = stat(binarye->binary.file, &s);
338 if (ret < 0) {
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200339 char cwd[PATH_MAX];
340 char *dir = cwd;
341
342 memset(cwd, 0, sizeof(cwd));
343 if (!getcwd(cwd, sizeof(cwd))) {
344 dir = "current working directory";
345 perror("getcwd() failed");
346 }
347
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200348 fprintf(stderr,
349 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
350 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
351 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200352 binarye->binary.file, dir);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200353 return 0;
354 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530355
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100356 headersz += sizeof(struct opt_hdr_v1) +
357 s.st_size +
358 (binarye->binary.nargs + 2) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200359 if (hasext)
360 *hasext = 1;
361 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530362
Stefan Roese69e9dde2015-07-20 11:20:38 +0200363#if defined(CONFIG_SYS_U_BOOT_OFFS)
364 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Mario Sixd6009d72017-01-11 16:00:54 +0100365 fprintf(stderr,
366 "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese69e9dde2015-07-20 11:20:38 +0200367 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
368 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
369 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smith88809492015-03-16 14:58:21 +0000370 return 0;
Kevin Smith88809492015-03-16 14:58:21 +0000371 }
Mario Sixd6009d72017-01-11 16:00:54 +0100372 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smith88809492015-03-16 14:58:21 +0000373#endif
374
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200375 /*
376 * The payload should be aligned on some reasonable
377 * boundary
378 */
379 return ALIGN_SUP(headersz, 4096);
380}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530381
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200382static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
383 int payloadsz)
384{
385 struct image_cfg_element *e, *binarye;
386 struct main_hdr_v1 *main_hdr;
387 size_t headersz;
Mario Six7497cd62017-01-11 16:00:55 +0100388 uint8_t *image, *cur;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200389 int hasext = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530390
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200391 /*
392 * Calculate the size of the header and the size of the
393 * payload
394 */
Mario Six855cf9e2017-01-11 16:00:57 +0100395 headersz = image_headersz_v1(&hasext);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200396 if (headersz == 0)
397 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530398
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200399 image = malloc(headersz);
400 if (!image) {
401 fprintf(stderr, "Cannot allocate memory for image\n");
402 return NULL;
403 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530404
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200405 memset(image, 0, headersz);
406
Mario Six7497cd62017-01-11 16:00:55 +0100407 main_hdr = (struct main_hdr_v1 *)image;
408 cur = image + sizeof(struct main_hdr_v1);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200409
410 /* Fill the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100411 main_hdr->blocksize =
412 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
413 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200414 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
Mario Six7e407632017-01-11 16:00:53 +0100415 main_hdr->destaddr = cpu_to_le32(params->addr)
416 - sizeof(image_header_t);
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100417 main_hdr->execaddr = cpu_to_le32(params->ep);
418 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200419 main_hdr->ext = hasext;
420 main_hdr->version = 1;
421 e = image_find_option(IMAGE_CFG_BOOT_FROM);
422 if (e)
423 main_hdr->blockid = e->bootfrom;
424 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
425 if (e)
426 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
427 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
428 if (e)
429 main_hdr->nandbadblklocation = e->nandbadblklocation;
Chris Packham883bf452016-11-09 22:07:45 +1300430 e = image_find_option(IMAGE_CFG_BAUDRATE);
431 if (e)
432 main_hdr->options = baudrate_to_option(e->baudrate);
Chris Packham1e0728a2016-11-09 22:21:45 +1300433 e = image_find_option(IMAGE_CFG_DEBUG);
434 if (e)
435 main_hdr->flags = e->debug ? 0x1 : 0;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200436
437 binarye = image_find_option(IMAGE_CFG_BINARY);
438 if (binarye) {
Mario Six7497cd62017-01-11 16:00:55 +0100439 struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100440 uint32_t *args;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200441 size_t binhdrsz;
442 struct stat s;
443 int argi;
444 FILE *bin;
Mario Six6f273632017-01-11 16:00:56 +0100445 int ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200446
447 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
448
449 bin = fopen(binarye->binary.file, "r");
450 if (!bin) {
451 fprintf(stderr, "Cannot open binary file %s\n",
452 binarye->binary.file);
453 return NULL;
454 }
455
456 fstat(fileno(bin), &s);
457
458 binhdrsz = sizeof(struct opt_hdr_v1) +
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100459 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200460 s.st_size;
Stefan Roesea4279a52015-10-28 07:53:58 +0100461
462 /*
463 * The size includes the binary image size, rounded
464 * up to a 4-byte boundary. Plus 4 bytes for the
465 * next-header byte and 3-byte alignment at the end.
466 */
467 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100468 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200469 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
470
471 cur += sizeof(struct opt_hdr_v1);
472
Mario Six7497cd62017-01-11 16:00:55 +0100473 args = (uint32_t *)cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100474 *args = cpu_to_le32(binarye->binary.nargs);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200475 args++;
476 for (argi = 0; argi < binarye->binary.nargs; argi++)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100477 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200478
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100479 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200480
481 ret = fread(cur, s.st_size, 1, bin);
482 if (ret != 1) {
483 fprintf(stderr,
484 "Could not read binary image %s\n",
485 binarye->binary.file);
486 return NULL;
487 }
488
489 fclose(bin);
490
Stefan Roesea4279a52015-10-28 07:53:58 +0100491 cur += ALIGN_SUP(s.st_size, 4);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200492
493 /*
494 * For now, we don't support more than one binary
495 * header, and no other header types are
496 * supported. So, the binary header is necessarily the
497 * last one
498 */
Stefan Roesea4279a52015-10-28 07:53:58 +0100499 *((uint32_t *)cur) = 0x00000000;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200500
501 cur += sizeof(uint32_t);
502 }
503
504 /* Calculate and set the header checksum */
505 main_hdr->checksum = image_checksum8(main_hdr, headersz);
506
507 *imagesz = headersz;
508 return image;
509}
510
511static int image_create_config_parse_oneline(char *line,
512 struct image_cfg_element *el)
513{
514 char *keyword, *saveptr;
515 char deliminiters[] = " \t";
516
517 keyword = strtok_r(line, deliminiters, &saveptr);
518 if (!strcmp(keyword, "VERSION")) {
519 char *value = strtok_r(NULL, deliminiters, &saveptr);
Mario Sixd6009d72017-01-11 16:00:54 +0100520
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200521 el->type = IMAGE_CFG_VERSION;
522 el->version = atoi(value);
523 } else if (!strcmp(keyword, "BOOT_FROM")) {
524 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200525 int ret = image_boot_mode_id(value);
Mario Sixd6009d72017-01-11 16:00:54 +0100526
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200527 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200528 fprintf(stderr,
529 "Invalid boot media '%s'\n", value);
530 return -1;
531 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200532 el->type = IMAGE_CFG_BOOT_FROM;
533 el->bootfrom = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200534 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
535 char *value = strtok_r(NULL, deliminiters, &saveptr);
Mario Sixd6009d72017-01-11 16:00:54 +0100536
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200537 el->type = IMAGE_CFG_NAND_BLKSZ;
538 el->nandblksz = strtoul(value, NULL, 16);
539 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
540 char *value = strtok_r(NULL, deliminiters, &saveptr);
Mario Sixd6009d72017-01-11 16:00:54 +0100541
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200542 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
543 el->nandbadblklocation =
544 strtoul(value, NULL, 16);
545 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
546 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200547 int ret = image_nand_ecc_mode_id(value);
Mario Sixd6009d72017-01-11 16:00:54 +0100548
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200549 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200550 fprintf(stderr,
551 "Invalid NAND ECC mode '%s'\n", value);
552 return -1;
553 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200554 el->type = IMAGE_CFG_NAND_ECC_MODE;
555 el->nandeccmode = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200556 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
557 char *value = strtok_r(NULL, deliminiters, &saveptr);
Mario Sixd6009d72017-01-11 16:00:54 +0100558
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200559 el->type = IMAGE_CFG_NAND_PAGESZ;
560 el->nandpagesz = strtoul(value, NULL, 16);
561 } else if (!strcmp(keyword, "BINARY")) {
562 char *value = strtok_r(NULL, deliminiters, &saveptr);
563 int argi = 0;
564
565 el->type = IMAGE_CFG_BINARY;
566 el->binary.file = strdup(value);
567 while (1) {
568 value = strtok_r(NULL, deliminiters, &saveptr);
569 if (!value)
570 break;
571 el->binary.args[argi] = strtoul(value, NULL, 16);
572 argi++;
573 if (argi >= BINARY_MAX_ARGS) {
574 fprintf(stderr,
575 "Too many argument for binary\n");
576 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530577 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530578 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200579 el->binary.nargs = argi;
580 } else if (!strcmp(keyword, "DATA")) {
581 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
582 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
583
584 if (!value1 || !value2) {
585 fprintf(stderr,
586 "Invalid number of arguments for DATA\n");
587 return -1;
588 }
589
590 el->type = IMAGE_CFG_DATA;
591 el->regdata.raddr = strtoul(value1, NULL, 16);
592 el->regdata.rdata = strtoul(value2, NULL, 16);
Chris Packham883bf452016-11-09 22:07:45 +1300593 } else if (!strcmp(keyword, "BAUDRATE")) {
594 char *value = strtok_r(NULL, deliminiters, &saveptr);
595 el->type = IMAGE_CFG_BAUDRATE;
596 el->baudrate = strtoul(value, NULL, 10);
Chris Packham1e0728a2016-11-09 22:21:45 +1300597 } else if (!strcmp(keyword, "DEBUG")) {
598 char *value = strtok_r(NULL, deliminiters, &saveptr);
599 el->type = IMAGE_CFG_DEBUG;
600 el->debug = strtoul(value, NULL, 10);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200601 } else {
602 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530603 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530604
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200605 return 0;
606}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530607
608/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200609 * Parse the configuration file 'fcfg' into the array of configuration
610 * elements 'image_cfg', and return the number of configuration
611 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530612 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200613static int image_create_config_parse(FILE *fcfg)
614{
615 int ret;
616 int cfgi = 0;
617
618 /* Parse the configuration file */
619 while (!feof(fcfg)) {
620 char *line;
621 char buf[256];
622
623 /* Read the current line */
624 memset(buf, 0, sizeof(buf));
625 line = fgets(buf, sizeof(buf), fcfg);
626 if (!line)
627 break;
628
629 /* Ignore useless lines */
630 if (line[0] == '\n' || line[0] == '#')
631 continue;
632
633 /* Strip final newline */
634 if (line[strlen(line) - 1] == '\n')
635 line[strlen(line) - 1] = 0;
636
637 /* Parse the current line */
638 ret = image_create_config_parse_oneline(line,
639 &image_cfg[cfgi]);
640 if (ret)
641 return ret;
642
643 cfgi++;
644
645 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
646 fprintf(stderr,
647 "Too many configuration elements in .cfg file\n");
648 return -1;
649 }
650 }
651
652 cfgn = cfgi;
653 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530654}
655
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200656static int image_get_version(void)
657{
658 struct image_cfg_element *e;
659
660 e = image_find_option(IMAGE_CFG_VERSION);
661 if (!e)
662 return -1;
663
664 return e->version;
665}
666
667static int image_version_file(const char *input)
668{
669 FILE *fcfg;
670 int version;
671 int ret;
672
673 fcfg = fopen(input, "r");
674 if (!fcfg) {
675 fprintf(stderr, "Could not open input file %s\n", input);
676 return -1;
677 }
678
679 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
680 sizeof(struct image_cfg_element));
681 if (!image_cfg) {
682 fprintf(stderr, "Cannot allocate memory\n");
683 fclose(fcfg);
684 return -1;
685 }
686
687 memset(image_cfg, 0,
688 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
689 rewind(fcfg);
690
691 ret = image_create_config_parse(fcfg);
692 fclose(fcfg);
693 if (ret) {
694 free(image_cfg);
695 return -1;
696 }
697
698 version = image_get_version();
699 /* Fallback to version 0 is no version is provided in the cfg file */
700 if (version == -1)
701 version = 0;
702
703 free(image_cfg);
704
705 return version;
706}
707
708static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700709 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530710{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200711 FILE *fcfg;
712 void *image = NULL;
713 int version;
Łukasz Majewskif04dab42014-11-21 09:22:43 +0100714 size_t headersz = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530715 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200716 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530717 int size;
718
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200719 fcfg = fopen(params->imagename, "r");
720 if (!fcfg) {
721 fprintf(stderr, "Could not open input file %s\n",
722 params->imagename);
723 exit(EXIT_FAILURE);
724 }
725
726 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
727 sizeof(struct image_cfg_element));
728 if (!image_cfg) {
729 fprintf(stderr, "Cannot allocate memory\n");
730 fclose(fcfg);
731 exit(EXIT_FAILURE);
732 }
733
734 memset(image_cfg, 0,
735 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
736 rewind(fcfg);
737
738 ret = image_create_config_parse(fcfg);
739 fclose(fcfg);
740 if (ret) {
741 free(image_cfg);
742 exit(EXIT_FAILURE);
743 }
744
Stefan Roese48676a32015-09-01 13:46:35 +0200745 /* The MVEBU BootROM does not allow non word aligned payloads */
746 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
747
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200748 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100749 switch (version) {
750 /*
751 * Fallback to version 0 if no version is provided in the
752 * cfg file
753 */
754 case -1:
755 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200756 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100757 break;
758
759 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200760 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100761 break;
762
763 default:
764 fprintf(stderr, "Unsupported version %d\n", version);
765 free(image_cfg);
766 exit(EXIT_FAILURE);
767 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530768
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200769 if (!image) {
770 fprintf(stderr, "Could not create image\n");
771 free(image_cfg);
772 exit(EXIT_FAILURE);
773 }
774
775 free(image_cfg);
776
777 /* Build and add image checksum header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100778 checksum =
779 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200780 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530781 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200782 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530783 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200784 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530785 }
786
787 sbuf->st_size += sizeof(uint32_t);
788
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200789 /* Finally copy the header into the image area */
790 memcpy(ptr, image, headersz);
791
792 free(image);
793}
794
795static void kwbimage_print_header(const void *ptr)
796{
797 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
798
799 printf("Image Type: MVEBU Boot from %s Image\n",
800 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200801 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100802 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200803 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
804 printf("Load Address: %08x\n", mhdr->destaddr);
805 printf("Entry Point: %08x\n", mhdr->execaddr);
806}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530807
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200808static int kwbimage_check_image_types(uint8_t type)
809{
810 if (type == IH_TYPE_KWBIMAGE)
811 return EXIT_SUCCESS;
Mario Sixd6009d72017-01-11 16:00:54 +0100812
813 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530814}
815
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200816static int kwbimage_verify_header(unsigned char *ptr, int image_size,
817 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530818{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200819 struct main_hdr_v0 *main_hdr;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200820 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530821
Mario Six7497cd62017-01-11 16:00:55 +0100822 main_hdr = (struct main_hdr_v0 *)ptr;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200823 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100824 sizeof(struct main_hdr_v0)
825 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200826 if (checksum != main_hdr->checksum)
827 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530828
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200829 /* Only version 0 extended header has checksum */
830 if (image_version((void *)ptr) == 0) {
Mario Six6f273632017-01-11 16:00:56 +0100831 struct ext_hdr_v0 *ext_hdr;
832
Mario Six7497cd62017-01-11 16:00:55 +0100833 ext_hdr = (struct ext_hdr_v0 *)
834 (ptr + sizeof(struct main_hdr_v0));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200835 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100836 sizeof(struct ext_hdr_v0)
837 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200838 if (checksum != ext_hdr->checksum)
839 return -FDT_ERR_BADSTRUCTURE;
840 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530841
842 return 0;
843}
844
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200845static int kwbimage_generate(struct image_tool_params *params,
846 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530847{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200848 int alloc_len;
849 void *hdr;
850 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530851
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200852 version = image_version_file(params->imagename);
853 if (version == 0) {
854 alloc_len = sizeof(struct main_hdr_v0) +
855 sizeof(struct ext_hdr_v0);
856 } else {
Mario Six855cf9e2017-01-11 16:00:57 +0100857 alloc_len = image_headersz_v1(NULL);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200858 }
859
860 hdr = malloc(alloc_len);
861 if (!hdr) {
862 fprintf(stderr, "%s: malloc return failure: %s\n",
863 params->cmdname, strerror(errno));
864 exit(EXIT_FAILURE);
865 }
866
867 memset(hdr, 0, alloc_len);
868 tparams->header_size = alloc_len;
869 tparams->hdr = hdr;
870
Stefan Roeseda43fd32015-11-24 09:14:59 +0100871 /*
872 * The resulting image needs to be 4-byte aligned. At least
873 * the Marvell hdrparser tool complains if its unaligned.
874 * By returning 1 here in this function, called via
875 * tparams->vrec_header() in mkimage.c, mkimage will
876 * automatically pad the the resulting image to a 4-byte
877 * size if necessary.
878 */
879 return 1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530880}
881
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200882/*
883 * Report Error if xflag is set in addition to default
884 */
885static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530886{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200887 if (!strlen(params->imagename)) {
Mario Sixd6009d72017-01-11 16:00:54 +0100888 char *msg = "Configuration file for kwbimage creation omitted";
889
890 fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200891 return CFG_INVALID;
892 }
893
894 return (params->dflag && (params->fflag || params->lflag)) ||
895 (params->fflag && (params->dflag || params->lflag)) ||
896 (params->lflag && (params->dflag || params->fflag)) ||
897 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530898}
899
900/*
901 * kwbimage type parameters definition
902 */
Guilherme Maciel Ferreira28be1cf2015-01-15 02:48:07 -0200903U_BOOT_IMAGE_TYPE(
904 kwbimage,
905 "Marvell MVEBU Boot Image support",
906 0,
907 NULL,
908 kwbimage_check_params,
909 kwbimage_verify_header,
910 kwbimage_print_header,
911 kwbimage_set_header,
912 NULL,
913 kwbimage_check_image_types,
914 NULL,
915 kwbimage_generate
916);