xref: /openbmc/u-boot/tools/mxsimage.c (revision c5b0bca4c3ca5c3d1d8ee99fdbf3b494a3986dbd)
1bce88370SMarek Vasut /*
2bce88370SMarek Vasut  * Freescale i.MX23/i.MX28 SB image generator
3bce88370SMarek Vasut  *
4bce88370SMarek Vasut  * Copyright (C) 2012-2013 Marek Vasut <marex@denx.de>
5bce88370SMarek Vasut  *
6bce88370SMarek Vasut  * SPDX-License-Identifier:	GPL-2.0+
7bce88370SMarek Vasut  */
8bce88370SMarek Vasut 
9bce88370SMarek Vasut #ifdef CONFIG_MXS
10bce88370SMarek Vasut 
11bce88370SMarek Vasut #include <errno.h>
12bce88370SMarek Vasut #include <fcntl.h>
13bce88370SMarek Vasut #include <stdio.h>
14bce88370SMarek Vasut #include <string.h>
15bce88370SMarek Vasut #include <unistd.h>
16bce88370SMarek Vasut #include <limits.h>
17bce88370SMarek Vasut 
18bce88370SMarek Vasut #include <openssl/evp.h>
19bce88370SMarek Vasut 
20f86ed6a8SGuilherme Maciel Ferreira #include "imagetool.h"
21bce88370SMarek Vasut #include "mxsimage.h"
2225308f45SCharles Manning #include "pbl_crc32.h"
23bce88370SMarek Vasut #include <image.h>
24bce88370SMarek Vasut 
257bae13b7SMarek Vasut /*
267bae13b7SMarek Vasut  * OpenSSL 1.1.0 and newer compatibility functions:
277bae13b7SMarek Vasut  * https://wiki.openssl.org/index.php/1.1_API_Changes
287bae13b7SMarek Vasut  */
29*c5b0bca4SHauke Mehrtens #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
30*c5b0bca4SHauke Mehrtens     (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
317bae13b7SMarek Vasut static void *OPENSSL_zalloc(size_t num)
327bae13b7SMarek Vasut {
337bae13b7SMarek Vasut 	void *ret = OPENSSL_malloc(num);
347bae13b7SMarek Vasut 
357bae13b7SMarek Vasut 	if (ret != NULL)
367bae13b7SMarek Vasut 		memset(ret, 0, num);
377bae13b7SMarek Vasut 	return ret;
387bae13b7SMarek Vasut }
397bae13b7SMarek Vasut 
407bae13b7SMarek Vasut EVP_MD_CTX *EVP_MD_CTX_new(void)
417bae13b7SMarek Vasut {
427bae13b7SMarek Vasut 	return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
437bae13b7SMarek Vasut }
447bae13b7SMarek Vasut 
457bae13b7SMarek Vasut void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
467bae13b7SMarek Vasut {
477bae13b7SMarek Vasut 	EVP_MD_CTX_cleanup(ctx);
487bae13b7SMarek Vasut 	OPENSSL_free(ctx);
497bae13b7SMarek Vasut }
507bae13b7SMarek Vasut 
517bae13b7SMarek Vasut int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx)
527bae13b7SMarek Vasut {
537bae13b7SMarek Vasut 	return EVP_CIPHER_CTX_cleanup(ctx);
547bae13b7SMarek Vasut }
557bae13b7SMarek Vasut #endif
56bce88370SMarek Vasut 
57bce88370SMarek Vasut /*
58bce88370SMarek Vasut  * DCD block
59bce88370SMarek Vasut  * |-Write to address command block
60bce88370SMarek Vasut  * |  0xf00 == 0xf33d
61bce88370SMarek Vasut  * |  0xba2 == 0xb33f
62bce88370SMarek Vasut  * |-ORR address with mask command block
63bce88370SMarek Vasut  * |  0xf00 |= 0x1337
64bce88370SMarek Vasut  * |-Write to address command block
65bce88370SMarek Vasut  * |  0xba2 == 0xd00d
66bce88370SMarek Vasut  * :
67bce88370SMarek Vasut  */
68bce88370SMarek Vasut #define SB_HAB_DCD_WRITE	0xccUL
69bce88370SMarek Vasut #define SB_HAB_DCD_CHECK	0xcfUL
70bce88370SMarek Vasut #define SB_HAB_DCD_NOOP		0xc0UL
71bce88370SMarek Vasut #define SB_HAB_DCD_MASK_BIT	(1 << 3)
72bce88370SMarek Vasut #define SB_HAB_DCD_SET_BIT	(1 << 4)
73bce88370SMarek Vasut 
74bce88370SMarek Vasut /* Addr.n = Value.n */
75bce88370SMarek Vasut #define	SB_DCD_WRITE	\
76bce88370SMarek Vasut 	(SB_HAB_DCD_WRITE << 24)
77bce88370SMarek Vasut /* Addr.n &= ~Value.n */
78bce88370SMarek Vasut #define	SB_DCD_ANDC	\
79bce88370SMarek Vasut 	((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT)
80bce88370SMarek Vasut /* Addr.n |= Value.n */
81bce88370SMarek Vasut #define	SB_DCD_ORR	\
82bce88370SMarek Vasut 	((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT)
83bce88370SMarek Vasut /* (Addr.n & Value.n) == 0 */
84bce88370SMarek Vasut #define	SB_DCD_CHK_EQZ	\
85bce88370SMarek Vasut 	(SB_HAB_DCD_CHECK << 24)
86bce88370SMarek Vasut /* (Addr.n & Value.n) == Value.n */
87bce88370SMarek Vasut #define	SB_DCD_CHK_EQ	\
88bce88370SMarek Vasut 	((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT)
89bce88370SMarek Vasut /* (Addr.n & Value.n) != Value.n */
90bce88370SMarek Vasut #define	SB_DCD_CHK_NEQ	\
91bce88370SMarek Vasut 	((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_MASK_BIT)
92bce88370SMarek Vasut /* (Addr.n & Value.n) != 0 */
93bce88370SMarek Vasut #define	SB_DCD_CHK_NEZ	\
94bce88370SMarek Vasut 	((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT)
95bce88370SMarek Vasut /* NOP */
96bce88370SMarek Vasut #define	SB_DCD_NOOP	\
97bce88370SMarek Vasut 	(SB_HAB_DCD_NOOP << 24)
98bce88370SMarek Vasut 
99bce88370SMarek Vasut struct sb_dcd_ctx {
100bce88370SMarek Vasut 	struct sb_dcd_ctx		*dcd;
101bce88370SMarek Vasut 
102bce88370SMarek Vasut 	uint32_t			id;
103bce88370SMarek Vasut 
104bce88370SMarek Vasut 	/* The DCD block. */
105bce88370SMarek Vasut 	uint32_t			*payload;
106bce88370SMarek Vasut 	/* Size of the whole DCD block. */
107bce88370SMarek Vasut 	uint32_t			size;
108bce88370SMarek Vasut 
109bce88370SMarek Vasut 	/* Pointer to previous DCD command block. */
110bce88370SMarek Vasut 	uint32_t			*prev_dcd_head;
111bce88370SMarek Vasut };
112bce88370SMarek Vasut 
113bce88370SMarek Vasut /*
114bce88370SMarek Vasut  * IMAGE
115bce88370SMarek Vasut  *   |-SECTION
116bce88370SMarek Vasut  *   |    |-CMD
117bce88370SMarek Vasut  *   |    |-CMD
118bce88370SMarek Vasut  *   |    `-CMD
119bce88370SMarek Vasut  *   |-SECTION
120bce88370SMarek Vasut  *   |    |-CMD
121bce88370SMarek Vasut  *   :    :
122bce88370SMarek Vasut  */
123bce88370SMarek Vasut struct sb_cmd_list {
124bce88370SMarek Vasut 	char				*cmd;
125bce88370SMarek Vasut 	size_t				len;
126bce88370SMarek Vasut 	unsigned int			lineno;
127bce88370SMarek Vasut };
128bce88370SMarek Vasut 
129bce88370SMarek Vasut struct sb_cmd_ctx {
130bce88370SMarek Vasut 	uint32_t			size;
131bce88370SMarek Vasut 
132bce88370SMarek Vasut 	struct sb_cmd_ctx		*cmd;
133bce88370SMarek Vasut 
134bce88370SMarek Vasut 	uint8_t				*data;
135bce88370SMarek Vasut 	uint32_t			length;
136bce88370SMarek Vasut 
137bce88370SMarek Vasut 	struct sb_command		payload;
138bce88370SMarek Vasut 	struct sb_command		c_payload;
139bce88370SMarek Vasut };
140bce88370SMarek Vasut 
141bce88370SMarek Vasut struct sb_section_ctx {
142bce88370SMarek Vasut 	uint32_t			size;
143bce88370SMarek Vasut 
144bce88370SMarek Vasut 	/* Section flags */
145bce88370SMarek Vasut 	unsigned int			boot:1;
146bce88370SMarek Vasut 
147bce88370SMarek Vasut 	struct sb_section_ctx		*sect;
148bce88370SMarek Vasut 
149bce88370SMarek Vasut 	struct sb_cmd_ctx		*cmd_head;
150bce88370SMarek Vasut 	struct sb_cmd_ctx		*cmd_tail;
151bce88370SMarek Vasut 
152bce88370SMarek Vasut 	struct sb_sections_header	payload;
153bce88370SMarek Vasut };
154bce88370SMarek Vasut 
155bce88370SMarek Vasut struct sb_image_ctx {
156bce88370SMarek Vasut 	unsigned int			in_section:1;
157bce88370SMarek Vasut 	unsigned int			in_dcd:1;
158bce88370SMarek Vasut 	/* Image configuration */
1597a139959SAlexey Ignatov 	unsigned int			display_progress:1;
160bce88370SMarek Vasut 	unsigned int			silent_dump:1;
161bce88370SMarek Vasut 	char				*input_filename;
162bce88370SMarek Vasut 	char				*output_filename;
163bce88370SMarek Vasut 	char				*cfg_filename;
164bce88370SMarek Vasut 	uint8_t				image_key[16];
165bce88370SMarek Vasut 
166bce88370SMarek Vasut 	/* Number of section in the image */
167bce88370SMarek Vasut 	unsigned int			sect_count;
168bce88370SMarek Vasut 	/* Bootable section */
169bce88370SMarek Vasut 	unsigned int			sect_boot;
170bce88370SMarek Vasut 	unsigned int			sect_boot_found:1;
171bce88370SMarek Vasut 
172bce88370SMarek Vasut 	struct sb_section_ctx		*sect_head;
173bce88370SMarek Vasut 	struct sb_section_ctx		*sect_tail;
174bce88370SMarek Vasut 
175bce88370SMarek Vasut 	struct sb_dcd_ctx		*dcd_head;
176bce88370SMarek Vasut 	struct sb_dcd_ctx		*dcd_tail;
177bce88370SMarek Vasut 
1787bae13b7SMarek Vasut 	EVP_CIPHER_CTX			*cipher_ctx;
1797bae13b7SMarek Vasut 	EVP_MD_CTX			*md_ctx;
180bce88370SMarek Vasut 	uint8_t				digest[32];
181bce88370SMarek Vasut 	struct sb_key_dictionary_key	sb_dict_key;
182bce88370SMarek Vasut 
183bce88370SMarek Vasut 	struct sb_boot_image_header	payload;
184bce88370SMarek Vasut };
185bce88370SMarek Vasut 
186bce88370SMarek Vasut /*
187bce88370SMarek Vasut  * Instruction semantics:
188bce88370SMarek Vasut  * NOOP
189bce88370SMarek Vasut  * TAG [LAST]
190bce88370SMarek Vasut  * LOAD       address file
191bce88370SMarek Vasut  * LOAD  IVT  address IVT_entry_point
192bce88370SMarek Vasut  * FILL address pattern length
193bce88370SMarek Vasut  * JUMP [HAB] address [r0_arg]
194bce88370SMarek Vasut  * CALL [HAB] address [r0_arg]
195bce88370SMarek Vasut  * MODE mode
196bce88370SMarek Vasut  *      For i.MX23, mode = USB/I2C/SPI1_FLASH/SPI2_FLASH/NAND_BCH
197bce88370SMarek Vasut  *                         JTAG/SPI3_EEPROM/SD_SSP0/SD_SSP1
198bce88370SMarek Vasut  *      For i.MX28, mode = USB/I2C/SPI2_FLASH/SPI3_FLASH/NAND_BCH
199bce88370SMarek Vasut  *                         JTAG/SPI2_EEPROM/SD_SSP0/SD_SSP1
200bce88370SMarek Vasut  */
201bce88370SMarek Vasut 
202bce88370SMarek Vasut /*
203bce88370SMarek Vasut  * AES libcrypto
204bce88370SMarek Vasut  */
205bce88370SMarek Vasut static int sb_aes_init(struct sb_image_ctx *ictx, uint8_t *iv, int enc)
206bce88370SMarek Vasut {
2077bae13b7SMarek Vasut 	EVP_CIPHER_CTX *ctx;
208bce88370SMarek Vasut 	int ret;
209bce88370SMarek Vasut 
210bce88370SMarek Vasut 	/* If there is no init vector, init vector is all zeroes. */
211bce88370SMarek Vasut 	if (!iv)
212bce88370SMarek Vasut 		iv = ictx->image_key;
213bce88370SMarek Vasut 
2147bae13b7SMarek Vasut 	ctx = EVP_CIPHER_CTX_new();
215bce88370SMarek Vasut 	ret = EVP_CipherInit(ctx, EVP_aes_128_cbc(), ictx->image_key, iv, enc);
2167bae13b7SMarek Vasut 	if (ret == 1) {
217bce88370SMarek Vasut 		EVP_CIPHER_CTX_set_padding(ctx, 0);
2187bae13b7SMarek Vasut 		ictx->cipher_ctx = ctx;
2197bae13b7SMarek Vasut 	}
220bce88370SMarek Vasut 	return ret;
221bce88370SMarek Vasut }
222bce88370SMarek Vasut 
223bce88370SMarek Vasut static int sb_aes_crypt(struct sb_image_ctx *ictx, uint8_t *in_data,
224bce88370SMarek Vasut 			uint8_t *out_data, int in_len)
225bce88370SMarek Vasut {
2267bae13b7SMarek Vasut 	EVP_CIPHER_CTX *ctx = ictx->cipher_ctx;
227bce88370SMarek Vasut 	int ret, outlen;
228bce88370SMarek Vasut 	uint8_t *outbuf;
229bce88370SMarek Vasut 
230bce88370SMarek Vasut 	outbuf = malloc(in_len);
231bce88370SMarek Vasut 	if (!outbuf)
232bce88370SMarek Vasut 		return -ENOMEM;
233bce88370SMarek Vasut 	memset(outbuf, 0, sizeof(in_len));
234bce88370SMarek Vasut 
235bce88370SMarek Vasut 	ret = EVP_CipherUpdate(ctx, outbuf, &outlen, in_data, in_len);
236bce88370SMarek Vasut 	if (!ret) {
237bce88370SMarek Vasut 		ret = -EINVAL;
238bce88370SMarek Vasut 		goto err;
239bce88370SMarek Vasut 	}
240bce88370SMarek Vasut 
241bce88370SMarek Vasut 	if (out_data)
242bce88370SMarek Vasut 		memcpy(out_data, outbuf, outlen);
243bce88370SMarek Vasut 
244bce88370SMarek Vasut err:
245bce88370SMarek Vasut 	free(outbuf);
246bce88370SMarek Vasut 	return ret;
247bce88370SMarek Vasut }
248bce88370SMarek Vasut 
249bce88370SMarek Vasut static int sb_aes_deinit(EVP_CIPHER_CTX *ctx)
250bce88370SMarek Vasut {
2517bae13b7SMarek Vasut 	return EVP_CIPHER_CTX_reset(ctx);
252bce88370SMarek Vasut }
253bce88370SMarek Vasut 
254bce88370SMarek Vasut static int sb_aes_reinit(struct sb_image_ctx *ictx, int enc)
255bce88370SMarek Vasut {
256bce88370SMarek Vasut 	int ret;
2577bae13b7SMarek Vasut 	EVP_CIPHER_CTX *ctx = ictx->cipher_ctx;
258bce88370SMarek Vasut 	struct sb_boot_image_header *sb_header = &ictx->payload;
259bce88370SMarek Vasut 	uint8_t *iv = sb_header->iv;
260bce88370SMarek Vasut 
261bce88370SMarek Vasut 	ret = sb_aes_deinit(ctx);
262bce88370SMarek Vasut 	if (!ret)
263bce88370SMarek Vasut 		return ret;
264bce88370SMarek Vasut 	return sb_aes_init(ictx, iv, enc);
265bce88370SMarek Vasut }
266bce88370SMarek Vasut 
267bce88370SMarek Vasut /*
268bce88370SMarek Vasut  * Debug
269bce88370SMarek Vasut  */
270bce88370SMarek Vasut static void soprintf(struct sb_image_ctx *ictx, const char *fmt, ...)
271bce88370SMarek Vasut {
272bce88370SMarek Vasut 	va_list ap;
273bce88370SMarek Vasut 
274bce88370SMarek Vasut 	if (ictx->silent_dump)
275bce88370SMarek Vasut 		return;
276bce88370SMarek Vasut 
277bce88370SMarek Vasut 	va_start(ap, fmt);
278bce88370SMarek Vasut 	vfprintf(stdout, fmt, ap);
279bce88370SMarek Vasut 	va_end(ap);
280bce88370SMarek Vasut }
281bce88370SMarek Vasut 
282bce88370SMarek Vasut /*
283bce88370SMarek Vasut  * Code
284bce88370SMarek Vasut  */
285bce88370SMarek Vasut static time_t sb_get_timestamp(void)
286bce88370SMarek Vasut {
287bce88370SMarek Vasut 	struct tm time_2000 = {
288bce88370SMarek Vasut 		.tm_yday	= 1,	/* Jan. 1st */
289bce88370SMarek Vasut 		.tm_year	= 100,	/* 2000 */
290bce88370SMarek Vasut 	};
291bce88370SMarek Vasut 	time_t seconds_to_2000 = mktime(&time_2000);
292bce88370SMarek Vasut 	time_t seconds_to_now = time(NULL);
293bce88370SMarek Vasut 
294bce88370SMarek Vasut 	return seconds_to_now - seconds_to_2000;
295bce88370SMarek Vasut }
296bce88370SMarek Vasut 
297bce88370SMarek Vasut static int sb_get_time(time_t time, struct tm *tm)
298bce88370SMarek Vasut {
299bce88370SMarek Vasut 	struct tm time_2000 = {
300bce88370SMarek Vasut 		.tm_yday	= 1,	/* Jan. 1st */
301bce88370SMarek Vasut 		.tm_year	= 0,	/* 1900 */
302bce88370SMarek Vasut 	};
303bce88370SMarek Vasut 	const time_t seconds_to_2000 = mktime(&time_2000);
304bce88370SMarek Vasut 	const time_t seconds_to_now = seconds_to_2000 + time;
305bce88370SMarek Vasut 	struct tm *ret;
306bce88370SMarek Vasut 	ret = gmtime_r(&seconds_to_now, tm);
307bce88370SMarek Vasut 	return ret ? 0 : -EINVAL;
308bce88370SMarek Vasut }
309bce88370SMarek Vasut 
310bce88370SMarek Vasut static void sb_encrypt_sb_header(struct sb_image_ctx *ictx)
311bce88370SMarek Vasut {
3127bae13b7SMarek Vasut 	EVP_MD_CTX *md_ctx = ictx->md_ctx;
313bce88370SMarek Vasut 	struct sb_boot_image_header *sb_header = &ictx->payload;
314bce88370SMarek Vasut 	uint8_t *sb_header_ptr = (uint8_t *)sb_header;
315bce88370SMarek Vasut 
316bce88370SMarek Vasut 	/* Encrypt the header, compute the digest. */
317bce88370SMarek Vasut 	sb_aes_crypt(ictx, sb_header_ptr, NULL, sizeof(*sb_header));
318bce88370SMarek Vasut 	EVP_DigestUpdate(md_ctx, sb_header_ptr, sizeof(*sb_header));
319bce88370SMarek Vasut }
320bce88370SMarek Vasut 
321bce88370SMarek Vasut static void sb_encrypt_sb_sections_header(struct sb_image_ctx *ictx)
322bce88370SMarek Vasut {
3237bae13b7SMarek Vasut 	EVP_MD_CTX *md_ctx = ictx->md_ctx;
324bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_head;
325bce88370SMarek Vasut 	struct sb_sections_header *shdr;
326bce88370SMarek Vasut 	uint8_t *sb_sections_header_ptr;
327bce88370SMarek Vasut 	const int size = sizeof(*shdr);
328bce88370SMarek Vasut 
329bce88370SMarek Vasut 	while (sctx) {
330bce88370SMarek Vasut 		shdr = &sctx->payload;
331bce88370SMarek Vasut 		sb_sections_header_ptr = (uint8_t *)shdr;
332bce88370SMarek Vasut 
333bce88370SMarek Vasut 		sb_aes_crypt(ictx, sb_sections_header_ptr,
334bce88370SMarek Vasut 			     ictx->sb_dict_key.cbc_mac, size);
335bce88370SMarek Vasut 		EVP_DigestUpdate(md_ctx, sb_sections_header_ptr, size);
336bce88370SMarek Vasut 
337bce88370SMarek Vasut 		sctx = sctx->sect;
338bce88370SMarek Vasut 	};
339bce88370SMarek Vasut }
340bce88370SMarek Vasut 
341bce88370SMarek Vasut static void sb_encrypt_key_dictionary_key(struct sb_image_ctx *ictx)
342bce88370SMarek Vasut {
3437bae13b7SMarek Vasut 	EVP_MD_CTX *md_ctx = ictx->md_ctx;
344bce88370SMarek Vasut 
345bce88370SMarek Vasut 	sb_aes_crypt(ictx, ictx->image_key, ictx->sb_dict_key.key,
346bce88370SMarek Vasut 		     sizeof(ictx->sb_dict_key.key));
347bce88370SMarek Vasut 	EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key));
348bce88370SMarek Vasut }
349bce88370SMarek Vasut 
350bce88370SMarek Vasut static void sb_decrypt_key_dictionary_key(struct sb_image_ctx *ictx)
351bce88370SMarek Vasut {
3527bae13b7SMarek Vasut 	EVP_MD_CTX *md_ctx = ictx->md_ctx;
353bce88370SMarek Vasut 
354bce88370SMarek Vasut 	EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key));
355bce88370SMarek Vasut 	sb_aes_crypt(ictx, ictx->sb_dict_key.key, ictx->image_key,
356bce88370SMarek Vasut 		     sizeof(ictx->sb_dict_key.key));
357bce88370SMarek Vasut }
358bce88370SMarek Vasut 
359bce88370SMarek Vasut static void sb_encrypt_tag(struct sb_image_ctx *ictx,
360bce88370SMarek Vasut 		struct sb_cmd_ctx *cctx)
361bce88370SMarek Vasut {
3627bae13b7SMarek Vasut 	EVP_MD_CTX *md_ctx = ictx->md_ctx;
363bce88370SMarek Vasut 	struct sb_command *cmd = &cctx->payload;
364bce88370SMarek Vasut 
365bce88370SMarek Vasut 	sb_aes_crypt(ictx, (uint8_t *)cmd,
366bce88370SMarek Vasut 		     (uint8_t *)&cctx->c_payload, sizeof(*cmd));
367bce88370SMarek Vasut 	EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd));
368bce88370SMarek Vasut }
369bce88370SMarek Vasut 
370bce88370SMarek Vasut static int sb_encrypt_image(struct sb_image_ctx *ictx)
371bce88370SMarek Vasut {
372bce88370SMarek Vasut 	/* Start image-wide crypto. */
3737bae13b7SMarek Vasut 	ictx->md_ctx = EVP_MD_CTX_new();
3747bae13b7SMarek Vasut 	EVP_DigestInit(ictx->md_ctx, EVP_sha1());
375bce88370SMarek Vasut 
376bce88370SMarek Vasut 	/*
377bce88370SMarek Vasut 	 * SB image header.
378bce88370SMarek Vasut 	 */
379bce88370SMarek Vasut 	sb_aes_init(ictx, NULL, 1);
380bce88370SMarek Vasut 	sb_encrypt_sb_header(ictx);
381bce88370SMarek Vasut 
382bce88370SMarek Vasut 	/*
383bce88370SMarek Vasut 	 * SB sections header.
384bce88370SMarek Vasut 	 */
385bce88370SMarek Vasut 	sb_encrypt_sb_sections_header(ictx);
386bce88370SMarek Vasut 
387bce88370SMarek Vasut 	/*
388bce88370SMarek Vasut 	 * Key dictionary.
389bce88370SMarek Vasut 	 */
390bce88370SMarek Vasut 	sb_aes_reinit(ictx, 1);
391bce88370SMarek Vasut 	sb_encrypt_key_dictionary_key(ictx);
392bce88370SMarek Vasut 
393bce88370SMarek Vasut 	/*
394bce88370SMarek Vasut 	 * Section tags.
395bce88370SMarek Vasut 	 */
396bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
397bce88370SMarek Vasut 	struct sb_command *ccmd;
398bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_head;
399bce88370SMarek Vasut 
400bce88370SMarek Vasut 	while (sctx) {
401bce88370SMarek Vasut 		cctx = sctx->cmd_head;
402bce88370SMarek Vasut 
403bce88370SMarek Vasut 		sb_aes_reinit(ictx, 1);
404bce88370SMarek Vasut 
405bce88370SMarek Vasut 		while (cctx) {
406bce88370SMarek Vasut 			ccmd = &cctx->payload;
407bce88370SMarek Vasut 
408bce88370SMarek Vasut 			sb_encrypt_tag(ictx, cctx);
409bce88370SMarek Vasut 
410bce88370SMarek Vasut 			if (ccmd->header.tag == ROM_TAG_CMD) {
411bce88370SMarek Vasut 				sb_aes_reinit(ictx, 1);
412bce88370SMarek Vasut 			} else if (ccmd->header.tag == ROM_LOAD_CMD) {
413bce88370SMarek Vasut 				sb_aes_crypt(ictx, cctx->data, cctx->data,
414bce88370SMarek Vasut 					     cctx->length);
4157bae13b7SMarek Vasut 				EVP_DigestUpdate(ictx->md_ctx, cctx->data,
416bce88370SMarek Vasut 						 cctx->length);
417bce88370SMarek Vasut 			}
418bce88370SMarek Vasut 
419bce88370SMarek Vasut 			cctx = cctx->cmd;
420bce88370SMarek Vasut 		}
421bce88370SMarek Vasut 
422bce88370SMarek Vasut 		sctx = sctx->sect;
423bce88370SMarek Vasut 	};
424bce88370SMarek Vasut 
425bce88370SMarek Vasut 	/*
426bce88370SMarek Vasut 	 * Dump the SHA1 of the whole image.
427bce88370SMarek Vasut 	 */
428bce88370SMarek Vasut 	sb_aes_reinit(ictx, 1);
429bce88370SMarek Vasut 
4307bae13b7SMarek Vasut 	EVP_DigestFinal(ictx->md_ctx, ictx->digest, NULL);
4317bae13b7SMarek Vasut 	EVP_MD_CTX_free(ictx->md_ctx);
432bce88370SMarek Vasut 	sb_aes_crypt(ictx, ictx->digest, ictx->digest, sizeof(ictx->digest));
433bce88370SMarek Vasut 
434bce88370SMarek Vasut 	/* Stop the encryption session. */
4357bae13b7SMarek Vasut 	sb_aes_deinit(ictx->cipher_ctx);
436bce88370SMarek Vasut 
437bce88370SMarek Vasut 	return 0;
438bce88370SMarek Vasut }
439bce88370SMarek Vasut 
440bce88370SMarek Vasut static int sb_load_file(struct sb_cmd_ctx *cctx, char *filename)
441bce88370SMarek Vasut {
442bce88370SMarek Vasut 	long real_size, roundup_size;
443bce88370SMarek Vasut 	uint8_t *data;
444bce88370SMarek Vasut 	long ret;
445bce88370SMarek Vasut 	unsigned long size;
446bce88370SMarek Vasut 	FILE *fp;
447bce88370SMarek Vasut 
448bce88370SMarek Vasut 	if (!filename) {
449bce88370SMarek Vasut 		fprintf(stderr, "ERR: Missing filename!\n");
450bce88370SMarek Vasut 		return -EINVAL;
451bce88370SMarek Vasut 	}
452bce88370SMarek Vasut 
453bce88370SMarek Vasut 	fp = fopen(filename, "r");
454bce88370SMarek Vasut 	if (!fp)
455bce88370SMarek Vasut 		goto err_open;
456bce88370SMarek Vasut 
457bce88370SMarek Vasut 	ret = fseek(fp, 0, SEEK_END);
458bce88370SMarek Vasut 	if (ret < 0)
459bce88370SMarek Vasut 		goto err_file;
460bce88370SMarek Vasut 
461bce88370SMarek Vasut 	real_size = ftell(fp);
462bce88370SMarek Vasut 	if (real_size < 0)
463bce88370SMarek Vasut 		goto err_file;
464bce88370SMarek Vasut 
465bce88370SMarek Vasut 	ret = fseek(fp, 0, SEEK_SET);
466bce88370SMarek Vasut 	if (ret < 0)
467bce88370SMarek Vasut 		goto err_file;
468bce88370SMarek Vasut 
469bce88370SMarek Vasut 	roundup_size = roundup(real_size, SB_BLOCK_SIZE);
470bce88370SMarek Vasut 	data = calloc(1, roundup_size);
471bce88370SMarek Vasut 	if (!data)
472bce88370SMarek Vasut 		goto err_file;
473bce88370SMarek Vasut 
474bce88370SMarek Vasut 	size = fread(data, 1, real_size, fp);
475bce88370SMarek Vasut 	if (size != (unsigned long)real_size)
476bce88370SMarek Vasut 		goto err_alloc;
477bce88370SMarek Vasut 
478bce88370SMarek Vasut 	cctx->data = data;
479bce88370SMarek Vasut 	cctx->length = roundup_size;
480bce88370SMarek Vasut 
481bce88370SMarek Vasut 	fclose(fp);
482bce88370SMarek Vasut 	return 0;
483bce88370SMarek Vasut 
484bce88370SMarek Vasut err_alloc:
485bce88370SMarek Vasut 	free(data);
486bce88370SMarek Vasut err_file:
487bce88370SMarek Vasut 	fclose(fp);
488bce88370SMarek Vasut err_open:
489bce88370SMarek Vasut 	fprintf(stderr, "ERR: Failed to load file \"%s\"\n", filename);
490bce88370SMarek Vasut 	return -EINVAL;
491bce88370SMarek Vasut }
492bce88370SMarek Vasut 
493bce88370SMarek Vasut static uint8_t sb_command_checksum(struct sb_command *inst)
494bce88370SMarek Vasut {
495bce88370SMarek Vasut 	uint8_t *inst_ptr = (uint8_t *)inst;
496bce88370SMarek Vasut 	uint8_t csum = 0;
497bce88370SMarek Vasut 	unsigned int i;
498bce88370SMarek Vasut 
499bce88370SMarek Vasut 	for (i = 0; i < sizeof(struct sb_command); i++)
500bce88370SMarek Vasut 		csum += inst_ptr[i];
501bce88370SMarek Vasut 
502bce88370SMarek Vasut 	return csum;
503bce88370SMarek Vasut }
504bce88370SMarek Vasut 
505bce88370SMarek Vasut static int sb_token_to_long(char *tok, uint32_t *rid)
506bce88370SMarek Vasut {
507bce88370SMarek Vasut 	char *endptr;
508bce88370SMarek Vasut 	unsigned long id;
509bce88370SMarek Vasut 
510bce88370SMarek Vasut 	if (tok[0] != '0' || tok[1] != 'x') {
511bce88370SMarek Vasut 		fprintf(stderr, "ERR: Invalid hexadecimal number!\n");
512bce88370SMarek Vasut 		return -EINVAL;
513bce88370SMarek Vasut 	}
514bce88370SMarek Vasut 
515bce88370SMarek Vasut 	tok += 2;
516bce88370SMarek Vasut 
5175b5a82ebSMarek Vasut 	errno = 0;
518bce88370SMarek Vasut 	id = strtoul(tok, &endptr, 16);
519bce88370SMarek Vasut 	if ((errno == ERANGE && id == ULONG_MAX) || (errno != 0 && id == 0)) {
520bce88370SMarek Vasut 		fprintf(stderr, "ERR: Value can't be decoded!\n");
521bce88370SMarek Vasut 		return -EINVAL;
522bce88370SMarek Vasut 	}
523bce88370SMarek Vasut 
524bce88370SMarek Vasut 	/* Check for 32-bit overflow. */
525bce88370SMarek Vasut 	if (id > 0xffffffff) {
526bce88370SMarek Vasut 		fprintf(stderr, "ERR: Value too big!\n");
527bce88370SMarek Vasut 		return -EINVAL;
528bce88370SMarek Vasut 	}
529bce88370SMarek Vasut 
530bce88370SMarek Vasut 	if (endptr == tok) {
531bce88370SMarek Vasut 		fprintf(stderr, "ERR: Deformed value!\n");
532bce88370SMarek Vasut 		return -EINVAL;
533bce88370SMarek Vasut 	}
534bce88370SMarek Vasut 
535bce88370SMarek Vasut 	*rid = (uint32_t)id;
536bce88370SMarek Vasut 	return 0;
537bce88370SMarek Vasut }
538bce88370SMarek Vasut 
539bce88370SMarek Vasut static int sb_grow_dcd(struct sb_dcd_ctx *dctx, unsigned int inc_size)
540bce88370SMarek Vasut {
541bce88370SMarek Vasut 	uint32_t *tmp;
542bce88370SMarek Vasut 
543bce88370SMarek Vasut 	if (!inc_size)
544bce88370SMarek Vasut 		return 0;
545bce88370SMarek Vasut 
546bce88370SMarek Vasut 	dctx->size += inc_size;
547bce88370SMarek Vasut 	tmp = realloc(dctx->payload, dctx->size);
548bce88370SMarek Vasut 	if (!tmp)
549bce88370SMarek Vasut 		return -ENOMEM;
550bce88370SMarek Vasut 
551bce88370SMarek Vasut 	dctx->payload = tmp;
552bce88370SMarek Vasut 
553bce88370SMarek Vasut 	/* Assemble and update the HAB DCD header. */
554bce88370SMarek Vasut 	dctx->payload[0] = htonl((SB_HAB_DCD_TAG << 24) |
555bce88370SMarek Vasut 				 (dctx->size << 8) |
556bce88370SMarek Vasut 				 SB_HAB_VERSION);
557bce88370SMarek Vasut 
558bce88370SMarek Vasut 	return 0;
559bce88370SMarek Vasut }
560bce88370SMarek Vasut 
561bce88370SMarek Vasut static int sb_build_dcd(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
562bce88370SMarek Vasut {
563bce88370SMarek Vasut 	struct sb_dcd_ctx *dctx;
564bce88370SMarek Vasut 
565bce88370SMarek Vasut 	char *tok;
566bce88370SMarek Vasut 	uint32_t id;
567bce88370SMarek Vasut 	int ret;
568bce88370SMarek Vasut 
569bce88370SMarek Vasut 	dctx = calloc(1, sizeof(*dctx));
570bce88370SMarek Vasut 	if (!dctx)
571bce88370SMarek Vasut 		return -ENOMEM;
572bce88370SMarek Vasut 
573bce88370SMarek Vasut 	ret = sb_grow_dcd(dctx, 4);
574bce88370SMarek Vasut 	if (ret)
575bce88370SMarek Vasut 		goto err_dcd;
576bce88370SMarek Vasut 
577bce88370SMarek Vasut 	/* Read DCD block number. */
578bce88370SMarek Vasut 	tok = strtok(cmd->cmd, " ");
579bce88370SMarek Vasut 	if (!tok) {
580bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: DCD block without number!\n",
581bce88370SMarek Vasut 			cmd->lineno);
582bce88370SMarek Vasut 		ret = -EINVAL;
583bce88370SMarek Vasut 		goto err_dcd;
584bce88370SMarek Vasut 	}
585bce88370SMarek Vasut 
586bce88370SMarek Vasut 	/* Parse the DCD block number. */
587bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &id);
588bce88370SMarek Vasut 	if (ret) {
589bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Malformed DCD block number!\n",
590bce88370SMarek Vasut 			cmd->lineno);
591bce88370SMarek Vasut 		goto err_dcd;
592bce88370SMarek Vasut 	}
593bce88370SMarek Vasut 
594bce88370SMarek Vasut 	dctx->id = id;
595bce88370SMarek Vasut 
596bce88370SMarek Vasut 	/*
597bce88370SMarek Vasut 	 * The DCD block is now constructed. Append it to the list.
598bce88370SMarek Vasut 	 * WARNING: The DCD size is still not computed and will be
599bce88370SMarek Vasut 	 * updated while parsing it's commands.
600bce88370SMarek Vasut 	 */
601bce88370SMarek Vasut 	if (!ictx->dcd_head) {
602bce88370SMarek Vasut 		ictx->dcd_head = dctx;
603bce88370SMarek Vasut 		ictx->dcd_tail = dctx;
604bce88370SMarek Vasut 	} else {
605bce88370SMarek Vasut 		ictx->dcd_tail->dcd = dctx;
606bce88370SMarek Vasut 		ictx->dcd_tail = dctx;
607bce88370SMarek Vasut 	}
608bce88370SMarek Vasut 
609bce88370SMarek Vasut 	return 0;
610bce88370SMarek Vasut 
611bce88370SMarek Vasut err_dcd:
612bce88370SMarek Vasut 	free(dctx->payload);
613bce88370SMarek Vasut 	free(dctx);
614bce88370SMarek Vasut 	return ret;
615bce88370SMarek Vasut }
616bce88370SMarek Vasut 
617bce88370SMarek Vasut static int sb_build_dcd_block(struct sb_image_ctx *ictx,
618bce88370SMarek Vasut 			      struct sb_cmd_list *cmd,
619bce88370SMarek Vasut 			      uint32_t type)
620bce88370SMarek Vasut {
621bce88370SMarek Vasut 	char *tok;
622bce88370SMarek Vasut 	uint32_t address, value, length;
623bce88370SMarek Vasut 	int ret;
624bce88370SMarek Vasut 
625bce88370SMarek Vasut 	struct sb_dcd_ctx *dctx = ictx->dcd_tail;
626bce88370SMarek Vasut 	uint32_t *dcd;
627bce88370SMarek Vasut 
628bce88370SMarek Vasut 	if (dctx->prev_dcd_head && (type != SB_DCD_NOOP) &&
629bce88370SMarek Vasut 	    ((dctx->prev_dcd_head[0] & 0xff0000ff) == type)) {
630bce88370SMarek Vasut 		/* Same instruction as before, just append it. */
631bce88370SMarek Vasut 		ret = sb_grow_dcd(dctx, 8);
632bce88370SMarek Vasut 		if (ret)
633bce88370SMarek Vasut 			return ret;
634bce88370SMarek Vasut 	} else if (type == SB_DCD_NOOP) {
635bce88370SMarek Vasut 		ret = sb_grow_dcd(dctx, 4);
636bce88370SMarek Vasut 		if (ret)
637bce88370SMarek Vasut 			return ret;
638bce88370SMarek Vasut 
639bce88370SMarek Vasut 		/* Update DCD command block pointer. */
640bce88370SMarek Vasut 		dctx->prev_dcd_head = dctx->payload +
641bce88370SMarek Vasut 				dctx->size / sizeof(*dctx->payload) - 1;
642bce88370SMarek Vasut 
643bce88370SMarek Vasut 		/* NOOP has only 4 bytes and no payload. */
644bce88370SMarek Vasut 		goto noop;
645bce88370SMarek Vasut 	} else {
646bce88370SMarek Vasut 		/*
647bce88370SMarek Vasut 		 * Either a different instruction block started now
648bce88370SMarek Vasut 		 * or this is the first instruction block.
649bce88370SMarek Vasut 		 */
650bce88370SMarek Vasut 		ret = sb_grow_dcd(dctx, 12);
651bce88370SMarek Vasut 		if (ret)
652bce88370SMarek Vasut 			return ret;
653bce88370SMarek Vasut 
654bce88370SMarek Vasut 		/* Update DCD command block pointer. */
655bce88370SMarek Vasut 		dctx->prev_dcd_head = dctx->payload +
656bce88370SMarek Vasut 				dctx->size / sizeof(*dctx->payload) - 3;
657bce88370SMarek Vasut 	}
658bce88370SMarek Vasut 
659bce88370SMarek Vasut 	dcd = dctx->payload + dctx->size / sizeof(*dctx->payload) - 2;
660bce88370SMarek Vasut 
661bce88370SMarek Vasut 	/*
662bce88370SMarek Vasut 	 * Prepare the command.
663bce88370SMarek Vasut 	 */
664bce88370SMarek Vasut 	tok = strtok(cmd->cmd, " ");
665bce88370SMarek Vasut 	if (!tok) {
666bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Missing DCD address!\n",
667bce88370SMarek Vasut 			cmd->lineno);
668bce88370SMarek Vasut 		ret = -EINVAL;
669bce88370SMarek Vasut 		goto err;
670bce88370SMarek Vasut 	}
671bce88370SMarek Vasut 
672bce88370SMarek Vasut 	/* Read DCD destination address. */
673bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &address);
674bce88370SMarek Vasut 	if (ret) {
675bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Incorrect DCD address!\n",
676bce88370SMarek Vasut 			cmd->lineno);
677bce88370SMarek Vasut 		goto err;
678bce88370SMarek Vasut 	}
679bce88370SMarek Vasut 
680bce88370SMarek Vasut 	tok = strtok(NULL, " ");
681bce88370SMarek Vasut 	if (!tok) {
682bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Missing DCD value!\n",
683bce88370SMarek Vasut 			cmd->lineno);
684bce88370SMarek Vasut 		ret = -EINVAL;
685bce88370SMarek Vasut 		goto err;
686bce88370SMarek Vasut 	}
687bce88370SMarek Vasut 
688bce88370SMarek Vasut 	/* Read DCD operation value. */
689bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &value);
690bce88370SMarek Vasut 	if (ret) {
691bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Incorrect DCD value!\n",
692bce88370SMarek Vasut 			cmd->lineno);
693bce88370SMarek Vasut 		goto err;
694bce88370SMarek Vasut 	}
695bce88370SMarek Vasut 
696bce88370SMarek Vasut 	/* Fill in the new DCD entry. */
697bce88370SMarek Vasut 	dcd[0] = htonl(address);
698bce88370SMarek Vasut 	dcd[1] = htonl(value);
699bce88370SMarek Vasut 
700bce88370SMarek Vasut noop:
701bce88370SMarek Vasut 	/* Update the DCD command block. */
702bce88370SMarek Vasut 	length = dctx->size -
703bce88370SMarek Vasut 		 ((dctx->prev_dcd_head - dctx->payload) *
704bce88370SMarek Vasut 		 sizeof(*dctx->payload));
705bce88370SMarek Vasut 	dctx->prev_dcd_head[0] = htonl(type | (length << 8));
706bce88370SMarek Vasut 
707bce88370SMarek Vasut err:
708bce88370SMarek Vasut 	return ret;
709bce88370SMarek Vasut }
710bce88370SMarek Vasut 
711bce88370SMarek Vasut static int sb_build_section(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
712bce88370SMarek Vasut {
713bce88370SMarek Vasut 	struct sb_section_ctx *sctx;
714bce88370SMarek Vasut 	struct sb_sections_header *shdr;
715bce88370SMarek Vasut 	char *tok;
716bce88370SMarek Vasut 	uint32_t bootable = 0;
717bce88370SMarek Vasut 	uint32_t id;
718bce88370SMarek Vasut 	int ret;
719bce88370SMarek Vasut 
720bce88370SMarek Vasut 	sctx = calloc(1, sizeof(*sctx));
721bce88370SMarek Vasut 	if (!sctx)
722bce88370SMarek Vasut 		return -ENOMEM;
723bce88370SMarek Vasut 
724bce88370SMarek Vasut 	/* Read section number. */
725bce88370SMarek Vasut 	tok = strtok(cmd->cmd, " ");
726bce88370SMarek Vasut 	if (!tok) {
727bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Section without number!\n",
728bce88370SMarek Vasut 			cmd->lineno);
729bce88370SMarek Vasut 		ret = -EINVAL;
730bce88370SMarek Vasut 		goto err_sect;
731bce88370SMarek Vasut 	}
732bce88370SMarek Vasut 
733bce88370SMarek Vasut 	/* Parse the section number. */
734bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &id);
735bce88370SMarek Vasut 	if (ret) {
736bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Malformed section number!\n",
737bce88370SMarek Vasut 			cmd->lineno);
738bce88370SMarek Vasut 		goto err_sect;
739bce88370SMarek Vasut 	}
740bce88370SMarek Vasut 
741bce88370SMarek Vasut 	/* Read section's BOOTABLE flag. */
742bce88370SMarek Vasut 	tok = strtok(NULL, " ");
743bce88370SMarek Vasut 	if (tok && (strlen(tok) == 8) && !strncmp(tok, "BOOTABLE", 8))
744bce88370SMarek Vasut 		bootable = SB_SECTION_FLAG_BOOTABLE;
745bce88370SMarek Vasut 
746bce88370SMarek Vasut 	sctx->boot = bootable;
747bce88370SMarek Vasut 
748bce88370SMarek Vasut 	shdr = &sctx->payload;
749bce88370SMarek Vasut 	shdr->section_number = id;
750bce88370SMarek Vasut 	shdr->section_flags = bootable;
751bce88370SMarek Vasut 
752bce88370SMarek Vasut 	/*
753bce88370SMarek Vasut 	 * The section is now constructed. Append it to the list.
754bce88370SMarek Vasut 	 * WARNING: The section size is still not computed and will
755bce88370SMarek Vasut 	 * be updated while parsing it's commands.
756bce88370SMarek Vasut 	 */
757bce88370SMarek Vasut 	ictx->sect_count++;
758bce88370SMarek Vasut 
759bce88370SMarek Vasut 	/* Mark that this section is bootable one. */
760bce88370SMarek Vasut 	if (bootable) {
761bce88370SMarek Vasut 		if (ictx->sect_boot_found) {
762bce88370SMarek Vasut 			fprintf(stderr,
763bce88370SMarek Vasut 				"#%i WARN: Multiple bootable section!\n",
764bce88370SMarek Vasut 				cmd->lineno);
765bce88370SMarek Vasut 		} else {
766bce88370SMarek Vasut 			ictx->sect_boot = id;
767bce88370SMarek Vasut 			ictx->sect_boot_found = 1;
768bce88370SMarek Vasut 		}
769bce88370SMarek Vasut 	}
770bce88370SMarek Vasut 
771bce88370SMarek Vasut 	if (!ictx->sect_head) {
772bce88370SMarek Vasut 		ictx->sect_head = sctx;
773bce88370SMarek Vasut 		ictx->sect_tail = sctx;
774bce88370SMarek Vasut 	} else {
775bce88370SMarek Vasut 		ictx->sect_tail->sect = sctx;
776bce88370SMarek Vasut 		ictx->sect_tail = sctx;
777bce88370SMarek Vasut 	}
778bce88370SMarek Vasut 
779bce88370SMarek Vasut 	return 0;
780bce88370SMarek Vasut 
781bce88370SMarek Vasut err_sect:
782bce88370SMarek Vasut 	free(sctx);
783bce88370SMarek Vasut 	return ret;
784bce88370SMarek Vasut }
785bce88370SMarek Vasut 
786bce88370SMarek Vasut static int sb_build_command_nop(struct sb_image_ctx *ictx)
787bce88370SMarek Vasut {
788bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_tail;
789bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
790bce88370SMarek Vasut 	struct sb_command *ccmd;
791bce88370SMarek Vasut 
792bce88370SMarek Vasut 	cctx = calloc(1, sizeof(*cctx));
793bce88370SMarek Vasut 	if (!cctx)
794bce88370SMarek Vasut 		return -ENOMEM;
795bce88370SMarek Vasut 
796bce88370SMarek Vasut 	ccmd = &cctx->payload;
797bce88370SMarek Vasut 
798bce88370SMarek Vasut 	/*
799bce88370SMarek Vasut 	 * Construct the command.
800bce88370SMarek Vasut 	 */
801bce88370SMarek Vasut 	ccmd->header.checksum	= 0x5a;
802bce88370SMarek Vasut 	ccmd->header.tag	= ROM_NOP_CMD;
803bce88370SMarek Vasut 
804bce88370SMarek Vasut 	cctx->size = sizeof(*ccmd);
805bce88370SMarek Vasut 
806bce88370SMarek Vasut 	/*
807bce88370SMarek Vasut 	 * Append the command to the last section.
808bce88370SMarek Vasut 	 */
809bce88370SMarek Vasut 	if (!sctx->cmd_head) {
810bce88370SMarek Vasut 		sctx->cmd_head = cctx;
811bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
812bce88370SMarek Vasut 	} else {
813bce88370SMarek Vasut 		sctx->cmd_tail->cmd = cctx;
814bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
815bce88370SMarek Vasut 	}
816bce88370SMarek Vasut 
817bce88370SMarek Vasut 	return 0;
818bce88370SMarek Vasut }
819bce88370SMarek Vasut 
820bce88370SMarek Vasut static int sb_build_command_tag(struct sb_image_ctx *ictx,
821bce88370SMarek Vasut 				struct sb_cmd_list *cmd)
822bce88370SMarek Vasut {
823bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_tail;
824bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
825bce88370SMarek Vasut 	struct sb_command *ccmd;
826bce88370SMarek Vasut 	char *tok;
827bce88370SMarek Vasut 
828bce88370SMarek Vasut 	cctx = calloc(1, sizeof(*cctx));
829bce88370SMarek Vasut 	if (!cctx)
830bce88370SMarek Vasut 		return -ENOMEM;
831bce88370SMarek Vasut 
832bce88370SMarek Vasut 	ccmd = &cctx->payload;
833bce88370SMarek Vasut 
834bce88370SMarek Vasut 	/*
835bce88370SMarek Vasut 	 * Prepare the command.
836bce88370SMarek Vasut 	 */
837bce88370SMarek Vasut 	/* Check for the LAST keyword. */
838bce88370SMarek Vasut 	tok = strtok(cmd->cmd, " ");
839bce88370SMarek Vasut 	if (tok && !strcmp(tok, "LAST"))
840bce88370SMarek Vasut 		ccmd->header.flags = ROM_TAG_CMD_FLAG_ROM_LAST_TAG;
841bce88370SMarek Vasut 
842bce88370SMarek Vasut 	/*
843bce88370SMarek Vasut 	 * Construct the command.
844bce88370SMarek Vasut 	 */
845bce88370SMarek Vasut 	ccmd->header.checksum	= 0x5a;
846bce88370SMarek Vasut 	ccmd->header.tag	= ROM_TAG_CMD;
847bce88370SMarek Vasut 
848bce88370SMarek Vasut 	cctx->size = sizeof(*ccmd);
849bce88370SMarek Vasut 
850bce88370SMarek Vasut 	/*
851bce88370SMarek Vasut 	 * Append the command to the last section.
852bce88370SMarek Vasut 	 */
853bce88370SMarek Vasut 	if (!sctx->cmd_head) {
854bce88370SMarek Vasut 		sctx->cmd_head = cctx;
855bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
856bce88370SMarek Vasut 	} else {
857bce88370SMarek Vasut 		sctx->cmd_tail->cmd = cctx;
858bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
859bce88370SMarek Vasut 	}
860bce88370SMarek Vasut 
861bce88370SMarek Vasut 	return 0;
862bce88370SMarek Vasut }
863bce88370SMarek Vasut 
864bce88370SMarek Vasut static int sb_build_command_load(struct sb_image_ctx *ictx,
865bce88370SMarek Vasut 				 struct sb_cmd_list *cmd)
866bce88370SMarek Vasut {
867bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_tail;
868bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
869bce88370SMarek Vasut 	struct sb_command *ccmd;
870bce88370SMarek Vasut 	char *tok;
871bce88370SMarek Vasut 	int ret, is_ivt = 0, is_dcd = 0;
872bce88370SMarek Vasut 	uint32_t dest, dcd = 0;
873bce88370SMarek Vasut 
874bce88370SMarek Vasut 	cctx = calloc(1, sizeof(*cctx));
875bce88370SMarek Vasut 	if (!cctx)
876bce88370SMarek Vasut 		return -ENOMEM;
877bce88370SMarek Vasut 
878bce88370SMarek Vasut 	ccmd = &cctx->payload;
879bce88370SMarek Vasut 
880bce88370SMarek Vasut 	/*
881bce88370SMarek Vasut 	 * Prepare the command.
882bce88370SMarek Vasut 	 */
883bce88370SMarek Vasut 	tok = strtok(cmd->cmd, " ");
884bce88370SMarek Vasut 	if (!tok) {
885bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Missing LOAD address or 'IVT'!\n",
886bce88370SMarek Vasut 			cmd->lineno);
887bce88370SMarek Vasut 		ret = -EINVAL;
888bce88370SMarek Vasut 		goto err;
889bce88370SMarek Vasut 	}
890bce88370SMarek Vasut 
891bce88370SMarek Vasut 	/* Check for "IVT" flag. */
892bce88370SMarek Vasut 	if (!strcmp(tok, "IVT"))
893bce88370SMarek Vasut 		is_ivt = 1;
894bce88370SMarek Vasut 	if (!strcmp(tok, "DCD"))
895bce88370SMarek Vasut 		is_dcd = 1;
896bce88370SMarek Vasut 	if (is_ivt || is_dcd) {
897bce88370SMarek Vasut 		tok = strtok(NULL, " ");
898bce88370SMarek Vasut 		if (!tok) {
899bce88370SMarek Vasut 			fprintf(stderr, "#%i ERR: Missing LOAD address!\n",
900bce88370SMarek Vasut 				cmd->lineno);
901bce88370SMarek Vasut 			ret = -EINVAL;
902bce88370SMarek Vasut 			goto err;
903bce88370SMarek Vasut 		}
904bce88370SMarek Vasut 	}
905bce88370SMarek Vasut 
906bce88370SMarek Vasut 	/* Read load destination address. */
907bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &dest);
908bce88370SMarek Vasut 	if (ret) {
909bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Incorrect LOAD address!\n",
910bce88370SMarek Vasut 			cmd->lineno);
911bce88370SMarek Vasut 		goto err;
912bce88370SMarek Vasut 	}
913bce88370SMarek Vasut 
914bce88370SMarek Vasut 	/* Read filename or IVT entrypoint or DCD block ID. */
915bce88370SMarek Vasut 	tok = strtok(NULL, " ");
916bce88370SMarek Vasut 	if (!tok) {
917bce88370SMarek Vasut 		fprintf(stderr,
918bce88370SMarek Vasut 			"#%i ERR: Missing LOAD filename or IVT ep or DCD block ID!\n",
919bce88370SMarek Vasut 			cmd->lineno);
920bce88370SMarek Vasut 		ret = -EINVAL;
921bce88370SMarek Vasut 		goto err;
922bce88370SMarek Vasut 	}
923bce88370SMarek Vasut 
924bce88370SMarek Vasut 	if (is_ivt) {
925bce88370SMarek Vasut 		/* Handle IVT. */
926bce88370SMarek Vasut 		struct sb_ivt_header *ivt;
927bce88370SMarek Vasut 		uint32_t ivtep;
928bce88370SMarek Vasut 		ret = sb_token_to_long(tok, &ivtep);
929bce88370SMarek Vasut 
930bce88370SMarek Vasut 		if (ret) {
931bce88370SMarek Vasut 			fprintf(stderr,
932bce88370SMarek Vasut 				"#%i ERR: Incorrect IVT entry point!\n",
933bce88370SMarek Vasut 				cmd->lineno);
934bce88370SMarek Vasut 			goto err;
935bce88370SMarek Vasut 		}
936bce88370SMarek Vasut 
937bce88370SMarek Vasut 		ivt = calloc(1, sizeof(*ivt));
938bce88370SMarek Vasut 		if (!ivt) {
939bce88370SMarek Vasut 			ret = -ENOMEM;
940bce88370SMarek Vasut 			goto err;
941bce88370SMarek Vasut 		}
942bce88370SMarek Vasut 
943bce88370SMarek Vasut 		ivt->header = sb_hab_ivt_header();
944bce88370SMarek Vasut 		ivt->entry = ivtep;
945bce88370SMarek Vasut 		ivt->self = dest;
946bce88370SMarek Vasut 
947bce88370SMarek Vasut 		cctx->data = (uint8_t *)ivt;
948bce88370SMarek Vasut 		cctx->length = sizeof(*ivt);
949bce88370SMarek Vasut 	} else if (is_dcd) {
950bce88370SMarek Vasut 		struct sb_dcd_ctx *dctx = ictx->dcd_head;
951bce88370SMarek Vasut 		uint32_t dcdid;
952bce88370SMarek Vasut 		uint8_t *payload;
953bce88370SMarek Vasut 		uint32_t asize;
954bce88370SMarek Vasut 		ret = sb_token_to_long(tok, &dcdid);
955bce88370SMarek Vasut 
956bce88370SMarek Vasut 		if (ret) {
957bce88370SMarek Vasut 			fprintf(stderr,
958bce88370SMarek Vasut 				"#%i ERR: Incorrect DCD block ID!\n",
959bce88370SMarek Vasut 				cmd->lineno);
960bce88370SMarek Vasut 			goto err;
961bce88370SMarek Vasut 		}
962bce88370SMarek Vasut 
963bce88370SMarek Vasut 		while (dctx) {
964bce88370SMarek Vasut 			if (dctx->id == dcdid)
965bce88370SMarek Vasut 				break;
966bce88370SMarek Vasut 			dctx = dctx->dcd;
967bce88370SMarek Vasut 		}
968bce88370SMarek Vasut 
969bce88370SMarek Vasut 		if (!dctx) {
970bce88370SMarek Vasut 			fprintf(stderr, "#%i ERR: DCD block %08x not found!\n",
971bce88370SMarek Vasut 				cmd->lineno, dcdid);
972bce88370SMarek Vasut 			goto err;
973bce88370SMarek Vasut 		}
974bce88370SMarek Vasut 
975bce88370SMarek Vasut 		asize = roundup(dctx->size, SB_BLOCK_SIZE);
976bce88370SMarek Vasut 		payload = calloc(1, asize);
977bce88370SMarek Vasut 		if (!payload) {
978bce88370SMarek Vasut 			ret = -ENOMEM;
979bce88370SMarek Vasut 			goto err;
980bce88370SMarek Vasut 		}
981bce88370SMarek Vasut 
982bce88370SMarek Vasut 		memcpy(payload, dctx->payload, dctx->size);
983bce88370SMarek Vasut 
984bce88370SMarek Vasut 		cctx->data = payload;
985bce88370SMarek Vasut 		cctx->length = asize;
986bce88370SMarek Vasut 
987bce88370SMarek Vasut 		/* Set the Load DCD flag. */
988bce88370SMarek Vasut 		dcd = ROM_LOAD_CMD_FLAG_DCD_LOAD;
989bce88370SMarek Vasut 	} else {
990bce88370SMarek Vasut 		/* Regular LOAD of a file. */
991bce88370SMarek Vasut 		ret = sb_load_file(cctx, tok);
992bce88370SMarek Vasut 		if (ret) {
993bce88370SMarek Vasut 			fprintf(stderr, "#%i ERR: Cannot load '%s'!\n",
994bce88370SMarek Vasut 				cmd->lineno, tok);
995bce88370SMarek Vasut 			goto err;
996bce88370SMarek Vasut 		}
997bce88370SMarek Vasut 	}
998bce88370SMarek Vasut 
999bce88370SMarek Vasut 	if (cctx->length & (SB_BLOCK_SIZE - 1)) {
1000bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Unaligned payload!\n",
1001bce88370SMarek Vasut 			cmd->lineno);
1002bce88370SMarek Vasut 	}
1003bce88370SMarek Vasut 
1004bce88370SMarek Vasut 	/*
1005bce88370SMarek Vasut 	 * Construct the command.
1006bce88370SMarek Vasut 	 */
1007bce88370SMarek Vasut 	ccmd->header.checksum	= 0x5a;
1008bce88370SMarek Vasut 	ccmd->header.tag	= ROM_LOAD_CMD;
1009bce88370SMarek Vasut 	ccmd->header.flags	= dcd;
1010bce88370SMarek Vasut 
1011bce88370SMarek Vasut 	ccmd->load.address	= dest;
1012bce88370SMarek Vasut 	ccmd->load.count	= cctx->length;
101325308f45SCharles Manning 	ccmd->load.crc32	= pbl_crc32(0,
101425308f45SCharles Manning 					    (const char *)cctx->data,
101525308f45SCharles Manning 					    cctx->length);
1016bce88370SMarek Vasut 
1017bce88370SMarek Vasut 	cctx->size = sizeof(*ccmd) + cctx->length;
1018bce88370SMarek Vasut 
1019bce88370SMarek Vasut 	/*
1020bce88370SMarek Vasut 	 * Append the command to the last section.
1021bce88370SMarek Vasut 	 */
1022bce88370SMarek Vasut 	if (!sctx->cmd_head) {
1023bce88370SMarek Vasut 		sctx->cmd_head = cctx;
1024bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
1025bce88370SMarek Vasut 	} else {
1026bce88370SMarek Vasut 		sctx->cmd_tail->cmd = cctx;
1027bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
1028bce88370SMarek Vasut 	}
1029bce88370SMarek Vasut 
1030bce88370SMarek Vasut 	return 0;
1031bce88370SMarek Vasut 
1032bce88370SMarek Vasut err:
1033bce88370SMarek Vasut 	free(cctx);
1034bce88370SMarek Vasut 	return ret;
1035bce88370SMarek Vasut }
1036bce88370SMarek Vasut 
1037bce88370SMarek Vasut static int sb_build_command_fill(struct sb_image_ctx *ictx,
1038bce88370SMarek Vasut 				 struct sb_cmd_list *cmd)
1039bce88370SMarek Vasut {
1040bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_tail;
1041bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
1042bce88370SMarek Vasut 	struct sb_command *ccmd;
1043bce88370SMarek Vasut 	char *tok;
1044bce88370SMarek Vasut 	uint32_t address, pattern, length;
1045bce88370SMarek Vasut 	int ret;
1046bce88370SMarek Vasut 
1047bce88370SMarek Vasut 	cctx = calloc(1, sizeof(*cctx));
1048bce88370SMarek Vasut 	if (!cctx)
1049bce88370SMarek Vasut 		return -ENOMEM;
1050bce88370SMarek Vasut 
1051bce88370SMarek Vasut 	ccmd = &cctx->payload;
1052bce88370SMarek Vasut 
1053bce88370SMarek Vasut 	/*
1054bce88370SMarek Vasut 	 * Prepare the command.
1055bce88370SMarek Vasut 	 */
1056bce88370SMarek Vasut 	tok = strtok(cmd->cmd, " ");
1057bce88370SMarek Vasut 	if (!tok) {
1058bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Missing FILL address!\n",
1059bce88370SMarek Vasut 			cmd->lineno);
1060bce88370SMarek Vasut 		ret = -EINVAL;
1061bce88370SMarek Vasut 		goto err;
1062bce88370SMarek Vasut 	}
1063bce88370SMarek Vasut 
1064bce88370SMarek Vasut 	/* Read fill destination address. */
1065bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &address);
1066bce88370SMarek Vasut 	if (ret) {
1067bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Incorrect FILL address!\n",
1068bce88370SMarek Vasut 			cmd->lineno);
1069bce88370SMarek Vasut 		goto err;
1070bce88370SMarek Vasut 	}
1071bce88370SMarek Vasut 
1072bce88370SMarek Vasut 	tok = strtok(NULL, " ");
1073bce88370SMarek Vasut 	if (!tok) {
1074bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Missing FILL pattern!\n",
1075bce88370SMarek Vasut 			cmd->lineno);
1076bce88370SMarek Vasut 		ret = -EINVAL;
1077bce88370SMarek Vasut 		goto err;
1078bce88370SMarek Vasut 	}
1079bce88370SMarek Vasut 
1080bce88370SMarek Vasut 	/* Read fill pattern address. */
1081bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &pattern);
1082bce88370SMarek Vasut 	if (ret) {
1083bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Incorrect FILL pattern!\n",
1084bce88370SMarek Vasut 			cmd->lineno);
1085bce88370SMarek Vasut 		goto err;
1086bce88370SMarek Vasut 	}
1087bce88370SMarek Vasut 
1088bce88370SMarek Vasut 	tok = strtok(NULL, " ");
1089bce88370SMarek Vasut 	if (!tok) {
1090bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Missing FILL length!\n",
1091bce88370SMarek Vasut 			cmd->lineno);
1092bce88370SMarek Vasut 		ret = -EINVAL;
1093bce88370SMarek Vasut 		goto err;
1094bce88370SMarek Vasut 	}
1095bce88370SMarek Vasut 
1096bce88370SMarek Vasut 	/* Read fill pattern address. */
1097bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &length);
1098bce88370SMarek Vasut 	if (ret) {
1099bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Incorrect FILL length!\n",
1100bce88370SMarek Vasut 			cmd->lineno);
1101bce88370SMarek Vasut 		goto err;
1102bce88370SMarek Vasut 	}
1103bce88370SMarek Vasut 
1104bce88370SMarek Vasut 	/*
1105bce88370SMarek Vasut 	 * Construct the command.
1106bce88370SMarek Vasut 	 */
1107bce88370SMarek Vasut 	ccmd->header.checksum	= 0x5a;
1108bce88370SMarek Vasut 	ccmd->header.tag	= ROM_FILL_CMD;
1109bce88370SMarek Vasut 
1110bce88370SMarek Vasut 	ccmd->fill.address	= address;
1111bce88370SMarek Vasut 	ccmd->fill.count	= length;
1112bce88370SMarek Vasut 	ccmd->fill.pattern	= pattern;
1113bce88370SMarek Vasut 
1114bce88370SMarek Vasut 	cctx->size = sizeof(*ccmd);
1115bce88370SMarek Vasut 
1116bce88370SMarek Vasut 	/*
1117bce88370SMarek Vasut 	 * Append the command to the last section.
1118bce88370SMarek Vasut 	 */
1119bce88370SMarek Vasut 	if (!sctx->cmd_head) {
1120bce88370SMarek Vasut 		sctx->cmd_head = cctx;
1121bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
1122bce88370SMarek Vasut 	} else {
1123bce88370SMarek Vasut 		sctx->cmd_tail->cmd = cctx;
1124bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
1125bce88370SMarek Vasut 	}
1126bce88370SMarek Vasut 
1127bce88370SMarek Vasut 	return 0;
1128bce88370SMarek Vasut 
1129bce88370SMarek Vasut err:
1130bce88370SMarek Vasut 	free(cctx);
1131bce88370SMarek Vasut 	return ret;
1132bce88370SMarek Vasut }
1133bce88370SMarek Vasut 
1134bce88370SMarek Vasut static int sb_build_command_jump_call(struct sb_image_ctx *ictx,
1135bce88370SMarek Vasut 				      struct sb_cmd_list *cmd,
1136bce88370SMarek Vasut 				      unsigned int is_call)
1137bce88370SMarek Vasut {
1138bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_tail;
1139bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
1140bce88370SMarek Vasut 	struct sb_command *ccmd;
1141bce88370SMarek Vasut 	char *tok;
1142bce88370SMarek Vasut 	uint32_t dest, arg = 0x0;
1143bce88370SMarek Vasut 	uint32_t hab = 0;
1144bce88370SMarek Vasut 	int ret;
1145bce88370SMarek Vasut 	const char *cmdname = is_call ? "CALL" : "JUMP";
1146bce88370SMarek Vasut 
1147bce88370SMarek Vasut 	cctx = calloc(1, sizeof(*cctx));
1148bce88370SMarek Vasut 	if (!cctx)
1149bce88370SMarek Vasut 		return -ENOMEM;
1150bce88370SMarek Vasut 
1151bce88370SMarek Vasut 	ccmd = &cctx->payload;
1152bce88370SMarek Vasut 
1153bce88370SMarek Vasut 	/*
1154bce88370SMarek Vasut 	 * Prepare the command.
1155bce88370SMarek Vasut 	 */
1156bce88370SMarek Vasut 	tok = strtok(cmd->cmd, " ");
1157bce88370SMarek Vasut 	if (!tok) {
1158bce88370SMarek Vasut 		fprintf(stderr,
1159bce88370SMarek Vasut 			"#%i ERR: Missing %s address or 'HAB'!\n",
1160bce88370SMarek Vasut 			cmd->lineno, cmdname);
1161bce88370SMarek Vasut 		ret = -EINVAL;
1162bce88370SMarek Vasut 		goto err;
1163bce88370SMarek Vasut 	}
1164bce88370SMarek Vasut 
1165bce88370SMarek Vasut 	/* Check for "HAB" flag. */
1166bce88370SMarek Vasut 	if (!strcmp(tok, "HAB")) {
1167bce88370SMarek Vasut 		hab = is_call ? ROM_CALL_CMD_FLAG_HAB : ROM_JUMP_CMD_FLAG_HAB;
1168bce88370SMarek Vasut 		tok = strtok(NULL, " ");
1169bce88370SMarek Vasut 		if (!tok) {
1170bce88370SMarek Vasut 			fprintf(stderr, "#%i ERR: Missing %s address!\n",
1171bce88370SMarek Vasut 				cmd->lineno, cmdname);
1172bce88370SMarek Vasut 			ret = -EINVAL;
1173bce88370SMarek Vasut 			goto err;
1174bce88370SMarek Vasut 		}
1175bce88370SMarek Vasut 	}
1176bce88370SMarek Vasut 	/* Read load destination address. */
1177bce88370SMarek Vasut 	ret = sb_token_to_long(tok, &dest);
1178bce88370SMarek Vasut 	if (ret) {
1179bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Incorrect %s address!\n",
1180bce88370SMarek Vasut 			cmd->lineno, cmdname);
1181bce88370SMarek Vasut 		goto err;
1182bce88370SMarek Vasut 	}
1183bce88370SMarek Vasut 
1184bce88370SMarek Vasut 	tok = strtok(NULL, " ");
1185bce88370SMarek Vasut 	if (tok) {
1186bce88370SMarek Vasut 		ret = sb_token_to_long(tok, &arg);
1187bce88370SMarek Vasut 		if (ret) {
1188bce88370SMarek Vasut 			fprintf(stderr,
1189bce88370SMarek Vasut 				"#%i ERR: Incorrect %s argument!\n",
1190bce88370SMarek Vasut 				cmd->lineno, cmdname);
1191bce88370SMarek Vasut 			goto err;
1192bce88370SMarek Vasut 		}
1193bce88370SMarek Vasut 	}
1194bce88370SMarek Vasut 
1195bce88370SMarek Vasut 	/*
1196bce88370SMarek Vasut 	 * Construct the command.
1197bce88370SMarek Vasut 	 */
1198bce88370SMarek Vasut 	ccmd->header.checksum	= 0x5a;
1199bce88370SMarek Vasut 	ccmd->header.tag	= is_call ? ROM_CALL_CMD : ROM_JUMP_CMD;
1200bce88370SMarek Vasut 	ccmd->header.flags	= hab;
1201bce88370SMarek Vasut 
1202bce88370SMarek Vasut 	ccmd->call.address	= dest;
1203bce88370SMarek Vasut 	ccmd->call.argument	= arg;
1204bce88370SMarek Vasut 
1205bce88370SMarek Vasut 	cctx->size = sizeof(*ccmd);
1206bce88370SMarek Vasut 
1207bce88370SMarek Vasut 	/*
1208bce88370SMarek Vasut 	 * Append the command to the last section.
1209bce88370SMarek Vasut 	 */
1210bce88370SMarek Vasut 	if (!sctx->cmd_head) {
1211bce88370SMarek Vasut 		sctx->cmd_head = cctx;
1212bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
1213bce88370SMarek Vasut 	} else {
1214bce88370SMarek Vasut 		sctx->cmd_tail->cmd = cctx;
1215bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
1216bce88370SMarek Vasut 	}
1217bce88370SMarek Vasut 
1218bce88370SMarek Vasut 	return 0;
1219bce88370SMarek Vasut 
1220bce88370SMarek Vasut err:
1221bce88370SMarek Vasut 	free(cctx);
1222bce88370SMarek Vasut 	return ret;
1223bce88370SMarek Vasut }
1224bce88370SMarek Vasut 
1225bce88370SMarek Vasut static int sb_build_command_jump(struct sb_image_ctx *ictx,
1226bce88370SMarek Vasut 				 struct sb_cmd_list *cmd)
1227bce88370SMarek Vasut {
1228bce88370SMarek Vasut 	return sb_build_command_jump_call(ictx, cmd, 0);
1229bce88370SMarek Vasut }
1230bce88370SMarek Vasut 
1231bce88370SMarek Vasut static int sb_build_command_call(struct sb_image_ctx *ictx,
1232bce88370SMarek Vasut 				 struct sb_cmd_list *cmd)
1233bce88370SMarek Vasut {
1234bce88370SMarek Vasut 	return sb_build_command_jump_call(ictx, cmd, 1);
1235bce88370SMarek Vasut }
1236bce88370SMarek Vasut 
1237bce88370SMarek Vasut static int sb_build_command_mode(struct sb_image_ctx *ictx,
1238bce88370SMarek Vasut 				 struct sb_cmd_list *cmd)
1239bce88370SMarek Vasut {
1240bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_tail;
1241bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
1242bce88370SMarek Vasut 	struct sb_command *ccmd;
1243bce88370SMarek Vasut 	char *tok;
1244bce88370SMarek Vasut 	int ret;
1245bce88370SMarek Vasut 	unsigned int i;
1246bce88370SMarek Vasut 	uint32_t mode = 0xffffffff;
1247bce88370SMarek Vasut 
1248bce88370SMarek Vasut 	cctx = calloc(1, sizeof(*cctx));
1249bce88370SMarek Vasut 	if (!cctx)
1250bce88370SMarek Vasut 		return -ENOMEM;
1251bce88370SMarek Vasut 
1252bce88370SMarek Vasut 	ccmd = &cctx->payload;
1253bce88370SMarek Vasut 
1254bce88370SMarek Vasut 	/*
1255bce88370SMarek Vasut 	 * Prepare the command.
1256bce88370SMarek Vasut 	 */
1257bce88370SMarek Vasut 	tok = strtok(cmd->cmd, " ");
1258bce88370SMarek Vasut 	if (!tok) {
1259bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Missing MODE boot mode argument!\n",
1260bce88370SMarek Vasut 			cmd->lineno);
1261bce88370SMarek Vasut 		ret = -EINVAL;
1262bce88370SMarek Vasut 		goto err;
1263bce88370SMarek Vasut 	}
1264bce88370SMarek Vasut 
1265bce88370SMarek Vasut 	for (i = 0; i < ARRAY_SIZE(modetable); i++) {
1266bce88370SMarek Vasut 		if (!strcmp(tok, modetable[i].name)) {
1267bce88370SMarek Vasut 			mode = modetable[i].mode;
1268bce88370SMarek Vasut 			break;
1269bce88370SMarek Vasut 		}
1270bce88370SMarek Vasut 
1271bce88370SMarek Vasut 		if (!modetable[i].altname)
1272bce88370SMarek Vasut 			continue;
1273bce88370SMarek Vasut 
1274bce88370SMarek Vasut 		if (!strcmp(tok, modetable[i].altname)) {
1275bce88370SMarek Vasut 			mode = modetable[i].mode;
1276bce88370SMarek Vasut 			break;
1277bce88370SMarek Vasut 		}
1278bce88370SMarek Vasut 	}
1279bce88370SMarek Vasut 
1280bce88370SMarek Vasut 	if (mode == 0xffffffff) {
1281bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Invalid MODE boot mode argument!\n",
1282bce88370SMarek Vasut 			cmd->lineno);
1283bce88370SMarek Vasut 		ret = -EINVAL;
1284bce88370SMarek Vasut 		goto err;
1285bce88370SMarek Vasut 	}
1286bce88370SMarek Vasut 
1287bce88370SMarek Vasut 	/*
1288bce88370SMarek Vasut 	 * Construct the command.
1289bce88370SMarek Vasut 	 */
1290bce88370SMarek Vasut 	ccmd->header.checksum	= 0x5a;
1291bce88370SMarek Vasut 	ccmd->header.tag	= ROM_MODE_CMD;
1292bce88370SMarek Vasut 
1293bce88370SMarek Vasut 	ccmd->mode.mode		= mode;
1294bce88370SMarek Vasut 
1295bce88370SMarek Vasut 	cctx->size = sizeof(*ccmd);
1296bce88370SMarek Vasut 
1297bce88370SMarek Vasut 	/*
1298bce88370SMarek Vasut 	 * Append the command to the last section.
1299bce88370SMarek Vasut 	 */
1300bce88370SMarek Vasut 	if (!sctx->cmd_head) {
1301bce88370SMarek Vasut 		sctx->cmd_head = cctx;
1302bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
1303bce88370SMarek Vasut 	} else {
1304bce88370SMarek Vasut 		sctx->cmd_tail->cmd = cctx;
1305bce88370SMarek Vasut 		sctx->cmd_tail = cctx;
1306bce88370SMarek Vasut 	}
1307bce88370SMarek Vasut 
1308bce88370SMarek Vasut 	return 0;
1309bce88370SMarek Vasut 
1310bce88370SMarek Vasut err:
1311bce88370SMarek Vasut 	free(cctx);
1312bce88370SMarek Vasut 	return ret;
1313bce88370SMarek Vasut }
1314bce88370SMarek Vasut 
1315bce88370SMarek Vasut static int sb_prefill_image_header(struct sb_image_ctx *ictx)
1316bce88370SMarek Vasut {
1317bce88370SMarek Vasut 	struct sb_boot_image_header *hdr = &ictx->payload;
1318bce88370SMarek Vasut 
1319bce88370SMarek Vasut 	/* Fill signatures */
1320bce88370SMarek Vasut 	memcpy(hdr->signature1, "STMP", 4);
1321bce88370SMarek Vasut 	memcpy(hdr->signature2, "sgtl", 4);
1322bce88370SMarek Vasut 
1323bce88370SMarek Vasut 	/* SB Image version 1.1 */
1324bce88370SMarek Vasut 	hdr->major_version = SB_VERSION_MAJOR;
1325bce88370SMarek Vasut 	hdr->minor_version = SB_VERSION_MINOR;
1326bce88370SMarek Vasut 
1327bce88370SMarek Vasut 	/* Boot image major version */
1328bce88370SMarek Vasut 	hdr->product_version.major = htons(0x999);
1329bce88370SMarek Vasut 	hdr->product_version.minor = htons(0x999);
1330bce88370SMarek Vasut 	hdr->product_version.revision = htons(0x999);
1331bce88370SMarek Vasut 	/* Boot image major version */
1332bce88370SMarek Vasut 	hdr->component_version.major = htons(0x999);
1333bce88370SMarek Vasut 	hdr->component_version.minor = htons(0x999);
1334bce88370SMarek Vasut 	hdr->component_version.revision = htons(0x999);
1335bce88370SMarek Vasut 
1336bce88370SMarek Vasut 	/* Drive tag must be 0x0 for i.MX23 */
1337bce88370SMarek Vasut 	hdr->drive_tag = 0;
1338bce88370SMarek Vasut 
1339bce88370SMarek Vasut 	hdr->header_blocks =
1340bce88370SMarek Vasut 		sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE;
1341bce88370SMarek Vasut 	hdr->section_header_size =
1342bce88370SMarek Vasut 		sizeof(struct sb_sections_header) / SB_BLOCK_SIZE;
1343bce88370SMarek Vasut 	hdr->timestamp_us = sb_get_timestamp() * 1000000;
1344bce88370SMarek Vasut 
13457a139959SAlexey Ignatov 	hdr->flags = ictx->display_progress ?
13467a139959SAlexey Ignatov 		SB_IMAGE_FLAG_DISPLAY_PROGRESS : 0;
1347bce88370SMarek Vasut 
1348bce88370SMarek Vasut 	/* FIXME -- We support only default key */
1349bce88370SMarek Vasut 	hdr->key_count = 1;
1350bce88370SMarek Vasut 
1351bce88370SMarek Vasut 	return 0;
1352bce88370SMarek Vasut }
1353bce88370SMarek Vasut 
1354bce88370SMarek Vasut static int sb_postfill_image_header(struct sb_image_ctx *ictx)
1355bce88370SMarek Vasut {
1356bce88370SMarek Vasut 	struct sb_boot_image_header *hdr = &ictx->payload;
1357bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_head;
1358bce88370SMarek Vasut 	uint32_t kd_size, sections_blocks;
13597bae13b7SMarek Vasut 	EVP_MD_CTX *md_ctx;
1360bce88370SMarek Vasut 
1361bce88370SMarek Vasut 	/* The main SB header size in blocks. */
1362bce88370SMarek Vasut 	hdr->image_blocks = hdr->header_blocks;
1363bce88370SMarek Vasut 
1364bce88370SMarek Vasut 	/* Size of the key dictionary, which has single zero entry. */
1365bce88370SMarek Vasut 	kd_size = hdr->key_count * sizeof(struct sb_key_dictionary_key);
1366bce88370SMarek Vasut 	hdr->image_blocks += kd_size / SB_BLOCK_SIZE;
1367bce88370SMarek Vasut 
1368bce88370SMarek Vasut 	/* Now count the payloads. */
1369bce88370SMarek Vasut 	hdr->section_count = ictx->sect_count;
1370bce88370SMarek Vasut 	while (sctx) {
1371bce88370SMarek Vasut 		hdr->image_blocks += sctx->size / SB_BLOCK_SIZE;
1372bce88370SMarek Vasut 		sctx = sctx->sect;
1373bce88370SMarek Vasut 	}
1374bce88370SMarek Vasut 
1375bce88370SMarek Vasut 	if (!ictx->sect_boot_found) {
1376bce88370SMarek Vasut 		fprintf(stderr, "ERR: No bootable section selected!\n");
1377bce88370SMarek Vasut 		return -EINVAL;
1378bce88370SMarek Vasut 	}
1379bce88370SMarek Vasut 	hdr->first_boot_section_id = ictx->sect_boot;
1380bce88370SMarek Vasut 
1381bce88370SMarek Vasut 	/* The n * SB section size in blocks. */
1382bce88370SMarek Vasut 	sections_blocks = hdr->section_count * hdr->section_header_size;
1383bce88370SMarek Vasut 	hdr->image_blocks += sections_blocks;
1384bce88370SMarek Vasut 
1385bce88370SMarek Vasut 	/* Key dictionary offset. */
1386bce88370SMarek Vasut 	hdr->key_dictionary_block = hdr->header_blocks + sections_blocks;
1387bce88370SMarek Vasut 
1388bce88370SMarek Vasut 	/* Digest of the whole image. */
1389bce88370SMarek Vasut 	hdr->image_blocks += 2;
1390bce88370SMarek Vasut 
1391bce88370SMarek Vasut 	/* Pointer past the dictionary. */
1392bce88370SMarek Vasut 	hdr->first_boot_tag_block =
1393bce88370SMarek Vasut 		hdr->key_dictionary_block + kd_size / SB_BLOCK_SIZE;
1394bce88370SMarek Vasut 
1395bce88370SMarek Vasut 	/* Compute header digest. */
13967bae13b7SMarek Vasut 	md_ctx = EVP_MD_CTX_new();
1397bce88370SMarek Vasut 
13987bae13b7SMarek Vasut 	EVP_DigestInit(md_ctx, EVP_sha1());
13997bae13b7SMarek Vasut 	EVP_DigestUpdate(md_ctx, hdr->signature1,
1400bce88370SMarek Vasut 			 sizeof(struct sb_boot_image_header) -
1401bce88370SMarek Vasut 			 sizeof(hdr->digest));
14027bae13b7SMarek Vasut 	EVP_DigestFinal(md_ctx, hdr->digest, NULL);
14037bae13b7SMarek Vasut 	EVP_MD_CTX_free(md_ctx);
1404bce88370SMarek Vasut 
1405bce88370SMarek Vasut 	return 0;
1406bce88370SMarek Vasut }
1407bce88370SMarek Vasut 
1408bce88370SMarek Vasut static int sb_fixup_sections_and_tags(struct sb_image_ctx *ictx)
1409bce88370SMarek Vasut {
1410bce88370SMarek Vasut 	/* Fixup the placement of sections. */
1411bce88370SMarek Vasut 	struct sb_boot_image_header *ihdr = &ictx->payload;
1412bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_head;
1413bce88370SMarek Vasut 	struct sb_sections_header *shdr;
1414bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
1415bce88370SMarek Vasut 	struct sb_command *ccmd;
1416bce88370SMarek Vasut 	uint32_t offset = ihdr->first_boot_tag_block;
1417bce88370SMarek Vasut 
1418bce88370SMarek Vasut 	while (sctx) {
1419bce88370SMarek Vasut 		shdr = &sctx->payload;
1420bce88370SMarek Vasut 
1421bce88370SMarek Vasut 		/* Fill in the section TAG offset. */
1422bce88370SMarek Vasut 		shdr->section_offset = offset + 1;
1423bce88370SMarek Vasut 		offset += shdr->section_size;
1424bce88370SMarek Vasut 
1425bce88370SMarek Vasut 		/* Section length is measured from the TAG block. */
1426bce88370SMarek Vasut 		shdr->section_size--;
1427bce88370SMarek Vasut 
1428bce88370SMarek Vasut 		/* Fixup the TAG command. */
1429bce88370SMarek Vasut 		cctx = sctx->cmd_head;
1430bce88370SMarek Vasut 		while (cctx) {
1431bce88370SMarek Vasut 			ccmd = &cctx->payload;
1432bce88370SMarek Vasut 			if (ccmd->header.tag == ROM_TAG_CMD) {
1433bce88370SMarek Vasut 				ccmd->tag.section_number = shdr->section_number;
1434bce88370SMarek Vasut 				ccmd->tag.section_length = shdr->section_size;
1435bce88370SMarek Vasut 				ccmd->tag.section_flags = shdr->section_flags;
1436bce88370SMarek Vasut 			}
1437bce88370SMarek Vasut 
1438bce88370SMarek Vasut 			/* Update the command checksum. */
1439bce88370SMarek Vasut 			ccmd->header.checksum = sb_command_checksum(ccmd);
1440bce88370SMarek Vasut 
1441bce88370SMarek Vasut 			cctx = cctx->cmd;
1442bce88370SMarek Vasut 		}
1443bce88370SMarek Vasut 
1444bce88370SMarek Vasut 		sctx = sctx->sect;
1445bce88370SMarek Vasut 	}
1446bce88370SMarek Vasut 
1447bce88370SMarek Vasut 	return 0;
1448bce88370SMarek Vasut }
1449bce88370SMarek Vasut 
1450bce88370SMarek Vasut static int sb_parse_line(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
1451bce88370SMarek Vasut {
1452bce88370SMarek Vasut 	char *tok;
1453bce88370SMarek Vasut 	char *line = cmd->cmd;
14543cb4b713SAlbert ARIBAUD 	char *rptr = NULL;
1455bce88370SMarek Vasut 	int ret;
1456bce88370SMarek Vasut 
1457bce88370SMarek Vasut 	/* Analyze the identifier on this line first. */
1458bce88370SMarek Vasut 	tok = strtok_r(line, " ", &rptr);
1459bce88370SMarek Vasut 	if (!tok || (strlen(tok) == 0)) {
1460bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Invalid line!\n", cmd->lineno);
1461bce88370SMarek Vasut 		return -EINVAL;
1462bce88370SMarek Vasut 	}
1463bce88370SMarek Vasut 
1464bce88370SMarek Vasut 	cmd->cmd = rptr;
1465bce88370SMarek Vasut 
14667a139959SAlexey Ignatov 	/* set DISPLAY_PROGRESS flag */
14677a139959SAlexey Ignatov 	if (!strcmp(tok, "DISPLAYPROGRESS")) {
14687a139959SAlexey Ignatov 		ictx->display_progress = 1;
14697a139959SAlexey Ignatov 		return 0;
14707a139959SAlexey Ignatov 	}
14717a139959SAlexey Ignatov 
1472bce88370SMarek Vasut 	/* DCD */
1473bce88370SMarek Vasut 	if (!strcmp(tok, "DCD")) {
1474bce88370SMarek Vasut 		ictx->in_section = 0;
1475bce88370SMarek Vasut 		ictx->in_dcd = 1;
1476bce88370SMarek Vasut 		sb_build_dcd(ictx, cmd);
1477bce88370SMarek Vasut 		return 0;
1478bce88370SMarek Vasut 	}
1479bce88370SMarek Vasut 
1480bce88370SMarek Vasut 	/* Section */
1481bce88370SMarek Vasut 	if (!strcmp(tok, "SECTION")) {
1482bce88370SMarek Vasut 		ictx->in_section = 1;
1483bce88370SMarek Vasut 		ictx->in_dcd = 0;
1484bce88370SMarek Vasut 		sb_build_section(ictx, cmd);
1485bce88370SMarek Vasut 		return 0;
1486bce88370SMarek Vasut 	}
1487bce88370SMarek Vasut 
1488bce88370SMarek Vasut 	if (!ictx->in_section && !ictx->in_dcd) {
1489bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Data outside of a section!\n",
1490bce88370SMarek Vasut 			cmd->lineno);
1491bce88370SMarek Vasut 		return -EINVAL;
1492bce88370SMarek Vasut 	}
1493bce88370SMarek Vasut 
1494bce88370SMarek Vasut 	if (ictx->in_section) {
1495bce88370SMarek Vasut 		/* Section commands */
1496bce88370SMarek Vasut 		if (!strcmp(tok, "NOP")) {
1497bce88370SMarek Vasut 			ret = sb_build_command_nop(ictx);
1498bce88370SMarek Vasut 		} else if (!strcmp(tok, "TAG")) {
1499bce88370SMarek Vasut 			ret = sb_build_command_tag(ictx, cmd);
1500bce88370SMarek Vasut 		} else if (!strcmp(tok, "LOAD")) {
1501bce88370SMarek Vasut 			ret = sb_build_command_load(ictx, cmd);
1502bce88370SMarek Vasut 		} else if (!strcmp(tok, "FILL")) {
1503bce88370SMarek Vasut 			ret = sb_build_command_fill(ictx, cmd);
1504bce88370SMarek Vasut 		} else if (!strcmp(tok, "JUMP")) {
1505bce88370SMarek Vasut 			ret = sb_build_command_jump(ictx, cmd);
1506bce88370SMarek Vasut 		} else if (!strcmp(tok, "CALL")) {
1507bce88370SMarek Vasut 			ret = sb_build_command_call(ictx, cmd);
1508bce88370SMarek Vasut 		} else if (!strcmp(tok, "MODE")) {
1509bce88370SMarek Vasut 			ret = sb_build_command_mode(ictx, cmd);
1510bce88370SMarek Vasut 		} else {
1511bce88370SMarek Vasut 			fprintf(stderr,
1512bce88370SMarek Vasut 				"#%i ERR: Unsupported instruction '%s'!\n",
1513bce88370SMarek Vasut 				cmd->lineno, tok);
1514bce88370SMarek Vasut 			return -ENOTSUP;
1515bce88370SMarek Vasut 		}
1516bce88370SMarek Vasut 	} else if (ictx->in_dcd) {
1517bce88370SMarek Vasut 		char *lptr;
1518bce88370SMarek Vasut 		uint32_t ilen = '1';
1519bce88370SMarek Vasut 
1520bce88370SMarek Vasut 		tok = strtok_r(tok, ".", &lptr);
1521bce88370SMarek Vasut 		if (!tok || (strlen(tok) == 0) || (lptr && strlen(lptr) != 1)) {
1522bce88370SMarek Vasut 			fprintf(stderr, "#%i ERR: Invalid line!\n",
1523bce88370SMarek Vasut 				cmd->lineno);
1524bce88370SMarek Vasut 			return -EINVAL;
1525bce88370SMarek Vasut 		}
1526bce88370SMarek Vasut 
1527bce88370SMarek Vasut 		if (lptr &&
1528bce88370SMarek Vasut 		    (lptr[0] != '1' && lptr[0] != '2' && lptr[0] != '4')) {
1529bce88370SMarek Vasut 			fprintf(stderr, "#%i ERR: Invalid instruction width!\n",
1530bce88370SMarek Vasut 				cmd->lineno);
1531bce88370SMarek Vasut 			return -EINVAL;
1532bce88370SMarek Vasut 		}
1533bce88370SMarek Vasut 
1534bce88370SMarek Vasut 		if (lptr)
1535bce88370SMarek Vasut 			ilen = lptr[0] - '1';
1536bce88370SMarek Vasut 
1537bce88370SMarek Vasut 		/* DCD commands */
1538bce88370SMarek Vasut 		if (!strcmp(tok, "WRITE")) {
1539bce88370SMarek Vasut 			ret = sb_build_dcd_block(ictx, cmd,
1540bce88370SMarek Vasut 						 SB_DCD_WRITE | ilen);
1541bce88370SMarek Vasut 		} else if (!strcmp(tok, "ANDC")) {
1542bce88370SMarek Vasut 			ret = sb_build_dcd_block(ictx, cmd,
1543bce88370SMarek Vasut 						 SB_DCD_ANDC | ilen);
1544bce88370SMarek Vasut 		} else if (!strcmp(tok, "ORR")) {
1545bce88370SMarek Vasut 			ret = sb_build_dcd_block(ictx, cmd,
1546bce88370SMarek Vasut 						 SB_DCD_ORR | ilen);
1547bce88370SMarek Vasut 		} else if (!strcmp(tok, "EQZ")) {
1548bce88370SMarek Vasut 			ret = sb_build_dcd_block(ictx, cmd,
1549bce88370SMarek Vasut 						 SB_DCD_CHK_EQZ | ilen);
1550bce88370SMarek Vasut 		} else if (!strcmp(tok, "EQ")) {
1551bce88370SMarek Vasut 			ret = sb_build_dcd_block(ictx, cmd,
1552bce88370SMarek Vasut 						 SB_DCD_CHK_EQ | ilen);
1553bce88370SMarek Vasut 		} else if (!strcmp(tok, "NEQ")) {
1554bce88370SMarek Vasut 			ret = sb_build_dcd_block(ictx, cmd,
1555bce88370SMarek Vasut 						 SB_DCD_CHK_NEQ | ilen);
1556bce88370SMarek Vasut 		} else if (!strcmp(tok, "NEZ")) {
1557bce88370SMarek Vasut 			ret = sb_build_dcd_block(ictx, cmd,
1558bce88370SMarek Vasut 						 SB_DCD_CHK_NEZ | ilen);
1559bce88370SMarek Vasut 		} else if (!strcmp(tok, "NOOP")) {
1560bce88370SMarek Vasut 			ret = sb_build_dcd_block(ictx, cmd, SB_DCD_NOOP);
1561bce88370SMarek Vasut 		} else {
1562bce88370SMarek Vasut 			fprintf(stderr,
1563bce88370SMarek Vasut 				"#%i ERR: Unsupported instruction '%s'!\n",
1564bce88370SMarek Vasut 				cmd->lineno, tok);
1565bce88370SMarek Vasut 			return -ENOTSUP;
1566bce88370SMarek Vasut 		}
1567bce88370SMarek Vasut 	} else {
1568bce88370SMarek Vasut 		fprintf(stderr, "#%i ERR: Unsupported instruction '%s'!\n",
1569bce88370SMarek Vasut 			cmd->lineno, tok);
1570bce88370SMarek Vasut 		return -ENOTSUP;
1571bce88370SMarek Vasut 	}
1572bce88370SMarek Vasut 
1573bce88370SMarek Vasut 	/*
1574bce88370SMarek Vasut 	 * Here we have at least one section with one command, otherwise we
1575bce88370SMarek Vasut 	 * would have failed already higher above.
1576bce88370SMarek Vasut 	 *
1577bce88370SMarek Vasut 	 * FIXME -- should the updating happen here ?
1578bce88370SMarek Vasut 	 */
1579bce88370SMarek Vasut 	if (ictx->in_section && !ret) {
1580bce88370SMarek Vasut 		ictx->sect_tail->size += ictx->sect_tail->cmd_tail->size;
1581bce88370SMarek Vasut 		ictx->sect_tail->payload.section_size =
1582bce88370SMarek Vasut 			ictx->sect_tail->size / SB_BLOCK_SIZE;
1583bce88370SMarek Vasut 	}
1584bce88370SMarek Vasut 
1585bce88370SMarek Vasut 	return ret;
1586bce88370SMarek Vasut }
1587bce88370SMarek Vasut 
1588bce88370SMarek Vasut static int sb_load_cmdfile(struct sb_image_ctx *ictx)
1589bce88370SMarek Vasut {
1590bce88370SMarek Vasut 	struct sb_cmd_list cmd;
1591bce88370SMarek Vasut 	int lineno = 1;
1592bce88370SMarek Vasut 	FILE *fp;
1593bce88370SMarek Vasut 	char *line = NULL;
1594bce88370SMarek Vasut 	ssize_t rlen;
1595bce88370SMarek Vasut 	size_t len;
1596bce88370SMarek Vasut 
1597bce88370SMarek Vasut 	fp = fopen(ictx->cfg_filename, "r");
1598bce88370SMarek Vasut 	if (!fp)
1599bce88370SMarek Vasut 		goto err_file;
1600bce88370SMarek Vasut 
1601bce88370SMarek Vasut 	while ((rlen = getline(&line, &len, fp)) > 0) {
1602bce88370SMarek Vasut 		memset(&cmd, 0, sizeof(cmd));
1603bce88370SMarek Vasut 
1604bce88370SMarek Vasut 		/* Strip the trailing newline. */
1605bce88370SMarek Vasut 		line[rlen - 1] = '\0';
1606bce88370SMarek Vasut 
1607bce88370SMarek Vasut 		cmd.cmd = line;
1608bce88370SMarek Vasut 		cmd.len = rlen;
1609bce88370SMarek Vasut 		cmd.lineno = lineno++;
1610bce88370SMarek Vasut 
1611bce88370SMarek Vasut 		sb_parse_line(ictx, &cmd);
1612bce88370SMarek Vasut 	}
1613bce88370SMarek Vasut 
1614bce88370SMarek Vasut 	free(line);
1615bce88370SMarek Vasut 
1616bce88370SMarek Vasut 	fclose(fp);
1617bce88370SMarek Vasut 
1618bce88370SMarek Vasut 	return 0;
1619bce88370SMarek Vasut 
1620bce88370SMarek Vasut err_file:
1621bce88370SMarek Vasut 	fclose(fp);
1622bce88370SMarek Vasut 	fprintf(stderr, "ERR: Failed to load file \"%s\"\n",
1623bce88370SMarek Vasut 		ictx->cfg_filename);
1624bce88370SMarek Vasut 	return -EINVAL;
1625bce88370SMarek Vasut }
1626bce88370SMarek Vasut 
1627bce88370SMarek Vasut static int sb_build_tree_from_cfg(struct sb_image_ctx *ictx)
1628bce88370SMarek Vasut {
1629bce88370SMarek Vasut 	int ret;
1630bce88370SMarek Vasut 
1631bce88370SMarek Vasut 	ret = sb_load_cmdfile(ictx);
1632bce88370SMarek Vasut 	if (ret)
1633bce88370SMarek Vasut 		return ret;
1634bce88370SMarek Vasut 
1635bce88370SMarek Vasut 	ret = sb_prefill_image_header(ictx);
1636bce88370SMarek Vasut 	if (ret)
1637bce88370SMarek Vasut 		return ret;
1638bce88370SMarek Vasut 
1639bce88370SMarek Vasut 	ret = sb_postfill_image_header(ictx);
1640bce88370SMarek Vasut 	if (ret)
1641bce88370SMarek Vasut 		return ret;
1642bce88370SMarek Vasut 
1643bce88370SMarek Vasut 	ret = sb_fixup_sections_and_tags(ictx);
1644bce88370SMarek Vasut 	if (ret)
1645bce88370SMarek Vasut 		return ret;
1646bce88370SMarek Vasut 
1647bce88370SMarek Vasut 	return 0;
1648bce88370SMarek Vasut }
1649bce88370SMarek Vasut 
1650bce88370SMarek Vasut static int sb_verify_image_header(struct sb_image_ctx *ictx,
1651bce88370SMarek Vasut 				  FILE *fp, long fsize)
1652bce88370SMarek Vasut {
1653bce88370SMarek Vasut 	/* Verify static fields in the image header. */
1654bce88370SMarek Vasut 	struct sb_boot_image_header *hdr = &ictx->payload;
1655bce88370SMarek Vasut 	const char *stat[2] = { "[PASS]", "[FAIL]" };
1656bce88370SMarek Vasut 	struct tm tm;
1657bce88370SMarek Vasut 	int sz, ret = 0;
1658bce88370SMarek Vasut 	unsigned char digest[20];
16597bae13b7SMarek Vasut 	EVP_MD_CTX *md_ctx;
1660bce88370SMarek Vasut 	unsigned long size;
1661bce88370SMarek Vasut 
1662bce88370SMarek Vasut 	/* Start image-wide crypto. */
16637bae13b7SMarek Vasut 	ictx->md_ctx = EVP_MD_CTX_new();
16647bae13b7SMarek Vasut 	EVP_DigestInit(ictx->md_ctx, EVP_sha1());
1665bce88370SMarek Vasut 
1666bce88370SMarek Vasut 	soprintf(ictx, "---------- Verifying SB Image Header ----------\n");
1667bce88370SMarek Vasut 
1668bce88370SMarek Vasut 	size = fread(&ictx->payload, 1, sizeof(ictx->payload), fp);
1669bce88370SMarek Vasut 	if (size != sizeof(ictx->payload)) {
1670bce88370SMarek Vasut 		fprintf(stderr, "ERR: SB image header too short!\n");
1671bce88370SMarek Vasut 		return -EINVAL;
1672bce88370SMarek Vasut 	}
1673bce88370SMarek Vasut 
1674bce88370SMarek Vasut 	/* Compute header digest. */
16757bae13b7SMarek Vasut 	md_ctx = EVP_MD_CTX_new();
16767bae13b7SMarek Vasut 	EVP_DigestInit(md_ctx, EVP_sha1());
16777bae13b7SMarek Vasut 	EVP_DigestUpdate(md_ctx, hdr->signature1,
1678bce88370SMarek Vasut 			 sizeof(struct sb_boot_image_header) -
1679bce88370SMarek Vasut 			 sizeof(hdr->digest));
16807bae13b7SMarek Vasut 	EVP_DigestFinal(md_ctx, digest, NULL);
16817bae13b7SMarek Vasut 	EVP_MD_CTX_free(md_ctx);
1682bce88370SMarek Vasut 
1683bce88370SMarek Vasut 	sb_aes_init(ictx, NULL, 1);
1684bce88370SMarek Vasut 	sb_encrypt_sb_header(ictx);
1685bce88370SMarek Vasut 
1686bce88370SMarek Vasut 	if (memcmp(digest, hdr->digest, 20))
1687bce88370SMarek Vasut 		ret = -EINVAL;
1688bce88370SMarek Vasut 	soprintf(ictx, "%s Image header checksum:        %s\n", stat[!!ret],
1689bce88370SMarek Vasut 		 ret ? "BAD" : "OK");
1690bce88370SMarek Vasut 	if (ret)
1691bce88370SMarek Vasut 		return ret;
1692bce88370SMarek Vasut 
1693bce88370SMarek Vasut 	if (memcmp(hdr->signature1, "STMP", 4) ||
1694bce88370SMarek Vasut 	    memcmp(hdr->signature2, "sgtl", 4))
1695bce88370SMarek Vasut 		ret = -EINVAL;
1696bce88370SMarek Vasut 	soprintf(ictx, "%s Signatures:                   '%.4s' '%.4s'\n",
1697bce88370SMarek Vasut 		 stat[!!ret], hdr->signature1, hdr->signature2);
1698bce88370SMarek Vasut 	if (ret)
1699bce88370SMarek Vasut 		return ret;
1700bce88370SMarek Vasut 
1701bce88370SMarek Vasut 	if ((hdr->major_version != SB_VERSION_MAJOR) ||
1702bce88370SMarek Vasut 	    ((hdr->minor_version != 1) && (hdr->minor_version != 2)))
1703bce88370SMarek Vasut 		ret = -EINVAL;
1704bce88370SMarek Vasut 	soprintf(ictx, "%s Image version:                v%i.%i\n", stat[!!ret],
1705bce88370SMarek Vasut 		 hdr->major_version, hdr->minor_version);
1706bce88370SMarek Vasut 	if (ret)
1707bce88370SMarek Vasut 		return ret;
1708bce88370SMarek Vasut 
1709bce88370SMarek Vasut 	ret = sb_get_time(hdr->timestamp_us / 1000000, &tm);
1710bce88370SMarek Vasut 	soprintf(ictx,
1711bce88370SMarek Vasut 		 "%s Creation time:                %02i:%02i:%02i %02i/%02i/%04i\n",
1712bce88370SMarek Vasut 		 stat[!!ret], tm.tm_hour, tm.tm_min, tm.tm_sec,
1713bce88370SMarek Vasut 		 tm.tm_mday, tm.tm_mon, tm.tm_year + 2000);
1714bce88370SMarek Vasut 	if (ret)
1715bce88370SMarek Vasut 		return ret;
1716bce88370SMarek Vasut 
1717bce88370SMarek Vasut 	soprintf(ictx, "%s Product version:              %x.%x.%x\n", stat[0],
1718bce88370SMarek Vasut 		 ntohs(hdr->product_version.major),
1719bce88370SMarek Vasut 		 ntohs(hdr->product_version.minor),
1720bce88370SMarek Vasut 		 ntohs(hdr->product_version.revision));
1721bce88370SMarek Vasut 	soprintf(ictx, "%s Component version:            %x.%x.%x\n", stat[0],
1722bce88370SMarek Vasut 		 ntohs(hdr->component_version.major),
1723bce88370SMarek Vasut 		 ntohs(hdr->component_version.minor),
1724bce88370SMarek Vasut 		 ntohs(hdr->component_version.revision));
1725bce88370SMarek Vasut 
17267a139959SAlexey Ignatov 	if (hdr->flags & ~SB_IMAGE_FLAGS_MASK)
1727bce88370SMarek Vasut 		ret = -EINVAL;
1728bce88370SMarek Vasut 	soprintf(ictx, "%s Image flags:                  %s\n", stat[!!ret],
17297a139959SAlexey Ignatov 		 hdr->flags & SB_IMAGE_FLAG_DISPLAY_PROGRESS ?
17307a139959SAlexey Ignatov 		 "Display_progress" : "");
1731bce88370SMarek Vasut 	if (ret)
1732bce88370SMarek Vasut 		return ret;
1733bce88370SMarek Vasut 
1734bce88370SMarek Vasut 	if (hdr->drive_tag != 0)
1735bce88370SMarek Vasut 		ret = -EINVAL;
1736bce88370SMarek Vasut 	soprintf(ictx, "%s Drive tag:                    %i\n", stat[!!ret],
1737bce88370SMarek Vasut 		 hdr->drive_tag);
1738bce88370SMarek Vasut 	if (ret)
1739bce88370SMarek Vasut 		return ret;
1740bce88370SMarek Vasut 
1741bce88370SMarek Vasut 	sz = sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE;
1742bce88370SMarek Vasut 	if (hdr->header_blocks != sz)
1743bce88370SMarek Vasut 		ret = -EINVAL;
1744bce88370SMarek Vasut 	soprintf(ictx, "%s Image header size (blocks):   %i\n", stat[!!ret],
1745bce88370SMarek Vasut 		 hdr->header_blocks);
1746bce88370SMarek Vasut 	if (ret)
1747bce88370SMarek Vasut 		return ret;
1748bce88370SMarek Vasut 
1749bce88370SMarek Vasut 	sz = sizeof(struct sb_sections_header) / SB_BLOCK_SIZE;
1750bce88370SMarek Vasut 	if (hdr->section_header_size != sz)
1751bce88370SMarek Vasut 		ret = -EINVAL;
1752bce88370SMarek Vasut 	soprintf(ictx, "%s Section header size (blocks): %i\n", stat[!!ret],
1753bce88370SMarek Vasut 		 hdr->section_header_size);
1754bce88370SMarek Vasut 	if (ret)
1755bce88370SMarek Vasut 		return ret;
1756bce88370SMarek Vasut 
1757bce88370SMarek Vasut 	soprintf(ictx, "%s Sections count:               %i\n", stat[!!ret],
1758bce88370SMarek Vasut 		 hdr->section_count);
1759bce88370SMarek Vasut 	soprintf(ictx, "%s First bootable section        %i\n", stat[!!ret],
1760bce88370SMarek Vasut 		 hdr->first_boot_section_id);
1761bce88370SMarek Vasut 
1762bce88370SMarek Vasut 	if (hdr->image_blocks != fsize / SB_BLOCK_SIZE)
1763bce88370SMarek Vasut 		ret = -EINVAL;
1764bce88370SMarek Vasut 	soprintf(ictx, "%s Image size (blocks):          %i\n", stat[!!ret],
1765bce88370SMarek Vasut 		 hdr->image_blocks);
1766bce88370SMarek Vasut 	if (ret)
1767bce88370SMarek Vasut 		return ret;
1768bce88370SMarek Vasut 
1769bce88370SMarek Vasut 	sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count;
1770bce88370SMarek Vasut 	if (hdr->key_dictionary_block != sz)
1771bce88370SMarek Vasut 		ret = -EINVAL;
1772bce88370SMarek Vasut 	soprintf(ictx, "%s Key dict offset (blocks):     %i\n", stat[!!ret],
1773bce88370SMarek Vasut 		 hdr->key_dictionary_block);
1774bce88370SMarek Vasut 	if (ret)
1775bce88370SMarek Vasut 		return ret;
1776bce88370SMarek Vasut 
1777bce88370SMarek Vasut 	if (hdr->key_count != 1)
1778bce88370SMarek Vasut 		ret = -EINVAL;
1779bce88370SMarek Vasut 	soprintf(ictx, "%s Number of encryption keys:    %i\n", stat[!!ret],
1780bce88370SMarek Vasut 		 hdr->key_count);
1781bce88370SMarek Vasut 	if (ret)
1782bce88370SMarek Vasut 		return ret;
1783bce88370SMarek Vasut 
1784bce88370SMarek Vasut 	sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count;
1785bce88370SMarek Vasut 	sz += hdr->key_count *
1786bce88370SMarek Vasut 		sizeof(struct sb_key_dictionary_key) / SB_BLOCK_SIZE;
1787bce88370SMarek Vasut 	if (hdr->first_boot_tag_block != (unsigned)sz)
1788bce88370SMarek Vasut 		ret = -EINVAL;
1789bce88370SMarek Vasut 	soprintf(ictx, "%s First TAG block (blocks):     %i\n", stat[!!ret],
1790bce88370SMarek Vasut 		 hdr->first_boot_tag_block);
1791bce88370SMarek Vasut 	if (ret)
1792bce88370SMarek Vasut 		return ret;
1793bce88370SMarek Vasut 
1794bce88370SMarek Vasut 	return 0;
1795bce88370SMarek Vasut }
1796bce88370SMarek Vasut 
1797bce88370SMarek Vasut static void sb_decrypt_tag(struct sb_image_ctx *ictx,
1798bce88370SMarek Vasut 		struct sb_cmd_ctx *cctx)
1799bce88370SMarek Vasut {
18007bae13b7SMarek Vasut 	EVP_MD_CTX *md_ctx = ictx->md_ctx;
1801bce88370SMarek Vasut 	struct sb_command *cmd = &cctx->payload;
1802bce88370SMarek Vasut 
1803bce88370SMarek Vasut 	sb_aes_crypt(ictx, (uint8_t *)&cctx->c_payload,
1804bce88370SMarek Vasut 		     (uint8_t *)&cctx->payload, sizeof(*cmd));
1805bce88370SMarek Vasut 	EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd));
1806bce88370SMarek Vasut }
1807bce88370SMarek Vasut 
1808bce88370SMarek Vasut static int sb_verify_command(struct sb_image_ctx *ictx,
1809bce88370SMarek Vasut 			     struct sb_cmd_ctx *cctx, FILE *fp,
1810bce88370SMarek Vasut 			     unsigned long *tsize)
1811bce88370SMarek Vasut {
1812bce88370SMarek Vasut 	struct sb_command *ccmd = &cctx->payload;
1813bce88370SMarek Vasut 	unsigned long size, asize;
1814bce88370SMarek Vasut 	char *csum, *flag = "";
1815bce88370SMarek Vasut 	int ret;
1816bce88370SMarek Vasut 	unsigned int i;
1817bce88370SMarek Vasut 	uint8_t csn, csc = ccmd->header.checksum;
1818bce88370SMarek Vasut 	ccmd->header.checksum = 0x5a;
1819bce88370SMarek Vasut 	csn = sb_command_checksum(ccmd);
1820bce88370SMarek Vasut 	ccmd->header.checksum = csc;
1821bce88370SMarek Vasut 
1822bce88370SMarek Vasut 	if (csc == csn)
1823bce88370SMarek Vasut 		ret = 0;
1824bce88370SMarek Vasut 	else
1825bce88370SMarek Vasut 		ret = -EINVAL;
1826bce88370SMarek Vasut 	csum = ret ? "checksum BAD" : "checksum OK";
1827bce88370SMarek Vasut 
1828bce88370SMarek Vasut 	switch (ccmd->header.tag) {
1829bce88370SMarek Vasut 	case ROM_NOP_CMD:
1830bce88370SMarek Vasut 		soprintf(ictx, " NOOP # %s\n", csum);
1831bce88370SMarek Vasut 		return ret;
1832bce88370SMarek Vasut 	case ROM_TAG_CMD:
1833bce88370SMarek Vasut 		if (ccmd->header.flags & ROM_TAG_CMD_FLAG_ROM_LAST_TAG)
1834bce88370SMarek Vasut 			flag = "LAST";
1835bce88370SMarek Vasut 		soprintf(ictx, " TAG %s # %s\n", flag, csum);
1836bce88370SMarek Vasut 		sb_aes_reinit(ictx, 0);
1837bce88370SMarek Vasut 		return ret;
1838bce88370SMarek Vasut 	case ROM_LOAD_CMD:
1839bce88370SMarek Vasut 		soprintf(ictx, " LOAD addr=0x%08x length=0x%08x # %s\n",
1840bce88370SMarek Vasut 			 ccmd->load.address, ccmd->load.count, csum);
1841bce88370SMarek Vasut 
1842bce88370SMarek Vasut 		cctx->length = ccmd->load.count;
1843bce88370SMarek Vasut 		asize = roundup(cctx->length, SB_BLOCK_SIZE);
1844bce88370SMarek Vasut 		cctx->data = malloc(asize);
1845bce88370SMarek Vasut 		if (!cctx->data)
1846bce88370SMarek Vasut 			return -ENOMEM;
1847bce88370SMarek Vasut 
1848bce88370SMarek Vasut 		size = fread(cctx->data, 1, asize, fp);
1849bce88370SMarek Vasut 		if (size != asize) {
1850bce88370SMarek Vasut 			fprintf(stderr,
1851bce88370SMarek Vasut 				"ERR: SB LOAD command payload too short!\n");
1852bce88370SMarek Vasut 			return -EINVAL;
1853bce88370SMarek Vasut 		}
1854bce88370SMarek Vasut 
1855bce88370SMarek Vasut 		*tsize += size;
1856bce88370SMarek Vasut 
18577bae13b7SMarek Vasut 		EVP_DigestUpdate(ictx->md_ctx, cctx->data, asize);
1858bce88370SMarek Vasut 		sb_aes_crypt(ictx, cctx->data, cctx->data, asize);
1859bce88370SMarek Vasut 
186025308f45SCharles Manning 		if (ccmd->load.crc32 != pbl_crc32(0,
186125308f45SCharles Manning 						  (const char *)cctx->data,
186225308f45SCharles Manning 						  asize)) {
1863bce88370SMarek Vasut 			fprintf(stderr,
1864bce88370SMarek Vasut 				"ERR: SB LOAD command payload CRC32 invalid!\n");
1865bce88370SMarek Vasut 			return -EINVAL;
1866bce88370SMarek Vasut 		}
1867bce88370SMarek Vasut 		return 0;
1868bce88370SMarek Vasut 	case ROM_FILL_CMD:
1869bce88370SMarek Vasut 		soprintf(ictx,
1870bce88370SMarek Vasut 			 " FILL addr=0x%08x length=0x%08x pattern=0x%08x # %s\n",
1871bce88370SMarek Vasut 			 ccmd->fill.address, ccmd->fill.count,
1872bce88370SMarek Vasut 			 ccmd->fill.pattern, csum);
1873bce88370SMarek Vasut 		return 0;
1874bce88370SMarek Vasut 	case ROM_JUMP_CMD:
1875bce88370SMarek Vasut 		if (ccmd->header.flags & ROM_JUMP_CMD_FLAG_HAB)
1876bce88370SMarek Vasut 			flag = " HAB";
1877bce88370SMarek Vasut 		soprintf(ictx,
1878bce88370SMarek Vasut 			 " JUMP%s addr=0x%08x r0_arg=0x%08x # %s\n",
1879bce88370SMarek Vasut 			 flag, ccmd->fill.address, ccmd->jump.argument, csum);
1880bce88370SMarek Vasut 		return 0;
1881bce88370SMarek Vasut 	case ROM_CALL_CMD:
1882bce88370SMarek Vasut 		if (ccmd->header.flags & ROM_CALL_CMD_FLAG_HAB)
1883bce88370SMarek Vasut 			flag = " HAB";
1884bce88370SMarek Vasut 		soprintf(ictx,
1885bce88370SMarek Vasut 			 " CALL%s addr=0x%08x r0_arg=0x%08x # %s\n",
1886bce88370SMarek Vasut 			 flag, ccmd->fill.address, ccmd->jump.argument, csum);
1887bce88370SMarek Vasut 		return 0;
1888bce88370SMarek Vasut 	case ROM_MODE_CMD:
1889bce88370SMarek Vasut 		for (i = 0; i < ARRAY_SIZE(modetable); i++) {
1890bce88370SMarek Vasut 			if (ccmd->mode.mode == modetable[i].mode) {
1891bce88370SMarek Vasut 				soprintf(ictx, " MODE %s # %s\n",
1892bce88370SMarek Vasut 					 modetable[i].name, csum);
1893bce88370SMarek Vasut 				break;
1894bce88370SMarek Vasut 			}
1895bce88370SMarek Vasut 		}
1896bce88370SMarek Vasut 		fprintf(stderr, " MODE !INVALID! # %s\n", csum);
1897bce88370SMarek Vasut 		return 0;
1898bce88370SMarek Vasut 	}
1899bce88370SMarek Vasut 
1900bce88370SMarek Vasut 	return ret;
1901bce88370SMarek Vasut }
1902bce88370SMarek Vasut 
1903bce88370SMarek Vasut static int sb_verify_commands(struct sb_image_ctx *ictx,
1904bce88370SMarek Vasut 			      struct sb_section_ctx *sctx, FILE *fp)
1905bce88370SMarek Vasut {
1906bce88370SMarek Vasut 	unsigned long size, tsize = 0;
1907bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
1908bce88370SMarek Vasut 	int ret;
1909bce88370SMarek Vasut 
1910bce88370SMarek Vasut 	sb_aes_reinit(ictx, 0);
1911bce88370SMarek Vasut 
1912bce88370SMarek Vasut 	while (tsize < sctx->size) {
1913bce88370SMarek Vasut 		cctx = calloc(1, sizeof(*cctx));
1914bce88370SMarek Vasut 		if (!cctx)
1915bce88370SMarek Vasut 			return -ENOMEM;
1916bce88370SMarek Vasut 		if (!sctx->cmd_head) {
1917bce88370SMarek Vasut 			sctx->cmd_head = cctx;
1918bce88370SMarek Vasut 			sctx->cmd_tail = cctx;
1919bce88370SMarek Vasut 		} else {
1920bce88370SMarek Vasut 			sctx->cmd_tail->cmd = cctx;
1921bce88370SMarek Vasut 			sctx->cmd_tail = cctx;
1922bce88370SMarek Vasut 		}
1923bce88370SMarek Vasut 
1924bce88370SMarek Vasut 		size = fread(&cctx->c_payload, 1, sizeof(cctx->c_payload), fp);
1925bce88370SMarek Vasut 		if (size != sizeof(cctx->c_payload)) {
1926bce88370SMarek Vasut 			fprintf(stderr, "ERR: SB command header too short!\n");
1927bce88370SMarek Vasut 			return -EINVAL;
1928bce88370SMarek Vasut 		}
1929bce88370SMarek Vasut 
1930bce88370SMarek Vasut 		tsize += size;
1931bce88370SMarek Vasut 
1932bce88370SMarek Vasut 		sb_decrypt_tag(ictx, cctx);
1933bce88370SMarek Vasut 
1934bce88370SMarek Vasut 		ret = sb_verify_command(ictx, cctx, fp, &tsize);
1935bce88370SMarek Vasut 		if (ret)
1936bce88370SMarek Vasut 			return -EINVAL;
1937bce88370SMarek Vasut 	}
1938bce88370SMarek Vasut 
1939bce88370SMarek Vasut 	return 0;
1940bce88370SMarek Vasut }
1941bce88370SMarek Vasut 
1942bce88370SMarek Vasut static int sb_verify_sections_cmds(struct sb_image_ctx *ictx, FILE *fp)
1943bce88370SMarek Vasut {
1944bce88370SMarek Vasut 	struct sb_boot_image_header *hdr = &ictx->payload;
1945bce88370SMarek Vasut 	struct sb_sections_header *shdr;
1946bce88370SMarek Vasut 	unsigned int i;
1947bce88370SMarek Vasut 	int ret;
1948bce88370SMarek Vasut 	struct sb_section_ctx *sctx;
1949bce88370SMarek Vasut 	unsigned long size;
1950bce88370SMarek Vasut 	char *bootable = "";
1951bce88370SMarek Vasut 
1952bce88370SMarek Vasut 	soprintf(ictx, "----- Verifying  SB Sections and Commands -----\n");
1953bce88370SMarek Vasut 
1954bce88370SMarek Vasut 	for (i = 0; i < hdr->section_count; i++) {
1955bce88370SMarek Vasut 		sctx = calloc(1, sizeof(*sctx));
1956bce88370SMarek Vasut 		if (!sctx)
1957bce88370SMarek Vasut 			return -ENOMEM;
1958bce88370SMarek Vasut 		if (!ictx->sect_head) {
1959bce88370SMarek Vasut 			ictx->sect_head = sctx;
1960bce88370SMarek Vasut 			ictx->sect_tail = sctx;
1961bce88370SMarek Vasut 		} else {
1962bce88370SMarek Vasut 			ictx->sect_tail->sect = sctx;
1963bce88370SMarek Vasut 			ictx->sect_tail = sctx;
1964bce88370SMarek Vasut 		}
1965bce88370SMarek Vasut 
1966bce88370SMarek Vasut 		size = fread(&sctx->payload, 1, sizeof(sctx->payload), fp);
1967bce88370SMarek Vasut 		if (size != sizeof(sctx->payload)) {
1968bce88370SMarek Vasut 			fprintf(stderr, "ERR: SB section header too short!\n");
1969bce88370SMarek Vasut 			return -EINVAL;
1970bce88370SMarek Vasut 		}
1971bce88370SMarek Vasut 	}
1972bce88370SMarek Vasut 
1973bce88370SMarek Vasut 	size = fread(&ictx->sb_dict_key, 1, sizeof(ictx->sb_dict_key), fp);
1974bce88370SMarek Vasut 	if (size != sizeof(ictx->sb_dict_key)) {
1975bce88370SMarek Vasut 		fprintf(stderr, "ERR: SB key dictionary too short!\n");
1976bce88370SMarek Vasut 		return -EINVAL;
1977bce88370SMarek Vasut 	}
1978bce88370SMarek Vasut 
1979bce88370SMarek Vasut 	sb_encrypt_sb_sections_header(ictx);
1980bce88370SMarek Vasut 	sb_aes_reinit(ictx, 0);
1981bce88370SMarek Vasut 	sb_decrypt_key_dictionary_key(ictx);
1982bce88370SMarek Vasut 
1983bce88370SMarek Vasut 	sb_aes_reinit(ictx, 0);
1984bce88370SMarek Vasut 
1985bce88370SMarek Vasut 	sctx = ictx->sect_head;
1986bce88370SMarek Vasut 	while (sctx) {
1987bce88370SMarek Vasut 		shdr = &sctx->payload;
1988bce88370SMarek Vasut 
1989bce88370SMarek Vasut 		if (shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) {
1990bce88370SMarek Vasut 			sctx->boot = 1;
1991bce88370SMarek Vasut 			bootable = " BOOTABLE";
1992bce88370SMarek Vasut 		}
1993bce88370SMarek Vasut 
1994bce88370SMarek Vasut 		sctx->size = (shdr->section_size * SB_BLOCK_SIZE) +
1995bce88370SMarek Vasut 			     sizeof(struct sb_command);
1996bce88370SMarek Vasut 		soprintf(ictx, "SECTION 0x%x%s # size = %i bytes\n",
1997bce88370SMarek Vasut 			 shdr->section_number, bootable, sctx->size);
1998bce88370SMarek Vasut 
1999bce88370SMarek Vasut 		if (shdr->section_flags & ~SB_SECTION_FLAG_BOOTABLE)
2000bce88370SMarek Vasut 			fprintf(stderr, " WARN: Unknown section flag(s) %08x\n",
2001bce88370SMarek Vasut 				shdr->section_flags);
2002bce88370SMarek Vasut 
2003bce88370SMarek Vasut 		if ((shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) &&
2004bce88370SMarek Vasut 		    (hdr->first_boot_section_id != shdr->section_number)) {
2005bce88370SMarek Vasut 			fprintf(stderr,
2006bce88370SMarek Vasut 				" WARN: Bootable section does ID not match image header ID!\n");
2007bce88370SMarek Vasut 		}
2008bce88370SMarek Vasut 
2009bce88370SMarek Vasut 		ret = sb_verify_commands(ictx, sctx, fp);
2010bce88370SMarek Vasut 		if (ret)
2011bce88370SMarek Vasut 			return ret;
2012bce88370SMarek Vasut 
2013bce88370SMarek Vasut 		sctx = sctx->sect;
2014bce88370SMarek Vasut 	}
2015bce88370SMarek Vasut 
2016bce88370SMarek Vasut 	/*
2017bce88370SMarek Vasut 	 * FIXME IDEA:
2018bce88370SMarek Vasut 	 * check if the first TAG command is at sctx->section_offset
2019bce88370SMarek Vasut 	 */
2020bce88370SMarek Vasut 	return 0;
2021bce88370SMarek Vasut }
2022bce88370SMarek Vasut 
2023bce88370SMarek Vasut static int sb_verify_image_end(struct sb_image_ctx *ictx,
2024bce88370SMarek Vasut 			       FILE *fp, off_t filesz)
2025bce88370SMarek Vasut {
2026bce88370SMarek Vasut 	uint8_t digest[32];
2027bce88370SMarek Vasut 	unsigned long size;
2028bce88370SMarek Vasut 	off_t pos;
2029bce88370SMarek Vasut 	int ret;
2030bce88370SMarek Vasut 
2031bce88370SMarek Vasut 	soprintf(ictx, "------------- Verifying image end -------------\n");
2032bce88370SMarek Vasut 
2033bce88370SMarek Vasut 	size = fread(digest, 1, sizeof(digest), fp);
2034bce88370SMarek Vasut 	if (size != sizeof(digest)) {
2035bce88370SMarek Vasut 		fprintf(stderr, "ERR: SB key dictionary too short!\n");
2036bce88370SMarek Vasut 		return -EINVAL;
2037bce88370SMarek Vasut 	}
2038bce88370SMarek Vasut 
2039bce88370SMarek Vasut 	pos = ftell(fp);
2040bce88370SMarek Vasut 	if (pos != filesz) {
2041bce88370SMarek Vasut 		fprintf(stderr, "ERR: Trailing data past the image!\n");
2042bce88370SMarek Vasut 		return -EINVAL;
2043bce88370SMarek Vasut 	}
2044bce88370SMarek Vasut 
2045bce88370SMarek Vasut 	/* Check the image digest. */
20467bae13b7SMarek Vasut 	EVP_DigestFinal(ictx->md_ctx, ictx->digest, NULL);
20477bae13b7SMarek Vasut 	EVP_MD_CTX_free(ictx->md_ctx);
2048bce88370SMarek Vasut 
2049bce88370SMarek Vasut 	/* Decrypt the image digest from the input image. */
2050bce88370SMarek Vasut 	sb_aes_reinit(ictx, 0);
2051bce88370SMarek Vasut 	sb_aes_crypt(ictx, digest, digest, sizeof(digest));
2052bce88370SMarek Vasut 
2053bce88370SMarek Vasut 	/* Check all of 20 bytes of the SHA1 hash. */
2054bce88370SMarek Vasut 	ret = memcmp(digest, ictx->digest, 20) ? -EINVAL : 0;
2055bce88370SMarek Vasut 
2056bce88370SMarek Vasut 	if (ret)
2057bce88370SMarek Vasut 		soprintf(ictx, "[FAIL] Full-image checksum:          BAD\n");
2058bce88370SMarek Vasut 	else
2059bce88370SMarek Vasut 		soprintf(ictx, "[PASS] Full-image checksum:          OK\n");
2060bce88370SMarek Vasut 
2061bce88370SMarek Vasut 	return ret;
2062bce88370SMarek Vasut }
2063bce88370SMarek Vasut 
2064bce88370SMarek Vasut 
2065bce88370SMarek Vasut static int sb_build_tree_from_img(struct sb_image_ctx *ictx)
2066bce88370SMarek Vasut {
2067bce88370SMarek Vasut 	long filesize;
2068bce88370SMarek Vasut 	int ret;
2069bce88370SMarek Vasut 	FILE *fp;
2070bce88370SMarek Vasut 
2071bce88370SMarek Vasut 	if (!ictx->input_filename) {
2072bce88370SMarek Vasut 		fprintf(stderr, "ERR: Missing filename!\n");
2073bce88370SMarek Vasut 		return -EINVAL;
2074bce88370SMarek Vasut 	}
2075bce88370SMarek Vasut 
2076bce88370SMarek Vasut 	fp = fopen(ictx->input_filename, "r");
2077bce88370SMarek Vasut 	if (!fp)
2078bce88370SMarek Vasut 		goto err_open;
2079bce88370SMarek Vasut 
2080bce88370SMarek Vasut 	ret = fseek(fp, 0, SEEK_END);
2081bce88370SMarek Vasut 	if (ret < 0)
2082bce88370SMarek Vasut 		goto err_file;
2083bce88370SMarek Vasut 
2084bce88370SMarek Vasut 	filesize = ftell(fp);
2085bce88370SMarek Vasut 	if (filesize < 0)
2086bce88370SMarek Vasut 		goto err_file;
2087bce88370SMarek Vasut 
2088bce88370SMarek Vasut 	ret = fseek(fp, 0, SEEK_SET);
2089bce88370SMarek Vasut 	if (ret < 0)
2090bce88370SMarek Vasut 		goto err_file;
2091bce88370SMarek Vasut 
2092bce88370SMarek Vasut 	if (filesize < (signed)sizeof(ictx->payload)) {
2093bce88370SMarek Vasut 		fprintf(stderr, "ERR: File too short!\n");
2094bce88370SMarek Vasut 		goto err_file;
2095bce88370SMarek Vasut 	}
2096bce88370SMarek Vasut 
2097bce88370SMarek Vasut 	if (filesize & (SB_BLOCK_SIZE - 1)) {
2098bce88370SMarek Vasut 		fprintf(stderr, "ERR: The file is not aligned!\n");
2099bce88370SMarek Vasut 		goto err_file;
2100bce88370SMarek Vasut 	}
2101bce88370SMarek Vasut 
2102bce88370SMarek Vasut 	/* Load and verify image header */
2103bce88370SMarek Vasut 	ret = sb_verify_image_header(ictx, fp, filesize);
2104bce88370SMarek Vasut 	if (ret)
2105bce88370SMarek Vasut 		goto err_verify;
2106bce88370SMarek Vasut 
2107bce88370SMarek Vasut 	/* Load and verify sections and commands */
2108bce88370SMarek Vasut 	ret = sb_verify_sections_cmds(ictx, fp);
2109bce88370SMarek Vasut 	if (ret)
2110bce88370SMarek Vasut 		goto err_verify;
2111bce88370SMarek Vasut 
2112bce88370SMarek Vasut 	ret = sb_verify_image_end(ictx, fp, filesize);
2113bce88370SMarek Vasut 	if (ret)
2114bce88370SMarek Vasut 		goto err_verify;
2115bce88370SMarek Vasut 
2116bce88370SMarek Vasut 	ret = 0;
2117bce88370SMarek Vasut 
2118bce88370SMarek Vasut err_verify:
2119bce88370SMarek Vasut 	soprintf(ictx, "-------------------- Result -------------------\n");
2120bce88370SMarek Vasut 	soprintf(ictx, "Verification %s\n", ret ? "FAILED" : "PASSED");
2121bce88370SMarek Vasut 
2122bce88370SMarek Vasut 	/* Stop the encryption session. */
21237bae13b7SMarek Vasut 	sb_aes_deinit(ictx->cipher_ctx);
2124bce88370SMarek Vasut 
2125bce88370SMarek Vasut 	fclose(fp);
2126bce88370SMarek Vasut 	return ret;
2127bce88370SMarek Vasut 
2128bce88370SMarek Vasut err_file:
2129bce88370SMarek Vasut 	fclose(fp);
2130bce88370SMarek Vasut err_open:
2131bce88370SMarek Vasut 	fprintf(stderr, "ERR: Failed to load file \"%s\"\n",
2132bce88370SMarek Vasut 		ictx->input_filename);
2133bce88370SMarek Vasut 	return -EINVAL;
2134bce88370SMarek Vasut }
2135bce88370SMarek Vasut 
2136bce88370SMarek Vasut static void sb_free_image(struct sb_image_ctx *ictx)
2137bce88370SMarek Vasut {
2138bce88370SMarek Vasut 	struct sb_section_ctx *sctx = ictx->sect_head, *s_head;
2139bce88370SMarek Vasut 	struct sb_dcd_ctx *dctx = ictx->dcd_head, *d_head;
2140bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx, *c_head;
2141bce88370SMarek Vasut 
2142bce88370SMarek Vasut 	while (sctx) {
2143bce88370SMarek Vasut 		s_head = sctx;
2144bce88370SMarek Vasut 		c_head = sctx->cmd_head;
2145bce88370SMarek Vasut 
2146bce88370SMarek Vasut 		while (c_head) {
2147bce88370SMarek Vasut 			cctx = c_head;
2148bce88370SMarek Vasut 			c_head = c_head->cmd;
2149bce88370SMarek Vasut 			if (cctx->data)
2150bce88370SMarek Vasut 				free(cctx->data);
2151bce88370SMarek Vasut 			free(cctx);
2152bce88370SMarek Vasut 		}
2153bce88370SMarek Vasut 
2154bce88370SMarek Vasut 		sctx = sctx->sect;
2155bce88370SMarek Vasut 		free(s_head);
2156bce88370SMarek Vasut 	}
2157bce88370SMarek Vasut 
2158bce88370SMarek Vasut 	while (dctx) {
2159bce88370SMarek Vasut 		d_head = dctx;
2160bce88370SMarek Vasut 		dctx = dctx->dcd;
2161bce88370SMarek Vasut 		free(d_head->payload);
2162bce88370SMarek Vasut 		free(d_head);
2163bce88370SMarek Vasut 	}
2164bce88370SMarek Vasut }
2165bce88370SMarek Vasut 
2166bce88370SMarek Vasut /*
2167bce88370SMarek Vasut  * MXSSB-MKIMAGE glue code.
2168bce88370SMarek Vasut  */
2169bce88370SMarek Vasut static int mxsimage_check_image_types(uint8_t type)
2170bce88370SMarek Vasut {
2171bce88370SMarek Vasut 	if (type == IH_TYPE_MXSIMAGE)
2172bce88370SMarek Vasut 		return EXIT_SUCCESS;
2173bce88370SMarek Vasut 	else
2174bce88370SMarek Vasut 		return EXIT_FAILURE;
2175bce88370SMarek Vasut }
2176bce88370SMarek Vasut 
2177bce88370SMarek Vasut static void mxsimage_set_header(void *ptr, struct stat *sbuf, int ifd,
2178f86ed6a8SGuilherme Maciel Ferreira 				struct image_tool_params *params)
2179bce88370SMarek Vasut {
2180bce88370SMarek Vasut }
2181bce88370SMarek Vasut 
2182f86ed6a8SGuilherme Maciel Ferreira int mxsimage_check_params(struct image_tool_params *params)
2183bce88370SMarek Vasut {
2184bce88370SMarek Vasut 	if (!params)
2185bce88370SMarek Vasut 		return -1;
2186bce88370SMarek Vasut 	if (!strlen(params->imagename)) {
2187bce88370SMarek Vasut 		fprintf(stderr,
2188bce88370SMarek Vasut 			"Error: %s - Configuration file not specified, it is needed for mxsimage generation\n",
2189bce88370SMarek Vasut 			params->cmdname);
2190bce88370SMarek Vasut 		return -1;
2191bce88370SMarek Vasut 	}
2192bce88370SMarek Vasut 
2193bce88370SMarek Vasut 	/*
2194bce88370SMarek Vasut 	 * Check parameters:
2195bce88370SMarek Vasut 	 * XIP is not allowed and verify that incompatible
2196bce88370SMarek Vasut 	 * parameters are not sent at the same time
2197bce88370SMarek Vasut 	 * For example, if list is required a data image must not be provided
2198bce88370SMarek Vasut 	 */
2199bce88370SMarek Vasut 	return	(params->dflag && (params->fflag || params->lflag)) ||
2200bce88370SMarek Vasut 		(params->fflag && (params->dflag || params->lflag)) ||
2201bce88370SMarek Vasut 		(params->lflag && (params->dflag || params->fflag)) ||
2202bce88370SMarek Vasut 		(params->xflag) || !(strlen(params->imagename));
2203bce88370SMarek Vasut }
2204bce88370SMarek Vasut 
2205bce88370SMarek Vasut static int mxsimage_verify_print_header(char *file, int silent)
2206bce88370SMarek Vasut {
2207bce88370SMarek Vasut 	int ret;
2208bce88370SMarek Vasut 	struct sb_image_ctx ctx;
2209bce88370SMarek Vasut 
2210bce88370SMarek Vasut 	memset(&ctx, 0, sizeof(ctx));
2211bce88370SMarek Vasut 
2212bce88370SMarek Vasut 	ctx.input_filename = file;
2213bce88370SMarek Vasut 	ctx.silent_dump = silent;
2214bce88370SMarek Vasut 
2215bce88370SMarek Vasut 	ret = sb_build_tree_from_img(&ctx);
2216bce88370SMarek Vasut 	sb_free_image(&ctx);
2217bce88370SMarek Vasut 
2218bce88370SMarek Vasut 	return ret;
2219bce88370SMarek Vasut }
2220bce88370SMarek Vasut 
2221bce88370SMarek Vasut char *imagefile;
2222bce88370SMarek Vasut static int mxsimage_verify_header(unsigned char *ptr, int image_size,
2223f86ed6a8SGuilherme Maciel Ferreira 			struct image_tool_params *params)
2224bce88370SMarek Vasut {
2225bce88370SMarek Vasut 	struct sb_boot_image_header *hdr;
2226bce88370SMarek Vasut 
2227bce88370SMarek Vasut 	if (!ptr)
2228bce88370SMarek Vasut 		return -EINVAL;
2229bce88370SMarek Vasut 
2230bce88370SMarek Vasut 	hdr = (struct sb_boot_image_header *)ptr;
2231bce88370SMarek Vasut 
2232bce88370SMarek Vasut 	/*
2233bce88370SMarek Vasut 	 * Check if the header contains the MXS image signatures,
2234bce88370SMarek Vasut 	 * if so, do a full-image verification.
2235bce88370SMarek Vasut 	 */
2236bce88370SMarek Vasut 	if (memcmp(hdr->signature1, "STMP", 4) ||
2237bce88370SMarek Vasut 	    memcmp(hdr->signature2, "sgtl", 4))
2238bce88370SMarek Vasut 		return -EINVAL;
2239bce88370SMarek Vasut 
2240bce88370SMarek Vasut 	imagefile = params->imagefile;
2241bce88370SMarek Vasut 
2242bce88370SMarek Vasut 	return mxsimage_verify_print_header(params->imagefile, 1);
2243bce88370SMarek Vasut }
2244bce88370SMarek Vasut 
2245bce88370SMarek Vasut static void mxsimage_print_header(const void *hdr)
2246bce88370SMarek Vasut {
2247bce88370SMarek Vasut 	if (imagefile)
2248bce88370SMarek Vasut 		mxsimage_verify_print_header(imagefile, 0);
2249bce88370SMarek Vasut }
2250bce88370SMarek Vasut 
2251bce88370SMarek Vasut static int sb_build_image(struct sb_image_ctx *ictx,
2252bce88370SMarek Vasut 			  struct image_type_params *tparams)
2253bce88370SMarek Vasut {
2254bce88370SMarek Vasut 	struct sb_boot_image_header *sb_header = &ictx->payload;
2255bce88370SMarek Vasut 	struct sb_section_ctx *sctx;
2256bce88370SMarek Vasut 	struct sb_cmd_ctx *cctx;
2257bce88370SMarek Vasut 	struct sb_command *ccmd;
2258bce88370SMarek Vasut 	struct sb_key_dictionary_key *sb_dict_key = &ictx->sb_dict_key;
2259bce88370SMarek Vasut 
2260bce88370SMarek Vasut 	uint8_t *image, *iptr;
2261bce88370SMarek Vasut 
2262bce88370SMarek Vasut 	/* Calculate image size. */
2263bce88370SMarek Vasut 	uint32_t size = sizeof(*sb_header) +
2264bce88370SMarek Vasut 		ictx->sect_count * sizeof(struct sb_sections_header) +
2265bce88370SMarek Vasut 		sizeof(*sb_dict_key) + sizeof(ictx->digest);
2266bce88370SMarek Vasut 
2267bce88370SMarek Vasut 	sctx = ictx->sect_head;
2268bce88370SMarek Vasut 	while (sctx) {
2269bce88370SMarek Vasut 		size += sctx->size;
2270bce88370SMarek Vasut 		sctx = sctx->sect;
2271bce88370SMarek Vasut 	};
2272bce88370SMarek Vasut 
2273bce88370SMarek Vasut 	image = malloc(size);
2274bce88370SMarek Vasut 	if (!image)
2275bce88370SMarek Vasut 		return -ENOMEM;
2276bce88370SMarek Vasut 	iptr = image;
2277bce88370SMarek Vasut 
2278bce88370SMarek Vasut 	memcpy(iptr, sb_header, sizeof(*sb_header));
2279bce88370SMarek Vasut 	iptr += sizeof(*sb_header);
2280bce88370SMarek Vasut 
2281bce88370SMarek Vasut 	sctx = ictx->sect_head;
2282bce88370SMarek Vasut 	while (sctx) {
2283bce88370SMarek Vasut 		memcpy(iptr, &sctx->payload, sizeof(struct sb_sections_header));
2284bce88370SMarek Vasut 		iptr += sizeof(struct sb_sections_header);
2285bce88370SMarek Vasut 		sctx = sctx->sect;
2286bce88370SMarek Vasut 	};
2287bce88370SMarek Vasut 
2288bce88370SMarek Vasut 	memcpy(iptr, sb_dict_key, sizeof(*sb_dict_key));
2289bce88370SMarek Vasut 	iptr += sizeof(*sb_dict_key);
2290bce88370SMarek Vasut 
2291bce88370SMarek Vasut 	sctx = ictx->sect_head;
2292bce88370SMarek Vasut 	while (sctx) {
2293bce88370SMarek Vasut 		cctx = sctx->cmd_head;
2294bce88370SMarek Vasut 		while (cctx) {
2295bce88370SMarek Vasut 			ccmd = &cctx->payload;
2296bce88370SMarek Vasut 
2297bce88370SMarek Vasut 			memcpy(iptr, &cctx->c_payload, sizeof(cctx->payload));
2298bce88370SMarek Vasut 			iptr += sizeof(cctx->payload);
2299bce88370SMarek Vasut 
2300bce88370SMarek Vasut 			if (ccmd->header.tag == ROM_LOAD_CMD) {
2301bce88370SMarek Vasut 				memcpy(iptr, cctx->data, cctx->length);
2302bce88370SMarek Vasut 				iptr += cctx->length;
2303bce88370SMarek Vasut 			}
2304bce88370SMarek Vasut 
2305bce88370SMarek Vasut 			cctx = cctx->cmd;
2306bce88370SMarek Vasut 		}
2307bce88370SMarek Vasut 
2308bce88370SMarek Vasut 		sctx = sctx->sect;
2309bce88370SMarek Vasut 	};
2310bce88370SMarek Vasut 
2311bce88370SMarek Vasut 	memcpy(iptr, ictx->digest, sizeof(ictx->digest));
2312bce88370SMarek Vasut 	iptr += sizeof(ictx->digest);
2313bce88370SMarek Vasut 
2314bce88370SMarek Vasut 	/* Configure the mkimage */
2315bce88370SMarek Vasut 	tparams->hdr = image;
2316bce88370SMarek Vasut 	tparams->header_size = size;
2317bce88370SMarek Vasut 
2318bce88370SMarek Vasut 	return 0;
2319bce88370SMarek Vasut }
2320bce88370SMarek Vasut 
2321f86ed6a8SGuilherme Maciel Ferreira static int mxsimage_generate(struct image_tool_params *params,
2322bce88370SMarek Vasut 	struct image_type_params *tparams)
2323bce88370SMarek Vasut {
2324bce88370SMarek Vasut 	int ret;
2325bce88370SMarek Vasut 	struct sb_image_ctx ctx;
2326bce88370SMarek Vasut 
2327bce88370SMarek Vasut 	/* Do not copy the U-Boot image! */
2328bce88370SMarek Vasut 	params->skipcpy = 1;
2329bce88370SMarek Vasut 
2330bce88370SMarek Vasut 	memset(&ctx, 0, sizeof(ctx));
2331bce88370SMarek Vasut 
2332bce88370SMarek Vasut 	ctx.cfg_filename = params->imagename;
2333bce88370SMarek Vasut 	ctx.output_filename = params->imagefile;
2334bce88370SMarek Vasut 
2335bce88370SMarek Vasut 	ret = sb_build_tree_from_cfg(&ctx);
2336bce88370SMarek Vasut 	if (ret)
2337bce88370SMarek Vasut 		goto fail;
2338bce88370SMarek Vasut 
2339bce88370SMarek Vasut 	ret = sb_encrypt_image(&ctx);
2340bce88370SMarek Vasut 	if (!ret)
2341bce88370SMarek Vasut 		ret = sb_build_image(&ctx, tparams);
2342bce88370SMarek Vasut 
2343bce88370SMarek Vasut fail:
2344bce88370SMarek Vasut 	sb_free_image(&ctx);
2345bce88370SMarek Vasut 
2346bce88370SMarek Vasut 	return ret;
2347bce88370SMarek Vasut }
2348bce88370SMarek Vasut 
2349bce88370SMarek Vasut /*
2350bce88370SMarek Vasut  * mxsimage parameters
2351bce88370SMarek Vasut  */
2352a93648d1SGuilherme Maciel Ferreira U_BOOT_IMAGE_TYPE(
2353a93648d1SGuilherme Maciel Ferreira 	mxsimage,
2354a93648d1SGuilherme Maciel Ferreira 	"Freescale MXS Boot Image support",
2355a93648d1SGuilherme Maciel Ferreira 	0,
2356a93648d1SGuilherme Maciel Ferreira 	NULL,
2357a93648d1SGuilherme Maciel Ferreira 	mxsimage_check_params,
2358a93648d1SGuilherme Maciel Ferreira 	mxsimage_verify_header,
2359a93648d1SGuilherme Maciel Ferreira 	mxsimage_print_header,
2360a93648d1SGuilherme Maciel Ferreira 	mxsimage_set_header,
2361a93648d1SGuilherme Maciel Ferreira 	NULL,
2362a93648d1SGuilherme Maciel Ferreira 	mxsimage_check_image_types,
2363a93648d1SGuilherme Maciel Ferreira 	NULL,
2364a93648d1SGuilherme Maciel Ferreira 	mxsimage_generate
2365a93648d1SGuilherme Maciel Ferreira );
2366bce88370SMarek Vasut #endif
2367