xref: /openbmc/u-boot/tools/pblimage.c (revision b0e6ef46)
1 /*
2  * Copyright 2012 Freescale Semiconductor, Inc.
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 #include "imagetool.h"
7 #include <image.h>
8 #include "pblimage.h"
9 #include "pbl_crc32.h"
10 
11 /*
12  * Initialize to an invalid value.
13  */
14 static uint32_t next_pbl_cmd = 0x82000000;
15 /*
16  * need to store all bytes in memory for calculating crc32, then write the
17  * bytes to image file for PBL boot.
18  */
19 static unsigned char mem_buf[1000000];
20 static unsigned char *pmem_buf = mem_buf;
21 static int pbl_size;
22 static char *fname = "Unknown";
23 static int lineno = -1;
24 static struct pbl_header pblimage_header;
25 
26 static union
27 {
28 	char c[4];
29 	unsigned char l;
30 } endian_test = { {'l', '?', '?', 'b'} };
31 
32 #define ENDIANNESS ((char)endian_test.l)
33 
34 /*
35  * The PBL can load up to 64 bytes at a time, so we split the U-Boot
36  * image into 64 byte chunks. PBL needs a command for each piece, of
37  * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the
38  * start offset by subtracting the size of the u-boot image from the
39  * top of the allowable 24-bit range.
40  */
41 static void init_next_pbl_cmd(FILE *fp_uboot)
42 {
43 	struct stat st;
44 	int fd = fileno(fp_uboot);
45 
46 	if (fstat(fd, &st) == -1) {
47 		printf("Error: Could not determine u-boot image size. %s\n",
48 			strerror(errno));
49 		exit(EXIT_FAILURE);
50 	}
51 
52 	next_pbl_cmd = 0x82000000 - st.st_size;
53 }
54 
55 static void generate_pbl_cmd(void)
56 {
57 	uint32_t val = next_pbl_cmd;
58 	next_pbl_cmd += 0x40;
59 	int i;
60 
61 	for (i = 3; i >= 0; i--) {
62 		*pmem_buf++ = (val >> (i * 8)) & 0xff;
63 		pbl_size++;
64 	}
65 }
66 
67 static void pbl_fget(size_t size, FILE *stream)
68 {
69 	unsigned char c;
70 	int c_temp;
71 
72 	while (size && (c_temp = fgetc(stream)) != EOF) {
73 		c = (unsigned char)c_temp;
74 		*pmem_buf++ = c;
75 		pbl_size++;
76 		size--;
77 	}
78 }
79 
80 /* load split u-boot with PBI command 81xxxxxx. */
81 static void load_uboot(FILE *fp_uboot)
82 {
83 	init_next_pbl_cmd(fp_uboot);
84 	while (next_pbl_cmd < 0x82000000) {
85 		generate_pbl_cmd();
86 		pbl_fget(64, fp_uboot);
87 	}
88 }
89 
90 static void check_get_hexval(char *token)
91 {
92 	uint32_t hexval;
93 	int i;
94 
95 	if (!sscanf(token, "%x", &hexval)) {
96 		printf("Error:%s[%d] - Invalid hex data(%s)\n", fname,
97 			lineno, token);
98 		exit(EXIT_FAILURE);
99 	}
100 	for (i = 3; i >= 0; i--) {
101 		*pmem_buf++ = (hexval >> (i * 8)) & 0xff;
102 		pbl_size++;
103 	}
104 }
105 
106 static void pbl_parser(char *name)
107 {
108 	FILE *fd = NULL;
109 	char *line = NULL;
110 	char *token, *saveptr1, *saveptr2;
111 	size_t len = 0;
112 
113 	fname = name;
114 	fd = fopen(name, "r");
115 	if (fd == NULL) {
116 		printf("Error:%s - Can't open\n", fname);
117 		exit(EXIT_FAILURE);
118 	}
119 
120 	while ((getline(&line, &len, fd)) > 0) {
121 		lineno++;
122 		token = strtok_r(line, "\r\n", &saveptr1);
123 		/* drop all lines with zero tokens (= empty lines) */
124 		if (token == NULL)
125 			continue;
126 		for (line = token;; line = NULL) {
127 			token = strtok_r(line, " \t", &saveptr2);
128 			if (token == NULL)
129 				break;
130 			/* Drop all text starting with '#' as comments */
131 			if (token[0] == '#')
132 				break;
133 			check_get_hexval(token);
134 		}
135 	}
136 	if (line)
137 		free(line);
138 	fclose(fd);
139 }
140 
141 static uint32_t reverse_byte(uint32_t val)
142 {
143 	uint32_t temp;
144 	unsigned char *p1;
145 	int j;
146 
147 	temp = val;
148 	p1 = (unsigned char *)&temp;
149 	for (j = 3; j >= 0; j--)
150 		*p1++ = (val >> (j * 8)) & 0xff;
151 	return temp;
152 }
153 
154 /* write end command and crc command to memory. */
155 static void add_end_cmd(void)
156 {
157 	uint32_t pbl_end_cmd[4] = {0x09138000, 0x00000000,
158 		0x091380c0, 0x00000000};
159 	uint32_t crc32_pbl;
160 	int i;
161 	unsigned char *p = (unsigned char *)&pbl_end_cmd;
162 
163 	if (ENDIANNESS == 'l') {
164 		for (i = 0; i < 4; i++)
165 			pbl_end_cmd[i] = reverse_byte(pbl_end_cmd[i]);
166 	}
167 
168 	for (i = 0; i < 16; i++) {
169 		*pmem_buf++ = *p++;
170 		pbl_size++;
171 	}
172 
173 	/* Add PBI CRC command. */
174 	*pmem_buf++ = 0x08;
175 	*pmem_buf++ = 0x13;
176 	*pmem_buf++ = 0x80;
177 	*pmem_buf++ = 0x40;
178 	pbl_size += 4;
179 
180 	/* calculated CRC32 and write it to memory. */
181 	crc32_pbl = pbl_crc32(0, (const char *)mem_buf, pbl_size);
182 	*pmem_buf++ = (crc32_pbl >> 24) & 0xff;
183 	*pmem_buf++ = (crc32_pbl >> 16) & 0xff;
184 	*pmem_buf++ = (crc32_pbl >> 8) & 0xff;
185 	*pmem_buf++ = (crc32_pbl) & 0xff;
186 	pbl_size += 4;
187 
188 	if ((pbl_size % 16) != 0) {
189 		for (i = 0; i < 8; i++) {
190 			*pmem_buf++ = 0x0;
191 			pbl_size++;
192 		}
193 	}
194 	if ((pbl_size % 16 != 0)) {
195 		printf("Error: Bad size of image file\n");
196 		exit(EXIT_FAILURE);
197 	}
198 }
199 
200 void pbl_load_uboot(int ifd, struct image_tool_params *params)
201 {
202 	FILE *fp_uboot;
203 	int size;
204 
205 	/* parse the rcw.cfg file. */
206 	pbl_parser(params->imagename);
207 
208 	/* parse the pbi.cfg file. */
209 	pbl_parser(params->imagename2);
210 
211 	fp_uboot = fopen(params->datafile, "r");
212 	if (fp_uboot == NULL) {
213 		printf("Error: %s open failed\n", params->datafile);
214 		exit(EXIT_FAILURE);
215 	}
216 
217 	load_uboot(fp_uboot);
218 	add_end_cmd();
219 	fclose(fp_uboot);
220 	lseek(ifd, 0, SEEK_SET);
221 
222 	size = pbl_size;
223 	if (write(ifd, (const void *)&mem_buf, size) != size) {
224 		fprintf(stderr, "Write error on %s: %s\n",
225 			params->imagefile, strerror(errno));
226 		exit(EXIT_FAILURE);
227 	}
228 }
229 
230 static int pblimage_check_image_types(uint8_t type)
231 {
232 	if (type == IH_TYPE_PBLIMAGE)
233 		return EXIT_SUCCESS;
234 	else
235 		return EXIT_FAILURE;
236 }
237 
238 static int pblimage_verify_header(unsigned char *ptr, int image_size,
239 			struct image_tool_params *params)
240 {
241 	struct pbl_header *pbl_hdr = (struct pbl_header *) ptr;
242 
243 	/* Only a few checks can be done: search for magic numbers */
244 	if (ENDIANNESS == 'l') {
245 		if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE))
246 			return -FDT_ERR_BADSTRUCTURE;
247 
248 		if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER))
249 			return -FDT_ERR_BADSTRUCTURE;
250 	} else {
251 		if (pbl_hdr->preamble != RCW_PREAMBLE)
252 			return -FDT_ERR_BADSTRUCTURE;
253 
254 		if (pbl_hdr->rcwheader != RCW_HEADER)
255 			return -FDT_ERR_BADSTRUCTURE;
256 	}
257 	return 0;
258 }
259 
260 static void pblimage_print_header(const void *ptr)
261 {
262 	printf("Image Type:   Freescale PBL Boot Image\n");
263 }
264 
265 static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd,
266 				struct image_tool_params *params)
267 {
268 	/*nothing need to do, pbl_load_uboot takes care of whole file. */
269 }
270 
271 /* pblimage parameters */
272 static struct image_type_params pblimage_params = {
273 	.name		= "Freescale PBL Boot Image support",
274 	.header_size	= sizeof(struct pbl_header),
275 	.hdr		= (void *)&pblimage_header,
276 	.check_image_type = pblimage_check_image_types,
277 	.verify_header	= pblimage_verify_header,
278 	.print_header	= pblimage_print_header,
279 	.set_header	= pblimage_set_header,
280 };
281 
282 void init_pbl_image_type(void)
283 {
284 	pbl_size = 0;
285 	register_image_type(&pblimage_params);
286 }
287