xref: /openbmc/u-boot/tools/socfpgaimage.c (revision 1b484736ce47cb220cb523f00ebe77025cab219f)
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  
59  #include <image.h>
60  
61  #define HEADER_OFFSET	0x40
62  #define VALIDATION_WORD	0x31305341
63  
64  static uint8_t buffer_v0[0x10000];
65  static uint8_t buffer_v1[0x40000];
66  
67  struct socfpga_header_v0 {
68  	uint32_t	validation;
69  	uint8_t		version;
70  	uint8_t		flags;
71  	uint16_t	length_u32;
72  	uint16_t	zero;
73  	uint16_t	checksum;
74  };
75  
76  struct socfpga_header_v1 {
77  	uint32_t	validation;
78  	uint8_t		version;
79  	uint8_t		flags;
80  	uint16_t	header_u8;
81  	uint32_t	length_u8;
82  	uint32_t	entry_offset;
83  	uint16_t	zero;
84  	uint16_t	checksum;
85  };
86  
sfp_hdr_size(uint8_t ver)87  static unsigned int sfp_hdr_size(uint8_t ver)
88  {
89  	if (ver == 0)
90  		return sizeof(struct socfpga_header_v0);
91  	if (ver == 1)
92  		return sizeof(struct socfpga_header_v1);
93  	return 0;
94  }
95  
sfp_pad_size(uint8_t ver)96  static unsigned int sfp_pad_size(uint8_t ver)
97  {
98  	if (ver == 0)
99  		return sizeof(buffer_v0);
100  	if (ver == 1)
101  		return sizeof(buffer_v1);
102  	return 0;
103  }
104  
105  /*
106   * The header checksum is just a very simple checksum over
107   * the header area.
108   * There is still a crc32 over the whole lot.
109   */
sfp_hdr_checksum(uint8_t * buf,unsigned char ver)110  static uint16_t sfp_hdr_checksum(uint8_t *buf, unsigned char ver)
111  {
112  	uint16_t ret = 0;
113  	int len = sfp_hdr_size(ver) - sizeof(ret);
114  
115  	while (--len)
116  		ret += *buf++;
117  
118  	return ret;
119  }
120  
sfp_build_header(uint8_t * buf,uint8_t ver,uint8_t flags,uint32_t length_bytes)121  static void sfp_build_header(uint8_t *buf, uint8_t ver, uint8_t flags,
122  			     uint32_t length_bytes)
123  {
124  	struct socfpga_header_v0 header_v0 = {
125  		.validation	= cpu_to_le32(VALIDATION_WORD),
126  		.version	= 0,
127  		.flags		= flags,
128  		.length_u32	= cpu_to_le16(length_bytes / 4),
129  		.zero		= 0,
130  	};
131  
132  	struct socfpga_header_v1 header_v1 = {
133  		.validation	= cpu_to_le32(VALIDATION_WORD),
134  		.version	= 1,
135  		.flags		= flags,
136  		.header_u8	= cpu_to_le16(sizeof(header_v1)),
137  		.length_u8	= cpu_to_le32(length_bytes),
138  		.entry_offset	= cpu_to_le32(0x14),	/* Trampoline offset */
139  		.zero		= 0,
140  	};
141  
142  	uint16_t csum;
143  
144  	if (ver == 0) {
145  		csum = sfp_hdr_checksum((uint8_t *)&header_v0, 0);
146  		header_v0.checksum = cpu_to_le16(csum);
147  		memcpy(buf, &header_v0, sizeof(header_v0));
148  	} else {
149  		csum = sfp_hdr_checksum((uint8_t *)&header_v1, 1);
150  		header_v1.checksum = cpu_to_le16(csum);
151  		memcpy(buf, &header_v1, sizeof(header_v1));
152  	}
153  }
154  
155  /*
156   * Perform a rudimentary verification of header and return
157   * size of image.
158   */
sfp_verify_header(const uint8_t * buf,uint8_t * ver)159  static int sfp_verify_header(const uint8_t *buf, uint8_t *ver)
160  {
161  	struct socfpga_header_v0 header_v0;
162  	struct socfpga_header_v1 header_v1;
163  	uint16_t hdr_csum, sfp_csum;
164  	uint32_t img_len;
165  
166  	/*
167  	 * Header v0 is always smaller than Header v1 and the validation
168  	 * word and version field is at the same place, so use Header v0
169  	 * to check for version during verifiction and upgrade to Header
170  	 * v1 if needed.
171  	 */
172  	memcpy(&header_v0, buf, sizeof(header_v0));
173  
174  	if (le32_to_cpu(header_v0.validation) != VALIDATION_WORD)
175  		return -1;
176  
177  	if (header_v0.version == 0) {
178  		hdr_csum = le16_to_cpu(header_v0.checksum);
179  		sfp_csum = sfp_hdr_checksum((uint8_t *)&header_v0, 0);
180  		img_len = le16_to_cpu(header_v0.length_u32) * 4;
181  	} else if (header_v0.version == 1) {
182  		memcpy(&header_v1, buf, sizeof(header_v1));
183  		hdr_csum = le16_to_cpu(header_v1.checksum);
184  		sfp_csum = sfp_hdr_checksum((uint8_t *)&header_v1, 1);
185  		img_len = le32_to_cpu(header_v1.length_u8);
186  	} else {	/* Invalid version */
187  		return -EINVAL;
188  	}
189  
190  	/* Verify checksum */
191  	if (hdr_csum != sfp_csum)
192  		return -EINVAL;
193  
194  	*ver = header_v0.version;
195  	return img_len;
196  }
197  
198  /* 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)199  static int sfp_sign_buffer(uint8_t *buf, uint8_t ver, uint8_t flags,
200  			   int len, int pad_64k)
201  {
202  	uint32_t calc_crc;
203  
204  	/* Align the length up */
205  	len = (len + 3) & ~3;
206  
207  	/* Build header, adding 4 bytes to length to hold the CRC32. */
208  	sfp_build_header(buf + HEADER_OFFSET, ver, flags, len + 4);
209  
210  	/* Calculate and apply the CRC */
211  	calc_crc = ~pbl_crc32(0, (char *)buf, len);
212  
213  	*((uint32_t *)(buf + len)) = cpu_to_le32(calc_crc);
214  
215  	if (!pad_64k)
216  		return len + 4;
217  
218  	return sfp_pad_size(ver);
219  }
220  
221  /* Verify that the buffer looks sane */
sfp_verify_buffer(const uint8_t * buf)222  static int sfp_verify_buffer(const uint8_t *buf)
223  {
224  	int len; /* Including 32bit CRC */
225  	uint32_t calc_crc;
226  	uint32_t buf_crc;
227  	uint8_t ver = 0;
228  
229  	len = sfp_verify_header(buf + HEADER_OFFSET, &ver);
230  	if (len < 0) {
231  		debug("Invalid header\n");
232  		return -1;
233  	}
234  
235  	if (len < HEADER_OFFSET || len > sfp_pad_size(ver)) {
236  		debug("Invalid header length (%i)\n", len);
237  		return -1;
238  	}
239  
240  	/*
241  	 * Adjust length to the base of the CRC.
242  	 * Check the CRC.
243  	*/
244  	len -= 4;
245  
246  	calc_crc = ~pbl_crc32(0, (const char *)buf, len);
247  
248  	buf_crc = le32_to_cpu(*((uint32_t *)(buf + len)));
249  
250  	if (buf_crc != calc_crc) {
251  		fprintf(stderr, "CRC32 does not match (%08x != %08x)\n",
252  			buf_crc, calc_crc);
253  		return -1;
254  	}
255  
256  	return 0;
257  }
258  
259  /* mkimage glue functions */
socfpgaimage_verify_header(unsigned char * ptr,int image_size,struct image_tool_params * params)260  static int socfpgaimage_verify_header(unsigned char *ptr, int image_size,
261  				      struct image_tool_params *params)
262  {
263  	if (image_size < 0x80)
264  		return -1;
265  
266  	return sfp_verify_buffer(ptr);
267  }
268  
socfpgaimage_print_header(const void * ptr)269  static void socfpgaimage_print_header(const void *ptr)
270  {
271  	if (sfp_verify_buffer(ptr) == 0)
272  		printf("Looks like a sane SOCFPGA preloader\n");
273  	else
274  		printf("Not a sane SOCFPGA preloader\n");
275  }
276  
socfpgaimage_check_params(struct image_tool_params * params)277  static int socfpgaimage_check_params(struct image_tool_params *params)
278  {
279  	/* Not sure if we should be accepting fflags */
280  	return	(params->dflag && (params->fflag || params->lflag)) ||
281  		(params->fflag && (params->dflag || params->lflag)) ||
282  		(params->lflag && (params->dflag || params->fflag));
283  }
284  
socfpgaimage_check_image_types_v0(uint8_t type)285  static int socfpgaimage_check_image_types_v0(uint8_t type)
286  {
287  	if (type == IH_TYPE_SOCFPGAIMAGE)
288  		return EXIT_SUCCESS;
289  	return EXIT_FAILURE;
290  }
291  
socfpgaimage_check_image_types_v1(uint8_t type)292  static int socfpgaimage_check_image_types_v1(uint8_t type)
293  {
294  	if (type == IH_TYPE_SOCFPGAIMAGE_V1)
295  		return EXIT_SUCCESS;
296  	return EXIT_FAILURE;
297  }
298  
299  /*
300   * To work in with the mkimage framework, we do some ugly stuff...
301   *
302   * First, socfpgaimage_vrec_header() is called.
303   * We prepend a fake header big enough to make the file sfp_pad_size().
304   * This gives us enough space to do what we want later.
305   *
306   * Next, socfpgaimage_set_header() is called.
307   * We fix up the buffer by moving the image to the start of the buffer.
308   * We now have some room to do what we need (add CRC and padding).
309   */
310  
311  static int data_size;
312  
sfp_fake_header_size(unsigned int size,uint8_t ver)313  static int sfp_fake_header_size(unsigned int size, uint8_t ver)
314  {
315  	return sfp_pad_size(ver) - size;
316  }
317  
sfp_vrec_header(struct image_tool_params * params,struct image_type_params * tparams,uint8_t ver)318  static int sfp_vrec_header(struct image_tool_params *params,
319  			   struct image_type_params *tparams, uint8_t ver)
320  {
321  	struct stat sbuf;
322  
323  	if (params->datafile &&
324  	    stat(params->datafile, &sbuf) == 0 &&
325  	    sbuf.st_size <= (sfp_pad_size(ver) - sizeof(uint32_t))) {
326  		data_size = sbuf.st_size;
327  		tparams->header_size = sfp_fake_header_size(data_size, ver);
328  	}
329  	return 0;
330  
331  }
332  
socfpgaimage_vrec_header_v0(struct image_tool_params * params,struct image_type_params * tparams)333  static int socfpgaimage_vrec_header_v0(struct image_tool_params *params,
334  				       struct image_type_params *tparams)
335  {
336  	return sfp_vrec_header(params, tparams, 0);
337  }
338  
socfpgaimage_vrec_header_v1(struct image_tool_params * params,struct image_type_params * tparams)339  static int socfpgaimage_vrec_header_v1(struct image_tool_params *params,
340  				       struct image_type_params *tparams)
341  {
342  	return sfp_vrec_header(params, tparams, 1);
343  }
344  
sfp_set_header(void * ptr,unsigned char ver)345  static void sfp_set_header(void *ptr, unsigned char ver)
346  {
347  	uint8_t *buf = (uint8_t *)ptr;
348  
349  	/*
350  	 * This function is called after vrec_header() has been called.
351  	 * At this stage we have the sfp_fake_header_size() dummy bytes
352  	 * followed by data_size image bytes. Total = sfp_pad_size().
353  	 * We need to fix the buffer by moving the image bytes back to
354  	 * the beginning of the buffer, then actually do the signing stuff...
355  	 */
356  	memmove(buf, buf + sfp_fake_header_size(data_size, ver), data_size);
357  	memset(buf + data_size, 0, sfp_fake_header_size(data_size, ver));
358  
359  	sfp_sign_buffer(buf, ver, 0, data_size, 0);
360  }
361  
socfpgaimage_set_header_v0(void * ptr,struct stat * sbuf,int ifd,struct image_tool_params * params)362  static void socfpgaimage_set_header_v0(void *ptr, struct stat *sbuf, int ifd,
363  				       struct image_tool_params *params)
364  {
365  	sfp_set_header(ptr, 0);
366  }
367  
socfpgaimage_set_header_v1(void * ptr,struct stat * sbuf,int ifd,struct image_tool_params * params)368  static void socfpgaimage_set_header_v1(void *ptr, struct stat *sbuf, int ifd,
369  				       struct image_tool_params *params)
370  {
371  	sfp_set_header(ptr, 1);
372  }
373  
374  U_BOOT_IMAGE_TYPE(
375  	socfpgaimage,
376  	"Altera SoCFPGA Cyclone V / Arria V image support",
377  	0, /* This will be modified by vrec_header() */
378  	(void *)buffer_v0,
379  	socfpgaimage_check_params,
380  	socfpgaimage_verify_header,
381  	socfpgaimage_print_header,
382  	socfpgaimage_set_header_v0,
383  	NULL,
384  	socfpgaimage_check_image_types_v0,
385  	NULL,
386  	socfpgaimage_vrec_header_v0
387  );
388  
389  U_BOOT_IMAGE_TYPE(
390  	socfpgaimage_v1,
391  	"Altera SoCFPGA Arria10 image support",
392  	0, /* This will be modified by vrec_header() */
393  	(void *)buffer_v1,
394  	socfpgaimage_check_params,
395  	socfpgaimage_verify_header,
396  	socfpgaimage_print_header,
397  	socfpgaimage_set_header_v1,
398  	NULL,
399  	socfpgaimage_check_image_types_v1,
400  	NULL,
401  	socfpgaimage_vrec_header_v1
402  );
403