1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
4  *
5  * Reference documents:
6  *   Cyclone V SoC: https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/hb/cyclone-v/cv_5400a.pdf
7  *   Arria V SoC:   https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/hb/arria-v/av_5400a.pdf
8  *   Arria 10 SoC:  https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/hb/arria-10/a10_5400a.pdf
9  *
10  * Bootable SoCFPGA image requires a structure of the following format
11  * positioned at offset 0x40 of the bootable image. Endian is LSB.
12  *
13  * There are two versions of the SoCFPGA header format, v0 and v1.
14  * The version 0 is used by Cyclone V SoC and Arria V SoC, while
15  * the version 1 is used by the Arria 10 SoC.
16  *
17  * Version 0:
18  * Offset   Length   Usage
19  * -----------------------
20  *   0x40        4   Validation word (0x31305341)
21  *   0x44        1   Version (0x0)
22  *   0x45        1   Flags (unused, zero is fine)
23  *   0x46        2   Length (in units of u32, including the end checksum).
24  *   0x48        2   Zero (0x0)
25  *   0x4A        2   Checksum over the header. NB Not CRC32
26  *
27  * Version 1:
28  * Offset   Length   Usage
29  * -----------------------
30  *   0x40        4   Validation word (0x31305341)
31  *   0x44        1   Version (0x1)
32  *   0x45        1   Flags (unused, zero is fine)
33  *   0x46        2   Header length (in units of u8).
34  *   0x48        4   Length (in units of u8).
35  *   0x4C        4   Image entry offset from standard of header
36  *   0x50        2   Zero (0x0)
37  *   0x52        2   Checksum over the header. NB Not CRC32
38  *
39  * At the end of the code we have a 32-bit CRC checksum over whole binary
40  * excluding the CRC.
41  *
42  * Note that the CRC used here is **not** the zlib/Adler crc32. It is the
43  * CRC-32 used in bzip2, ethernet and elsewhere.
44  *
45  * The Image entry offset in version 1 image is relative the the start of
46  * the header, 0x40, and must not be a negative number. Therefore, it is
47  * only possible to make the SoCFPGA jump forward. The U-Boot bootloader
48  * places a trampoline instruction at offset 0x5c, 0x14 bytes from the
49  * start of the SoCFPGA header, which jumps to the reset vector.
50  *
51  * The image is padded out to 64k, because that is what is
52  * typically used to write the image to the boot medium.
53  */
54 
55 #include "pbl_crc32.h"
56 #include "imagetool.h"
57 #include "mkimage.h"
58 #include <u-boot/crc.h>
59 
60 #include <image.h>
61 
62 #define HEADER_OFFSET	0x40
63 #define VALIDATION_WORD	0x31305341
64 #define IMAGE_ALIGN	16
65 
66 /* Minimum and default entry point offset */
67 #define ENTRY_POINT_OFFSET	0x14
68 
69 static uint8_t buffer_v0[0x10000];
70 static uint8_t buffer_v1[0x40000];
71 
72 struct socfpga_header_v0 {
73 	uint32_t	validation;
74 	uint8_t		version;
75 	uint8_t		flags;
76 	uint16_t	length_u32;
77 	uint16_t	zero;
78 	uint16_t	checksum;
79 };
80 
81 struct socfpga_header_v1 {
82 	uint32_t	validation;
83 	uint8_t		version;
84 	uint8_t		flags;
85 	uint16_t	header_u8;
86 	uint32_t	length_u8;
87 	uint32_t	entry_offset;
88 	uint16_t	zero;
89 	uint16_t	checksum;
90 };
91 
sfp_hdr_size(uint8_t ver)92 static unsigned int sfp_hdr_size(uint8_t ver)
93 {
94 	if (ver == 0)
95 		return sizeof(struct socfpga_header_v0);
96 	if (ver == 1)
97 		return sizeof(struct socfpga_header_v1);
98 	return 0;
99 }
100 
sfp_max_size(uint8_t ver)101 static unsigned int sfp_max_size(uint8_t ver)
102 {
103 	if (ver == 0)
104 		return sizeof(buffer_v0);
105 	if (ver == 1)
106 		return sizeof(buffer_v1);
107 	return 0;
108 }
109 
sfp_aligned_len(uint32_t size)110 static unsigned int sfp_aligned_len(uint32_t size)
111 {
112 	/* Add 4 bytes for CRC and align to 16 bytes */
113 	return ALIGN(size + sizeof(uint32_t), IMAGE_ALIGN);
114 }
115 
116 /*
117  * The header checksum is just a very simple checksum over
118  * the header area.
119  * There is still a crc32 over the whole lot.
120  */
sfp_hdr_checksum(uint8_t * buf,unsigned char ver)121 static uint16_t sfp_hdr_checksum(uint8_t *buf, unsigned char ver)
122 {
123 	uint16_t ret = 0;
124 	int len = sfp_hdr_size(ver) - sizeof(ret);
125 
126 	while (--len)
127 		ret += *buf++;
128 
129 	return ret;
130 }
131 
sfp_build_header(uint8_t * buf,uint8_t ver,uint8_t flags,uint32_t length_bytes,struct image_tool_params * params)132 static void sfp_build_header(uint8_t *buf, uint8_t ver, uint8_t flags,
133 			     uint32_t length_bytes,
134 			     struct image_tool_params *params)
135 {
136 	uint32_t entry_offset = params->eflag ? params->ep : ENTRY_POINT_OFFSET;
137 	struct socfpga_header_v0 header_v0 = {
138 		.validation	= cpu_to_le32(VALIDATION_WORD),
139 		.version	= 0,
140 		.flags		= flags,
141 		.length_u32	= cpu_to_le16(length_bytes / 4),
142 		.zero		= 0,
143 	};
144 
145 	struct socfpga_header_v1 header_v1 = {
146 		.validation	= cpu_to_le32(VALIDATION_WORD),
147 		.version	= 1,
148 		.flags		= flags,
149 		.header_u8	= cpu_to_le16(sizeof(header_v1)),
150 		.length_u8	= cpu_to_le32(length_bytes),
151 		/* Trampoline offset */
152 		.entry_offset	= cpu_to_le32(entry_offset),
153 		.zero		= 0,
154 	};
155 
156 	uint16_t csum;
157 
158 	if (ver == 0) {
159 		csum = sfp_hdr_checksum((uint8_t *)&header_v0, 0);
160 		header_v0.checksum = cpu_to_le16(csum);
161 		memcpy(buf, &header_v0, sizeof(header_v0));
162 	} else {
163 		csum = sfp_hdr_checksum((uint8_t *)&header_v1, 1);
164 		header_v1.checksum = cpu_to_le16(csum);
165 		memcpy(buf, &header_v1, sizeof(header_v1));
166 	}
167 }
168 
169 /*
170  * Perform a rudimentary verification of header and return
171  * size of image.
172  */
sfp_verify_header(const uint8_t * buf,uint8_t * ver)173 static int sfp_verify_header(const uint8_t *buf, uint8_t *ver)
174 {
175 	struct socfpga_header_v0 header_v0;
176 	struct socfpga_header_v1 header_v1;
177 	uint16_t hdr_csum, sfp_csum;
178 	uint32_t img_len;
179 
180 	/*
181 	 * Header v0 is always smaller than Header v1 and the validation
182 	 * word and version field is at the same place, so use Header v0
183 	 * to check for version during verifiction and upgrade to Header
184 	 * v1 if needed.
185 	 */
186 	memcpy(&header_v0, buf, sizeof(header_v0));
187 
188 	if (le32_to_cpu(header_v0.validation) != VALIDATION_WORD)
189 		return -1;
190 
191 	if (header_v0.version == 0) {
192 		hdr_csum = le16_to_cpu(header_v0.checksum);
193 		sfp_csum = sfp_hdr_checksum((uint8_t *)&header_v0, 0);
194 		img_len = le16_to_cpu(header_v0.length_u32) * 4;
195 	} else if (header_v0.version == 1) {
196 		memcpy(&header_v1, buf, sizeof(header_v1));
197 		hdr_csum = le16_to_cpu(header_v1.checksum);
198 		sfp_csum = sfp_hdr_checksum((uint8_t *)&header_v1, 1);
199 		img_len = le32_to_cpu(header_v1.length_u8);
200 	} else {	/* Invalid version */
201 		return -EINVAL;
202 	}
203 
204 	/* Verify checksum */
205 	if (hdr_csum != sfp_csum)
206 		return -EINVAL;
207 
208 	*ver = header_v0.version;
209 	return img_len;
210 }
211 
212 /* Sign the buffer and return the signed buffer size */
sfp_sign_buffer(uint8_t * buf,uint8_t ver,uint8_t flags,int len,int pad_64k,struct image_tool_params * params)213 static int sfp_sign_buffer(uint8_t *buf, uint8_t ver, uint8_t flags,
214 			   int len, int pad_64k,
215 			   struct image_tool_params *params)
216 {
217 	uint32_t calc_crc;
218 	uint32_t crc_off;
219 
220 	/* Align the length up */
221 	len = sfp_aligned_len(len);
222 
223 	/* Build header */
224 	sfp_build_header(buf + HEADER_OFFSET, ver, flags, len, params);
225 
226 	/* Calculate and apply the CRC */
227 	crc_off = len - sizeof(uint32_t); /* at last 4 bytes of image */
228 	calc_crc = ~pbl_crc32(0, (char *)buf, crc_off);
229 
230 	*((uint32_t *)(buf + crc_off)) = cpu_to_le32(calc_crc);
231 
232 	if (!pad_64k)
233 		return len + 4;
234 
235 	return sfp_max_size(ver);
236 }
237 
238 /* Verify that the buffer looks sane */
sfp_verify_buffer(const uint8_t * buf)239 static int sfp_verify_buffer(const uint8_t *buf)
240 {
241 	int len; /* Including 32bit CRC */
242 	uint32_t calc_crc;
243 	uint32_t buf_crc;
244 	uint8_t ver = 0;
245 
246 	len = sfp_verify_header(buf + HEADER_OFFSET, &ver);
247 	if (len < 0) {
248 		debug("Invalid header\n");
249 		return -1;
250 	}
251 
252 	if (len < HEADER_OFFSET || len > sfp_max_size(ver)) {
253 		debug("Invalid header length (%i)\n", len);
254 		return -1;
255 	}
256 
257 	/*
258 	 * Adjust length to the base of the CRC.
259 	 * Check the CRC.
260 	*/
261 	len -= 4;
262 
263 	calc_crc = ~pbl_crc32(0, (const char *)buf, len);
264 
265 	buf_crc = le32_to_cpu(*((uint32_t *)(buf + len)));
266 
267 	if (buf_crc != calc_crc) {
268 		fprintf(stderr, "CRC32 does not match (%08x != %08x)\n",
269 			buf_crc, calc_crc);
270 		return -1;
271 	}
272 
273 	return 0;
274 }
275 
276 /* mkimage glue functions */
socfpgaimage_verify_header(unsigned char * ptr,int image_size,struct image_tool_params * params)277 static int socfpgaimage_verify_header(unsigned char *ptr, int image_size,
278 				      struct image_tool_params *params)
279 {
280 	if (image_size < 0x80)
281 		return -1;
282 
283 	return sfp_verify_buffer(ptr);
284 }
285 
socfpgaimage_print_header_v0(struct socfpga_header_v0 * header)286 static void socfpgaimage_print_header_v0(struct socfpga_header_v0 *header)
287 {
288 	printf("Image Type\t: Cyclone V / Arria V SoC Image\n");
289 	printf("Validation word\t: 0x%08x\n",
290 	       le32_to_cpu(header->validation));
291 	printf("Version\t\t: 0x%08x\n", header->version);
292 	printf("Flags\t\t: 0x%08x\n", header->flags);
293 	printf("Program length\t: 0x%08x\n",
294 	       le16_to_cpu(header->length_u32));
295 	printf("Header checksum\t: 0x%08x\n",
296 	       le16_to_cpu(header->checksum));
297 }
298 
socfpgaimage_print_header_v1(struct socfpga_header_v1 * header)299 static void socfpgaimage_print_header_v1(struct socfpga_header_v1 *header)
300 {
301 	printf("Image Type\t: Arria 10 SoC Image\n");
302 	printf("Validation word\t: 0x%08x\n",
303 	       le32_to_cpu(header->validation));
304 	printf("Version\t\t: 0x%08x\n", header->version);
305 	printf("Flags\t\t: 0x%08x\n", header->flags);
306 	printf("Header length\t: 0x%08x\n",
307 	       le16_to_cpu(header->header_u8));
308 	printf("Program length\t: 0x%08x\n",
309 	       le32_to_cpu(header->length_u8));
310 	printf("Program entry\t: 0x%08x\n",
311 	       le32_to_cpu(header->entry_offset));
312 	printf("Header checksum\t: 0x%08x\n",
313 	       le16_to_cpu(header->checksum));
314 }
315 
socfpgaimage_print_header(const void * ptr)316 static void socfpgaimage_print_header(const void *ptr)
317 {
318 	const void *header = ptr + HEADER_OFFSET;
319 	struct socfpga_header_v0 *header_v0;
320 
321 	if (sfp_verify_buffer(ptr) == 0) {
322 		header_v0 = (struct socfpga_header_v0 *)header;
323 
324 		if (header_v0->version == 0)
325 			socfpgaimage_print_header_v0(header_v0);
326 		else
327 			socfpgaimage_print_header_v1((struct socfpga_header_v1 *)header);
328 	} else {
329 		printf("Not a sane SOCFPGA preloader\n");
330 	}
331 }
332 
socfpgaimage_check_params_v0(struct image_tool_params * params)333 static int socfpgaimage_check_params_v0(struct image_tool_params *params)
334 {
335 	/* Not sure if we should be accepting fflags */
336 	return	(params->dflag && (params->fflag || params->lflag)) ||
337 		(params->fflag && (params->dflag || params->lflag)) ||
338 		(params->lflag && (params->dflag || params->fflag));
339 }
340 
socfpgaimage_check_params_v1(struct image_tool_params * params)341 static int socfpgaimage_check_params_v1(struct image_tool_params *params)
342 {
343 	/*
344 	 * If the entry point is specified, ensure it is >= ENTRY_POINT_OFFSET
345 	 * and it is 4 bytes aligned.
346 	 */
347 	if (params->eflag && (params->ep < ENTRY_POINT_OFFSET ||
348 			      params->ep % 4 != 0)) {
349 		fprintf(stderr,
350 			"Error: Entry point must be greater than 0x%x.\n",
351 			ENTRY_POINT_OFFSET);
352 		return -1;
353 	}
354 
355 	/* Not sure if we should be accepting fflags */
356 	return	(params->dflag && (params->fflag || params->lflag)) ||
357 		(params->fflag && (params->dflag || params->lflag)) ||
358 		(params->lflag && (params->dflag || params->fflag));
359 }
360 
socfpgaimage_check_image_types_v0(uint8_t type)361 static int socfpgaimage_check_image_types_v0(uint8_t type)
362 {
363 	if (type == IH_TYPE_SOCFPGAIMAGE)
364 		return EXIT_SUCCESS;
365 	return EXIT_FAILURE;
366 }
367 
socfpgaimage_check_image_types_v1(uint8_t type)368 static int socfpgaimage_check_image_types_v1(uint8_t type)
369 {
370 	if (type == IH_TYPE_SOCFPGAIMAGE_V1)
371 		return EXIT_SUCCESS;
372 	return EXIT_FAILURE;
373 }
374 
375 /*
376  * To work in with the mkimage framework, we do some ugly stuff...
377  *
378  * First, socfpgaimage_vrec_header() is called.
379  * We prepend a fake header big enough to include crc32 and align image to 16
380  * bytes.
381  * This gives us enough space to do what we want later.
382  *
383  * Next, socfpgaimage_set_header() is called.
384  * We fix up the buffer by moving the image to the start of the buffer.
385  * We now have some room to do what we need (add CRC).
386  */
387 
388 static int data_size;
389 
sfp_fake_header_size(unsigned int size,uint8_t ver)390 static int sfp_fake_header_size(unsigned int size, uint8_t ver)
391 {
392 	unsigned int align_size;
393 
394 	align_size = sfp_aligned_len(size);
395 
396 	/* extra bytes needed */
397 	return align_size - size;
398 }
399 
sfp_vrec_header(struct image_tool_params * params,struct image_type_params * tparams,uint8_t ver)400 static int sfp_vrec_header(struct image_tool_params *params,
401 			   struct image_type_params *tparams, uint8_t ver)
402 {
403 	struct stat sbuf;
404 
405 	if (params->datafile &&
406 	    stat(params->datafile, &sbuf) == 0 &&
407 	    sbuf.st_size <= (sfp_max_size(ver) - sizeof(uint32_t))) {
408 		data_size = sbuf.st_size;
409 		tparams->header_size = sfp_fake_header_size(data_size, ver);
410 	}
411 	return 0;
412 
413 }
414 
socfpgaimage_vrec_header_v0(struct image_tool_params * params,struct image_type_params * tparams)415 static int socfpgaimage_vrec_header_v0(struct image_tool_params *params,
416 				       struct image_type_params *tparams)
417 {
418 	return sfp_vrec_header(params, tparams, 0);
419 }
420 
socfpgaimage_vrec_header_v1(struct image_tool_params * params,struct image_type_params * tparams)421 static int socfpgaimage_vrec_header_v1(struct image_tool_params *params,
422 				       struct image_type_params *tparams)
423 {
424 	return sfp_vrec_header(params, tparams, 1);
425 }
426 
sfp_set_header(void * ptr,unsigned char ver,struct image_tool_params * params)427 static void sfp_set_header(void *ptr, unsigned char ver,
428 			   struct image_tool_params *params)
429 {
430 	uint8_t *buf = (uint8_t *)ptr;
431 
432 	/*
433 	 * This function is called after vrec_header() has been called.
434 	 * At this stage we have the sfp_fake_header_size() dummy bytes
435 	 * followed by data_size image bytes.
436 	 * We need to fix the buffer by moving the image bytes back to
437 	 * the beginning of the buffer, then actually do the signing stuff...
438 	 */
439 	memmove(buf, buf + sfp_fake_header_size(data_size, ver), data_size);
440 	memset(buf + data_size, 0, sfp_fake_header_size(data_size, ver));
441 
442 	sfp_sign_buffer(buf, ver, 0, data_size, 0, params);
443 }
444 
socfpgaimage_set_header_v0(void * ptr,struct stat * sbuf,int ifd,struct image_tool_params * params)445 static void socfpgaimage_set_header_v0(void *ptr, struct stat *sbuf, int ifd,
446 				       struct image_tool_params *params)
447 {
448 	sfp_set_header(ptr, 0, params);
449 }
450 
socfpgaimage_set_header_v1(void * ptr,struct stat * sbuf,int ifd,struct image_tool_params * params)451 static void socfpgaimage_set_header_v1(void *ptr, struct stat *sbuf, int ifd,
452 				       struct image_tool_params *params)
453 {
454 	sfp_set_header(ptr, 1, params);
455 }
456 
457 U_BOOT_IMAGE_TYPE(
458 	socfpgaimage,
459 	"Altera SoCFPGA Cyclone V / Arria V image support",
460 	0, /* This will be modified by vrec_header() */
461 	(void *)buffer_v0,
462 	socfpgaimage_check_params_v0,
463 	socfpgaimage_verify_header,
464 	socfpgaimage_print_header,
465 	socfpgaimage_set_header_v0,
466 	NULL,
467 	socfpgaimage_check_image_types_v0,
468 	NULL,
469 	socfpgaimage_vrec_header_v0
470 );
471 
472 U_BOOT_IMAGE_TYPE(
473 	socfpgaimage_v1,
474 	"Altera SoCFPGA Arria10 image support",
475 	0, /* This will be modified by vrec_header() */
476 	(void *)buffer_v1,
477 	socfpgaimage_check_params_v1,
478 	socfpgaimage_verify_header,
479 	socfpgaimage_print_header,
480 	socfpgaimage_set_header_v1,
481 	NULL,
482 	socfpgaimage_check_image_types_v1,
483 	NULL,
484 	socfpgaimage_vrec_header_v1
485 );
486