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