xref: /openbmc/u-boot/tools/pblimage.c (revision aec36cfd)
1 /*
2  * Copyright 2012 Freescale Semiconductor, Inc.
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 #define _GNU_SOURCE
23 
24 #include "mkimage.h"
25 #include <image.h>
26 #include "pblimage.h"
27 
28 /*
29  * Initialize to an invalid value.
30  */
31 static uint32_t next_pbl_cmd = 0x82000000;
32 /*
33  * need to store all bytes in memory for calculating crc32, then write the
34  * bytes to image file for PBL boot.
35  */
36 static unsigned char mem_buf[1000000];
37 static unsigned char *pmem_buf = mem_buf;
38 static int pbl_size;
39 static char *fname = "Unknown";
40 static int lineno = -1;
41 static struct pbl_header pblimage_header;
42 
43 static union
44 {
45 	char c[4];
46 	unsigned char l;
47 } endian_test = { {'l', '?', '?', 'b'} };
48 
49 #define ENDIANNESS ((char)endian_test.l)
50 
51 /*
52  * The PBL can load up to 64 bytes at a time, so we split the U-Boot
53  * image into 64 byte chunks. PBL needs a command for each piece, of
54  * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the
55  * start offset by subtracting the size of the u-boot image from the
56  * top of the allowable 24-bit range.
57  */
58 static void init_next_pbl_cmd(FILE *fp_uboot)
59 {
60 	struct stat st;
61 	int fd = fileno(fp_uboot);
62 
63 	if (fstat(fd, &st) == -1) {
64 		printf("Error: Could not determine u-boot image size. %s\n",
65 			strerror(errno));
66 		exit(EXIT_FAILURE);
67 	}
68 
69 	next_pbl_cmd = 0x82000000 - st.st_size;
70 }
71 
72 static void generate_pbl_cmd(void)
73 {
74 	uint32_t val = next_pbl_cmd;
75 	next_pbl_cmd += 0x40;
76 	int i;
77 
78 	for (i = 3; i >= 0; i--) {
79 		*pmem_buf++ = (val >> (i * 8)) & 0xff;
80 		pbl_size++;
81 	}
82 }
83 
84 static void pbl_fget(size_t size, FILE *stream)
85 {
86 	unsigned char c;
87 	int c_temp;
88 
89 	while (size && (c_temp = fgetc(stream)) != EOF) {
90 		c = (unsigned char)c_temp;
91 		*pmem_buf++ = c;
92 		pbl_size++;
93 		size--;
94 	}
95 }
96 
97 /* load split u-boot with PBI command 81xxxxxx. */
98 static void load_uboot(FILE *fp_uboot)
99 {
100 	init_next_pbl_cmd(fp_uboot);
101 	while (next_pbl_cmd < 0x82000000) {
102 		generate_pbl_cmd();
103 		pbl_fget(64, fp_uboot);
104 	}
105 }
106 
107 static void check_get_hexval(char *token)
108 {
109 	uint32_t hexval;
110 	int i;
111 
112 	if (!sscanf(token, "%x", &hexval)) {
113 		printf("Error:%s[%d] - Invalid hex data(%s)\n", fname,
114 			lineno, token);
115 		exit(EXIT_FAILURE);
116 	}
117 	for (i = 3; i >= 0; i--) {
118 		*pmem_buf++ = (hexval >> (i * 8)) & 0xff;
119 		pbl_size++;
120 	}
121 }
122 
123 static void pbl_parser(char *name)
124 {
125 	FILE *fd = NULL;
126 	char *line = NULL;
127 	char *token, *saveptr1, *saveptr2;
128 	size_t len = 0;
129 
130 	fname = name;
131 	fd = fopen(name, "r");
132 	if (fd == NULL) {
133 		printf("Error:%s - Can't open\n", fname);
134 		exit(EXIT_FAILURE);
135 	}
136 
137 	while ((getline(&line, &len, fd)) > 0) {
138 		lineno++;
139 		token = strtok_r(line, "\r\n", &saveptr1);
140 		/* drop all lines with zero tokens (= empty lines) */
141 		if (token == NULL)
142 			continue;
143 		for (line = token;; line = NULL) {
144 			token = strtok_r(line, " \t", &saveptr2);
145 			if (token == NULL)
146 				break;
147 			/* Drop all text starting with '#' as comments */
148 			if (token[0] == '#')
149 				break;
150 			check_get_hexval(token);
151 		}
152 	}
153 	if (line)
154 		free(line);
155 	fclose(fd);
156 }
157 
158 static uint32_t crc_table[256];
159 
160 static void make_crc_table(void)
161 {
162 	uint32_t mask;
163 	int i, j;
164 	uint32_t poly; /* polynomial exclusive-or pattern */
165 
166 	/*
167 	 * the polynomial used by PBL is 1 + x1 + x2 + x4 + x5 + x7 + x8 + x10
168 	 * + x11 + x12 + x16 + x22 + x23 + x26 + x32.
169 	 */
170 	poly = 0x04c11db7;
171 
172 	for (i = 0; i < 256; i++) {
173 		mask = i << 24;
174 		for (j = 0; j < 8; j++) {
175 			if (mask & 0x80000000)
176 				mask = (mask << 1) ^ poly;
177 			else
178 				mask <<= 1;
179 		}
180 		crc_table[i] = mask;
181 	}
182 }
183 
184 unsigned long pbl_crc32(unsigned long crc, const char *buf, uint32_t len)
185 {
186 	uint32_t crc32_val = 0xffffffff;
187 	uint32_t xor = 0x0;
188 	int i;
189 
190 	make_crc_table();
191 
192 	for (i = 0; i < len; i++)
193 		crc32_val = (crc32_val << 8) ^
194 			crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)];
195 
196 	crc32_val = crc32_val ^ xor;
197 	if (crc32_val < 0) {
198 		crc32_val += 0xffffffff;
199 		crc32_val += 1;
200 	}
201 	return crc32_val;
202 }
203 
204 static uint32_t reverse_byte(uint32_t val)
205 {
206 	uint32_t temp;
207 	unsigned char *p1;
208 	int j;
209 
210 	temp = val;
211 	p1 = (unsigned char *)&temp;
212 	for (j = 3; j >= 0; j--)
213 		*p1++ = (val >> (j * 8)) & 0xff;
214 	return temp;
215 }
216 
217 /* write end command and crc command to memory. */
218 static void add_end_cmd(void)
219 {
220 	uint32_t pbl_end_cmd[4] = {0x09138000, 0x00000000,
221 		0x091380c0, 0x00000000};
222 	uint32_t crc32_pbl;
223 	int i;
224 	unsigned char *p = (unsigned char *)&pbl_end_cmd;
225 
226 	if (ENDIANNESS == 'l') {
227 		for (i = 0; i < 4; i++)
228 			pbl_end_cmd[i] = reverse_byte(pbl_end_cmd[i]);
229 	}
230 
231 	for (i = 0; i < 16; i++) {
232 		*pmem_buf++ = *p++;
233 		pbl_size++;
234 	}
235 
236 	/* Add PBI CRC command. */
237 	*pmem_buf++ = 0x08;
238 	*pmem_buf++ = 0x13;
239 	*pmem_buf++ = 0x80;
240 	*pmem_buf++ = 0x40;
241 	pbl_size += 4;
242 
243 	/* calculated CRC32 and write it to memory. */
244 	crc32_pbl = pbl_crc32(0, (const char *)mem_buf, pbl_size);
245 	*pmem_buf++ = (crc32_pbl >> 24) & 0xff;
246 	*pmem_buf++ = (crc32_pbl >> 16) & 0xff;
247 	*pmem_buf++ = (crc32_pbl >> 8) & 0xff;
248 	*pmem_buf++ = (crc32_pbl) & 0xff;
249 	pbl_size += 4;
250 
251 	if ((pbl_size % 16) != 0) {
252 		for (i = 0; i < 8; i++) {
253 			*pmem_buf++ = 0x0;
254 			pbl_size++;
255 		}
256 	}
257 	if ((pbl_size % 16 != 0)) {
258 		printf("Error: Bad size of image file\n");
259 		exit(EXIT_FAILURE);
260 	}
261 }
262 
263 void pbl_load_uboot(int ifd, struct mkimage_params *params)
264 {
265 	FILE *fp_uboot;
266 	int size;
267 
268 	/* parse the rcw.cfg file. */
269 	pbl_parser(params->imagename);
270 
271 	/* parse the pbi.cfg file. */
272 	pbl_parser(params->imagename2);
273 
274 	fp_uboot = fopen(params->datafile, "r");
275 	if (fp_uboot == NULL) {
276 		printf("Error: %s open failed\n", params->datafile);
277 		exit(EXIT_FAILURE);
278 	}
279 
280 	load_uboot(fp_uboot);
281 	add_end_cmd();
282 	fclose(fp_uboot);
283 	lseek(ifd, 0, SEEK_SET);
284 
285 	size = pbl_size;
286 	if (write(ifd, (const void *)&mem_buf, size) != size) {
287 		fprintf(stderr, "Write error on %s: %s\n",
288 			params->imagefile, strerror(errno));
289 		exit(EXIT_FAILURE);
290 	}
291 }
292 
293 static int pblimage_check_image_types(uint8_t type)
294 {
295 	if (type == IH_TYPE_PBLIMAGE)
296 		return EXIT_SUCCESS;
297 	else
298 		return EXIT_FAILURE;
299 }
300 
301 static int pblimage_verify_header(unsigned char *ptr, int image_size,
302 			struct mkimage_params *params)
303 {
304 	struct pbl_header *pbl_hdr = (struct pbl_header *) ptr;
305 
306 	/* Only a few checks can be done: search for magic numbers */
307 	if (ENDIANNESS == 'l') {
308 		if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE))
309 			return -FDT_ERR_BADSTRUCTURE;
310 
311 		if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER))
312 			return -FDT_ERR_BADSTRUCTURE;
313 	} else {
314 		if (pbl_hdr->preamble != RCW_PREAMBLE)
315 			return -FDT_ERR_BADSTRUCTURE;
316 
317 		if (pbl_hdr->rcwheader != RCW_HEADER)
318 			return -FDT_ERR_BADSTRUCTURE;
319 	}
320 	return 0;
321 }
322 
323 static void pblimage_print_header(const void *ptr)
324 {
325 	printf("Image Type:   Freescale PBL Boot Image\n");
326 }
327 
328 static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd,
329 				struct mkimage_params *params)
330 {
331 	/*nothing need to do, pbl_load_uboot takes care of whole file. */
332 }
333 
334 /* pblimage parameters */
335 static struct image_type_params pblimage_params = {
336 	.name		= "Freescale PBL Boot Image support",
337 	.header_size	= sizeof(struct pbl_header),
338 	.hdr		= (void *)&pblimage_header,
339 	.check_image_type = pblimage_check_image_types,
340 	.verify_header	= pblimage_verify_header,
341 	.print_header	= pblimage_print_header,
342 	.set_header	= pblimage_set_header,
343 };
344 
345 void init_pbl_image_type(void)
346 {
347 	pbl_size = 0;
348 	mkimage_register(&pblimage_params);
349 }
350