diff mbox

[U-Boot,v6] socfpga: Add socfpga preloader signing to mkimage

Message ID 1393472979-7522-1-git-send-email-cdhmanning@gmail.com
State Superseded
Delegated to: Albert ARIBAUD
Headers show

Commit Message

Charles Manning Feb. 27, 2014, 3:49 a.m. UTC
Like many platforms, the Altera socfpga platform requires that the
preloader be "signed" in a certain way or the built-in boot ROM will
not boot the code.

This change automatically creates an appropriately signed preloader
from an SPL image.

The signed image includes a CRC which must, of course, be generated
with a CRC generator that the SoCFPGA boot ROM agrees with otherwise
the boot ROM will reject the image.

Unfortunately the CRC used in this boot ROM is not the same as the
Adler CRC in lib/crc32.c. Indeed the Adler code is not technically a
CRC but is more correctly described as a checksum.

Thus, the appropriate CRC generator is added to lib/ as crc32_alt.c.

Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---

Changes for v3:
 - Fix some coding style issues.
 - Move from a standalone tool to the mkimgae framework.

Changes for v4:
 - Fix more coding style issues.
 - Fix typos in Makefile.
 - Rebase on master (previous version was not on master, but on a 
   working socfpga branch).

Changes for v5:
 - Fix more coding style issues.
 - Add some more comments.
 - Remove some unused defines.
 - Move the local CRC32 code into lib/crc32_alt.c.

Changes for v6:
 - Fix more coding style issues.
 - Rejig socfpgaimage_vrec_header() function so that it has one return 
   path and does stricter size checks.

Note: Building a SOCFPGA preloader will currently not produe a working
image if built in master, but that is due to issues in building SPL,
not in this signer.


 common/image.c       |    1 +
 include/crc32_alt.h  |   17 +++
 include/image.h      |    1 +
 lib/Makefile         |    1 +
 lib/crc32_alt.c      |   94 +++++++++++++++++
 spl/Makefile         |    5 +
 tools/Makefile       |    2 +
 tools/crc32_alt.c    |    1 +
 tools/imagetool.c    |    2 +
 tools/imagetool.h    |    1 +
 tools/socfpgaimage.c |  278 ++++++++++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 403 insertions(+)
 create mode 100644 include/crc32_alt.h
 create mode 100644 lib/crc32_alt.c
 create mode 100644 tools/crc32_alt.c
 create mode 100644 tools/socfpgaimage.c

Comments

Wolfgang Denk Feb. 27, 2014, 9:57 p.m. UTC | #1
Dear Charles,

In message <1393472979-7522-1-git-send-email-cdhmanning@gmail.com> you wrote:
> Like many platforms, the Altera socfpga platform requires that the
> preloader be "signed" in a certain way or the built-in boot ROM will
> not boot the code.
...

> diff --git a/include/crc32_alt.h b/include/crc32_alt.h
> new file mode 100644
> index 0000000..813d55d
> --- /dev/null
> +++ b/include/crc32_alt.h

"alt" is a bad name as there is more than one alternative. Please use
a descriptive name.

> --- /dev/null
> +++ b/lib/crc32_alt.c
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + *
> + * Note that the CRC is **not** the zlib/Adler crc32 in crc32.c.
> + * It is the CRC-32 used in bzip2, ethernet and elsewhere.
> + */

I understand this was copied from "lib/bzlib_crctable.c" ? BUt you
claim copyright on this, without any attribution where you got it
form.  This is very, vary bad.

> +static uint32_t crc_table[256] = {
> +	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
...
> +	0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
> +};

Indeed this looks very much like a duplication of code we have
elsewhere:

- in "lib/bzlib_crctable.c" (as BZ2_crc32Table[])
- in "drivers/mtd/ubi/crc32table.h" (as crc32table_be[])


> +uint32_t crc32_alt(uint32_t crc, const void *_buf, int length)
> +{
> +	const uint8_t *buf = _buf;
> +
> +	crc ^= ~0;
> +
> +	while (length--) {
> +		crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *buf) & 0xff];
> +		buf++;
> +	}
> +
> +	crc ^= ~0;
> +
> +	return crc;
> +}

In addition to this, we also have
- crc32 in "lib/crc32.c"
- crc32() in "tools/mxsimage.c"
- make_crc_table() and pbl_crc32() in "tools/pblimage.c"


I really think we should factor out the common tables and code here.
I will not accept yet another duplication of this - we already have
way too many of these.

> --- /dev/null
> +++ b/tools/socfpgaimage.c
> @@ -0,0 +1,278 @@
...
> + * Endian is LSB.

What does that mean? When talking about endianess, I know
"Big-endian" and "Little-endian" - LSB is meaningless in this context
(unless you write something like "LSB first" or "LSB last", but even
this would not be really clear).

> + * Note that the CRC used here is **not** the zlib/Adler crc32. It is the
> + * CRC-32 used in bzip2, ethernet and elsewhere.

Does this have a name?

> + * The image is padded out to 64k, because that is what is
> + * typically used to write the image to the boot medium.
> + */

"typically used" - by what or whom?  Is there any rechnical reason for
such padding?  If not, can we not rather omit this?

> +/*
> + * Some byte marshalling functions...
> + * These load or get little endian values to/from the
> + * buffer.
> + */
> +static void load_le16(uint8_t *buf, uint16_t v)
> +{
> +	buf[0] = (v >> 0) & 0xff;
> +	buf[1] = (v >> 8) & 0xff;
> +}
> +
> +static void load_le32(uint8_t *buf, uint32_t v)
> +{
> +	buf[0] = (v >>  0) & 0xff;
> +	buf[1] = (v >>  8) & 0xff;
> +	buf[2] = (v >> 16) & 0xff;
> +	buf[3] = (v >> 24) & 0xff;
> +}

These are misnomers.  You do not load something, but instead you store
the value of 'v' into the buffer 'buf'.

And why do you invent new functions here instead of using existing
code (like put_unaligned_le16(), put_unaligned_le32()) ?

> +static uint16_t get_le16(const uint8_t *buf)
> +{
> +	uint16_t retval;
> +
> +	retval = (((uint16_t) buf[0]) << 0) |
> +		 (((uint16_t) buf[1]) << 8);
> +	return retval;
> +}
> +
> +static uint32_t get_le32(const uint8_t *buf)
> +{
> +	uint32_t retval;
> +
> +	retval = (((uint32_t) buf[0]) <<  0) |
> +		 (((uint32_t) buf[1]) <<  8) |
> +		 (((uint32_t) buf[2]) << 16) |
> +		 (((uint32_t) buf[3]) << 24);
> +	return retval;
> +}

Why do you not use existing code (like get_unaligned_le16(),
get_unaligned_le32()) ?

> +static int align4(int v)
> +{
> +	return ((v + 3) / 4) * 4;
> +}

Don't we have macros to do this?


Best regards,

Wolfgang Denk
Chin Liang See Feb. 27, 2014, 10:34 p.m. UTC | #2
Hi Charles,

I hit error when trying to apply the patch
bash-3.2$ git apply signing.patch 
fatal: corrupt patch at line 205



On Thu, 2014-02-27 at 16:49 +1300, Charles Manning wrote:
> Like many platforms, the Altera socfpga platform requires that the
> preloader be "signed" in a certain way or the built-in boot ROM will
> not boot the code.
> 
> This change automatically creates an appropriately signed preloader
> from an SPL image.
> 
> The signed image includes a CRC which must, of course, be generated
> with a CRC generator that the SoCFPGA boot ROM agrees with otherwise
> the boot ROM will reject the image.
> 
> Unfortunately the CRC used in this boot ROM is not the same as the
> Adler CRC in lib/crc32.c. Indeed the Adler code is not technically a
> CRC but is more correctly described as a checksum.
> 
> Thus, the appropriate CRC generator is added to lib/ as crc32_alt.c.
> 
> Signed-off-by: Charles Manning <cdhmanning@gmail.com>
> ---
> 
> Changes for v3:
>  - Fix some coding style issues.
>  - Move from a standalone tool to the mkimgae framework.
> 
> Changes for v4:
>  - Fix more coding style issues.
>  - Fix typos in Makefile.
>  - Rebase on master (previous version was not on master, but on a 
>    working socfpga branch).
> 
> Changes for v5:
>  - Fix more coding style issues.
>  - Add some more comments.
>  - Remove some unused defines.
>  - Move the local CRC32 code into lib/crc32_alt.c.
> 
> Changes for v6:
>  - Fix more coding style issues.
>  - Rejig socfpgaimage_vrec_header() function so that it has one return 
>    path and does stricter size checks.
> 
> Note: Building a SOCFPGA preloader will currently not produe a working
> image if built in master, but that is due to issues in building SPL,
> not in this signer.
> 
> 
>  common/image.c       |    1 +
>  include/crc32_alt.h  |   17 +++
>  include/image.h      |    1 +
>  lib/Makefile         |    1 +
>  lib/crc32_alt.c      |   94 +++++++++++++++++
>  spl/Makefile         |    5 +
>  tools/Makefile       |    2 +
>  tools/crc32_alt.c    |    1 +
>  tools/imagetool.c    |    2 +
>  tools/imagetool.h    |    1 +
>  tools/socfpgaimage.c |  278 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  11 files changed, 403 insertions(+)
>  create mode 100644 include/crc32_alt.h
>  create mode 100644 lib/crc32_alt.c
>  create mode 100644 tools/crc32_alt.c
>  create mode 100644 tools/socfpgaimage.c
> 
> diff --git a/common/image.c b/common/image.c
> index 9c6bec5..e7dc8cc 100644
> --- a/common/image.c
> +++ b/common/image.c
> @@ -135,6 +135,7 @@ static const table_entry_t uimage_type[] = {
>  	{	IH_TYPE_PBLIMAGE,   "pblimage",   "Freescale PBL Boot Image",},
>  	{	IH_TYPE_RAMDISK,    "ramdisk",	  "RAMDisk Image",	},
>  	{	IH_TYPE_SCRIPT,     "script",	  "Script",		},
> +	{	IH_TYPE_SOCFPGAIMAGE,  "socfpgaimage",  "Altera SOCFPGA preloader",},
>  	{	IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
>  	{	IH_TYPE_UBLIMAGE,   "ublimage",   "Davinci UBL image",},
>  	{	IH_TYPE_MXSIMAGE,   "mxsimage",   "Freescale MXS Boot Image",},
> diff --git a/include/crc32_alt.h b/include/crc32_alt.h
> new file mode 100644
> index 0000000..813d55d
> --- /dev/null
> +++ b/include/crc32_alt.h
> @@ -0,0 +1,17 @@
> +/*
> + * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + *
> + * Note that the CRC is **not** the zlib/Adler crc32 in crc32.c.
> + * It is the CRC-32 used in bzip2, ethernet and elsewhere.
> + */
> +
> +#ifndef __CRC32_ALT_H__
> +#define __CRC32_ALT_H__
> +
> +#include <stdint.h>
> +
> +uint32_t crc32_alt(uint32_t crc, const void *_buf, int length);
> +
> +#endif
> diff --git a/include/image.h b/include/image.h
> index 6afd57b..bde31d9 100644
> --- a/include/image.h
> +++ b/include/image.h
> @@ -215,6 +215,7 @@ struct lmb;
>  #define IH_TYPE_KERNEL_NOLOAD	14	/* OS Kernel Image, can run from any load address */
>  #define IH_TYPE_PBLIMAGE	15	/* Freescale PBL Boot Image	*/
>  #define IH_TYPE_MXSIMAGE	16	/* Freescale MXSBoot Image	*/
> +#define IH_TYPE_SOCFPGAIMAGE	17	/* Altera SOCFPGA Preloader	*/
>  
>  /*
>   * Compression Types
> diff --git a/lib/Makefile b/lib/Makefile
> index 8c483c9..7ee07a5 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -52,6 +52,7 @@ obj-y += errno.o
>  obj-y += display_options.o
>  obj-$(CONFIG_BCH) += bch.o
>  obj-y += crc32.o
> +obj-y += crc32_alt.o
>  obj-y += ctype.o
>  obj-y += div64.o
>  obj-y += hang.o
> diff --git a/lib/crc32_alt.c b/lib/crc32_alt.c
> new file mode 100644
> index 0000000..e0db335
> --- /dev/null
> +++ b/lib/crc32_alt.c
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + *
> + * Note that the CRC is **not** the zlib/Adler crc32 in crc32.c.
> + * It is the CRC-32 used in bzip2, ethernet and elsewhere.
> + */
> +
> +#include <crc32_alt.h>
> +#include <stdint.h>
> +
> +static uint32_t crc_table[256] = {
> +	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
> +	0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
> +	0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
> +	0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
> +	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
> +	0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
> +	0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
> +	0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
> +	0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
> +	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
> +	0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
> +	0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
> +	0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
> +	0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
> +	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
> +	0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
> +	0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
> +	0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
> +	0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
> +	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
> +	0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
> +	0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
> +	0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
> +	0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
> +	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
> +	0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
> +	0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
> +	0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
> +	0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
> +	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
> +	0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
> +	0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
> +	0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
> +	0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
> +	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
> +	0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
> +	0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
> +	0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
> +	0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
> +	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
> +	0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
> +	0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
> +	0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
> +	0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
> +	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
> +	0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
> +	0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
> +	0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
> +	0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
> +	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
> +	0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
> +	0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
> +	0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
> +	0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
> +	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
> +	0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
> +	0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
> +	0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
> +	0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
> +	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
> +	0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
> +	0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
> +	0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
> +	0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
> +};
> +
> +uint32_t crc32_alt(uint32_t crc, const void *_buf, int length)
> +{
> +	const uint8_t *buf = _buf;
> +
> +	crc ^= ~0;
> +
> +	while (length--) {
> +		crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *buf) & 0xff];
> +		buf++;
> +	}
> +
> +	crc ^= ~0;
> +
> +	return crc;
> +}


This function is the same as BZ_UPDATE_CRC within lib/bzlib_private.h.


> diff --git a/spl/Makefile b/spl/Makefile
> index bf98024..bce9055 100644
> --- a/spl/Makefile
> +++ b/spl/Makefile
> @@ -181,6 +181,11 @@ $(objtree)/SPL : $(obj)/u-boot-spl.bin
>  
>  ALL-y	+= $(obj)/$(SPL_BIN).bin
>  
> +$(OBJTREE)/socfpga-signed-preloader.bin: $(obj)/u-boot-spl.bin
> +	$(OBJTREE)/tools/mkimage -T socfpgaimage -d $< $@
> +
> +ALL-$(CONFIG_SOCFPGA) += $(OBJTREE)/socfpga-signed-preloader.bin
> +
>  ifdef CONFIG_SAMSUNG
>  ALL-y	+= $(obj)/$(BOARD)-spl.bin
>  endif
> diff --git a/tools/Makefile b/tools/Makefile
> index dcd49f8..46af0b1 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -71,6 +71,7 @@ RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := rsa-sign.o
>  dumpimage-mkimage-objs := aisimage.o \
>  			$(FIT_SIG_OBJS-y) \
>  			crc32.o \
> +			crc32_alt.o \
>  			default_image.o \
>  			fit_image.o \
>  			image-fit.o \
> @@ -85,6 +86,7 @@ dumpimage-mkimage-objs := aisimage.o \
>  			os_support.o \
>  			pblimage.o \
>  			sha1.o \
> +			socfpgaimage.o \
>  			ublimage.o \
>  			$(LIBFDT_OBJS) \
>  			$(RSA_OBJS-y)
> diff --git a/tools/crc32_alt.c b/tools/crc32_alt.c
> new file mode 100644
> index 0000000..3faa222
> --- /dev/null
> +++ b/tools/crc32_alt.c
> @@ -0,0 +1 @@
> +#include "../lib/crc32_alt.c"
> diff --git a/tools/imagetool.c b/tools/imagetool.c
> index 29d2189..1ef20b1 100644
> --- a/tools/imagetool.c
> +++ b/tools/imagetool.c
> @@ -45,6 +45,8 @@ void register_image_tool(imagetool_register_t image_register)
>  	init_ubl_image_type();
>  	/* Init Davinci AIS support */
>  	init_ais_image_type();
> +	/* Init Altera SOCFPGA support */
> +	init_socfpga_image_type();
>  }
>  
>  /*
> diff --git a/tools/imagetool.h b/tools/imagetool.h
> index c2c9aea..c4833b1 100644
> --- a/tools/imagetool.h
> +++ b/tools/imagetool.h
> @@ -167,6 +167,7 @@ void init_mxs_image_type(void);
>  void init_fit_image_type(void);
>  void init_ubl_image_type(void);
>  void init_omap_image_type(void);
> +void init_socfpga_image_type(void);
>  
>  void pbl_load_uboot(int fd, struct image_tool_params *mparams);
>  
> diff --git a/tools/socfpgaimage.c b/tools/socfpgaimage.c
> new file mode 100644
> index 0000000..842c1b0
> --- /dev/null
> +++ b/tools/socfpgaimage.c
> @@ -0,0 +1,278 @@
> +/*
> + * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + *
> + * Reference doc http://www.altera.com.cn/literature/hb/cyclone-v/cv_5400A.pdf
> + * Note this doc is not entirely accurate. Of particular interest to us is the
> + * "header" length field being in U32s and not bytes.
> + *
> + * "Header" is a structure of the following format.
> + * this is positioned at 0x40.
> + *
> + * Endian is LSB.
> + *
> + * Offset   Length   Usage
> + * -----------------------
> + *   0x40        4   Validation word 0x31305341
> + *   0x44        1   Version (whatever, zero is fine)
> + *   0x45        1   Flags   (unused, zero is fine)
> + *   0x46        2   Length  (in units of u32, including the end checksum).
> + *   0x48        2   Zero
> + *   0x4A        2   Checksum over the heder. NB Not CRC32
> + *
> + * At the end of the code we have a 32-bit CRC checksum over whole binary
> + * excluding the CRC.
> + *
> + * Note that the CRC used here is **not** the zlib/Adler crc32. It is the
> + * CRC-32 used in bzip2, ethernet and elsewhere.
> + *
> + * The image is padded out to 64k, because that is what is
> + * typically used to write the image to the boot medium.
> + */
> +
> +#include <crc32_alt.h>
> +#include "imagetool.h"
> +#include <image.h>
> +
> +#define HEADER_OFFSET	0x40
> +#define HEADER_SIZE	0xC
> +#define VALIDATION_WORD	0x31305341
> +#define PADDED_SIZE	0x10000
> +
> +/* To allow for adding CRC, the max input size is a bit smaller. */
> +#define MAX_INPUT_SIZE	(PADDED_SIZE - sizeof(uint32_t))
> +
> +static uint8_t buffer[PADDED_SIZE];
> +
> +/*
> + * The header checksum is just a very simple checksum over
> + * the header area.
> + * There is still a crc32 over the whole lot.
> + */
> +static uint16_t hdr_checksum(const uint8_t *buf, int len)
> +{
> +	uint16_t ret = 0;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		ret += (((uint16_t) *buf) & 0xff);
> +		buf++;
> +	}
> +	return ret;
> +}
> +
> +/*
> + * Some byte marshalling functions...
> + * These load or get little endian values to/from the
> + * buffer.
> + */
> +static void load_le16(uint8_t *buf, uint16_t v)
> +{
> +	buf[0] = (v >> 0) & 0xff;
> +	buf[1] = (v >> 8) & 0xff;
> +}
> +
> +static void load_le32(uint8_t *buf, uint32_t v)
> +{
> +	buf[0] = (v >>  0) & 0xff;
> +	buf[1] = (v >>  8) & 0xff;
> +	buf[2] = (v >> 16) & 0xff;
> +	buf[3] = (v >> 24) & 0xff;
> +}
> +
> +static uint16_t get_le16(const uint8_t *buf)
> +{
> +	uint16_t retval;
> +
> +	retval = (((uint16_t) buf[0]) << 0) |
> +		 (((uint16_t) buf[1]) << 8);
> +	return retval;
> +}
> +
> +static uint32_t get_le32(const uint8_t *buf)
> +{
> +	uint32_t retval;
> +
> +	retval = (((uint32_t) buf[0]) <<  0) |
> +		 (((uint32_t) buf[1]) <<  8) |
> +		 (((uint32_t) buf[2]) << 16) |
> +		 (((uint32_t) buf[3]) << 24);
> +	return retval;
> +}
> +
> +static int align4(int v)
> +{
> +	return ((v + 3) / 4) * 4;
> +}
> +
> +static void build_header(uint8_t *buf,
> +			  uint8_t version,
> +			  uint8_t flags,
> +			  uint16_t length_bytes)
> +{
> +	memset(buf, 0, HEADER_SIZE);
> +
> +	load_le32(buf + 0, VALIDATION_WORD);
> +	buf[4] = version;
> +	buf[5] = flags;
> +	load_le16(buf + 6, length_bytes/4);
> +	load_le16(buf + 10, hdr_checksum(buf, 10));
> +}
> +
> +/*
> + * Perform a rudimentary verification of header and return
> + * size of image.
> + */
> +static int verify_header(const uint8_t *buf)
> +{
> +	if (get_le32(buf) != VALIDATION_WORD)
> +		return -1;
> +	if (get_le16(buf + 10) != hdr_checksum(buf, 10))
> +		return -1;
> +
> +	return get_le16(buf + 6) * 4;
> +}
> +
> +/* Sign the buffer and return the signed buffer size */
> +static int sign_buffer(uint8_t *buf,
> +			uint8_t version, uint8_t flags,
> +			int len, int pad_64k)
> +{
> +	uint32_t crcval;
> +
> +	/* Align the length up */
> +	len = align4(len);
> +
> +	/* Build header, adding 4 bytes to length to hold the CRC32. */
> +	build_header(buf + HEADER_OFFSET,  version, flags, len + 4);
> +
> +	crcval = crc32_alt(0, buf, len);
> +
> +	load_le32(buf + len, crcval);
> +
> +	if (!pad_64k)
> +		return len + 4;
> +
> +	return PADDED_SIZE;
> +}
> +
> +/* Verify that the buffer looks sane */
> +static int verify_buffer(const uint8_t *buf)
> +{
> +	int len; /* Including 32bit CRC */
> +	uint32_t crccalc;
> +
> +	len = verify_header(buf + HEADER_OFFSET);
> +	if (len < 0)
> +		return -1;
> +	if (len < HEADER_OFFSET || len > PADDED_SIZE)
> +		return -1;
> +
> +	/* Adjust length, removing CRC */
> +	len -= 4;
> +
> +	crccalc = crc32_alt(0, buf, len);
> +
> +	if (get_le32(buf + len) != crccalc)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +/* mkimage glue functions */
> +static int socfpgaimage_verify_header(unsigned char *ptr, int image_size,
> +			struct image_tool_params *params)
> +{
> +	if (image_size != PADDED_SIZE)
> +		return -1;
> +
> +	return verify_buffer(ptr);
> +}
> +
> +static void socfpgaimage_print_header(const void *ptr)
> +{
> +	if (verify_buffer(ptr) == 0)
> +		printf("Looks like a sane SOCFPGA preloader\n");
> +	else
> +		printf("Not a sane SOCFPGA preloader\n");
> +}
> +
> +static int socfpgaimage_check_params(struct image_tool_params *params)
> +{
> +	/* Not sure if we should be accepting fflags */
> +	return	(params->dflag && (params->fflag || params->lflag)) ||
> +		(params->fflag && (params->dflag || params->lflag)) ||
> +		(params->lflag && (params->dflag || params->fflag));
> +}
> +
> +static int socfpgaimage_check_image_types(uint8_t type)
> +{
> +	if (type == IH_TYPE_SOCFPGAIMAGE)
> +		return EXIT_SUCCESS;
> +	return EXIT_FAILURE;
> +}
> +
> +/*
> + * To work in with the mkimage framework, we do some ugly stuff...
> + *
> + * First, socfpgaimage_vrec_header() is called.
> + * We prepend a fake header big enough to make the file PADDED_SIZE.
> + * This gives us enough space to do what we want later.
> + *
> + * Next, socfpgaimage_set_header() is called.
> + * We fix up the buffer by moving the image to the start of the buffer.
> + * We now have some room to do what we need (add CRC and padding).
> + */
> +
> +static int data_size;
> +#define FAKE_HEADER_SIZE (PADDED_SIZE - data_size)
> +
> +static int socfpgaimage_vrec_header(struct image_tool_params *params,
> +				struct image_type_params *tparams)
> +{
> +	struct stat sbuf;
> +
> +	if (params->datafile &&
> +	    stat(params->datafile, &sbuf) == 0 &&
> +	    sbuf.st_size <= MAX_INPUT_SIZE) {
> +		data_size = sbuf.st_size;
> +		tparams->header_size = FAKE_HEADER_SIZE;
> +	}
> +	return 0;
> +}
> +
> +static void socfpgaimage_set_header(void *ptr, struct stat *sbuf, int ifd,
> +				struct image_tool_params *params)
> +{
> +	uint8_t *buf = (uint8_t *)ptr;
> +
> +	/*
> +	 * This function is called after vrec_header() has been called.
> +	 * At this stage we have the FAKE_HEADER_SIZE dummy bytes followed by
> +	 * data_size image bytes. Total = PADDED_SIZE.
> +	 * We need to fix the buffer by moving the image bytes back to
> +	 * the beginning of the buffer, then actually do the signing stuff...
> +	 */
> +	memmove(buf, buf + FAKE_HEADER_SIZE, data_size);
> +	memset(buf + data_size, 0, FAKE_HEADER_SIZE);
> +
> +	sign_buffer(buf, 0, 0, data_size, 0);
> +}
> +
> +static struct image_type_params socfpgaimage_params = {
> +	.name		= "Altera SOCFPGA preloader support",
> +	.vrec_header	= socfpgaimage_vrec_header,
> +	.header_size	= 0, /* This will be modified by vrec_header() */
> +	.hdr		= (void *)buffer,
> +	.check_image_type = socfpgaimage_check_image_types,
> +	.verify_header	= socfpgaimage_verify_header,
> +	.print_header	= socfpgaimage_print_header,
> +	.set_header	= socfpgaimage_set_header,
> +	.check_params	= socfpgaimage_check_params,
> +};
> +
> +void init_socfpga_image_type(void)
> +{
> +	register_image_type(&socfpgaimage_params);
> +}
Charles Manning Feb. 27, 2014, 10:43 p.m. UTC | #3
On Friday 28 February 2014 10:57:21 Wolfgang Denk wrote:
> Dear Charles,
>
> In message <1393472979-7522-1-git-send-email-cdhmanning@gmail.com> you 
wrote:
> > Like many platforms, the Altera socfpga platform requires that the
> > preloader be "signed" in a certain way or the built-in boot ROM will
> > not boot the code.
>
> ...
>
> > diff --git a/include/crc32_alt.h b/include/crc32_alt.h
> > new file mode 100644
> > index 0000000..813d55d
> > --- /dev/null
> > +++ b/include/crc32_alt.h
>
> "alt" is a bad name as there is more than one alternative. Please use
> a descriptive name.

Ok I shall do that.


>
> > --- /dev/null
> > +++ b/lib/crc32_alt.c
> > @@ -0,0 +1,94 @@
> > +/*
> > + * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
> > + *
> > + * SPDX-License-Identifier:	GPL-2.0+
> > + *
> > + * Note that the CRC is **not** the zlib/Adler crc32 in crc32.c.
> > + * It is the CRC-32 used in bzip2, ethernet and elsewhere.
> > + */
>
> I understand this was copied from "lib/bzlib_crctable.c" ? BUt you
> claim copyright on this, without any attribution where you got it
> form.  This is very, vary bad.

You understand incorrectly. I did not copy it from bzlib.  I generated it.
I had generated this table before I even knew it was part of 
ib/bzlib_crctable.c.

Of course it **must** have the same values in it because that is how the 
mathematics works out.

I hope you are as free with your retractions as you are with your accusations!

>
> > +static uint32_t crc_table[256] = {
> > +	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
>
> ...
>
> > +	0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
> > +};
>
> Indeed this looks very much like a duplication of code we have
> elsewhere:
>
> - in "lib/bzlib_crctable.c" (as BZ2_crc32Table[])
> - in "drivers/mtd/ubi/crc32table.h" (as crc32table_be[])
>
> > +uint32_t crc32_alt(uint32_t crc, const void *_buf, int length)
> > +{
> > +	const uint8_t *buf = _buf;
> > +
> > +	crc ^= ~0;
> > +
> > +	while (length--) {
> > +		crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *buf) & 0xff];
> > +		buf++;
> > +	}
> > +
> > +	crc ^= ~0;
> > +
> > +	return crc;
> > +}
>
> In addition to this, we also have
> - crc32 in "lib/crc32.c"
> - crc32() in "tools/mxsimage.c"
> - make_crc_table() and pbl_crc32() in "tools/pblimage.c"

>
>
> I really think we should factor out the common tables and code here.
> I will not accept yet another duplication of this - we already have
> way too many of these.

Based on your comments in another thread, I have suggested that I do one of 
two things:

1) Either have a new C file in lib that uses the bzlib table or
2) Extend the bzlib in a way that exposes a function called
crc32_bzlib() or bzlib_crc32().

Whichever you like.

It seems to me that refactoring is best kept as a different patch.

May I humbly submit that it would be a good idea to bed this socfpga signer 
down. Then, as a separate commit and a separate patch, I will refactor with 
pbllimage and mxsimage. 

Does that sound OK with you?

>
> > --- /dev/null
> > +++ b/tools/socfpgaimage.c
> > @@ -0,0 +1,278 @@
>
> ...
>
> > + * Endian is LSB.
>
> What does that mean? When talking about endianess, I know
> "Big-endian" and "Little-endian" - LSB is meaningless in this context
> (unless you write something like "LSB first" or "LSB last", but even
> this would not be really clear).

Sorry typo. I will fix.

>
> > + * Note that the CRC used here is **not** the zlib/Adler crc32. It is
> > the + * CRC-32 used in bzip2, ethernet and elsewhere.
>
> Does this have a name?
CRC-32 ... the real one. Adler was really a bit naughty in using the crc32 
name for something that:
a) is not the "most standard" crc
b) is not even really a crc anyway -i t is more correctly a checksum.

>
> > + * The image is padded out to 64k, because that is what is
> > + * typically used to write the image to the boot medium.
> > + */
>
> "typically used" - by what or whom?  Is there any rechnical reason for
> such padding?  If not, can we not rather omit this?

The files are often concatenated into blocks of 4 repeats and are also often 
written into NAND and aligning them to 64k makes some sense.

>
> > +/*
> > + * Some byte marshalling functions...
> > + * These load or get little endian values to/from the
> > + * buffer.
> > + */
> > +static void load_le16(uint8_t *buf, uint16_t v)
> > +{
> > +	buf[0] = (v >> 0) & 0xff;
> > +	buf[1] = (v >> 8) & 0xff;
> > +}
> > +
> > +static void load_le32(uint8_t *buf, uint32_t v)
> > +{
> > +	buf[0] = (v >>  0) & 0xff;
> > +	buf[1] = (v >>  8) & 0xff;
> > +	buf[2] = (v >> 16) & 0xff;
> > +	buf[3] = (v >> 24) & 0xff;
> > +}
>
> These are misnomers.  You do not load something, but instead you store
> the value of 'v' into the buffer 'buf'.
>
> And why do you invent new functions here instead of using existing
> code (like put_unaligned_le16(), put_unaligned_le32()) ?

I was not aware of the existence of these functions.

Thank you.

>
> > +static uint16_t get_le16(const uint8_t *buf)
> > +{
> > +	uint16_t retval;
> > +
> > +	retval = (((uint16_t) buf[0]) << 0) |
> > +		 (((uint16_t) buf[1]) << 8);
> > +	return retval;
> > +}
> > +
> > +static uint32_t get_le32(const uint8_t *buf)
> > +{
> > +	uint32_t retval;
> > +
> > +	retval = (((uint32_t) buf[0]) <<  0) |
> > +		 (((uint32_t) buf[1]) <<  8) |
> > +		 (((uint32_t) buf[2]) << 16) |
> > +		 (((uint32_t) buf[3]) << 24);
> > +	return retval;
> > +}
>
> Why do you not use existing code (like get_unaligned_le16(),
> get_unaligned_le32()) ?

I was not aware of the existence of these functions.

Thank you.

>
> > +static int align4(int v)
> > +{
> > +	return ((v + 3) / 4) * 4;
> > +}
>
> Don't we have macros to do this?

Possibly, I will look.

Thanks

Charles
Charles Manning March 5, 2014, 4:36 a.m. UTC | #4
Hello Wolfgang

Further to my last response

On Friday 28 February 2014 11:43:47 Charles Manning wrote:
> On Friday 28 February 2014 10:57:21 Wolfgang Denk wrote:
> > > +static uint32_t get_le32(const uint8_t *buf)
> > > +{
> > > +	uint32_t retval;
> > > +
> > > +	retval = (((uint32_t) buf[0]) <<  0) |
> > > +		 (((uint32_t) buf[1]) <<  8) |
> > > +		 (((uint32_t) buf[2]) << 16) |
> > > +		 (((uint32_t) buf[3]) << 24);
> > > +	return retval;
> > > +}
> >
> > Why do you not use existing code (like get_unaligned_le16(),
> > get_unaligned_le32()) ?

From what I see these get_aligned_xxx() functions and friends exist in target 
space, not host land.

From my limited understanding of these matters, it is unwise to call
these functions here.

Are you Ok with that explanation? I will be fixing the other issues you raised 
one way or another.

Best regards

Charles
diff mbox

Patch

diff --git a/common/image.c b/common/image.c
index 9c6bec5..e7dc8cc 100644
--- a/common/image.c
+++ b/common/image.c
@@ -135,6 +135,7 @@  static const table_entry_t uimage_type[] = {
 	{	IH_TYPE_PBLIMAGE,   "pblimage",   "Freescale PBL Boot Image",},
 	{	IH_TYPE_RAMDISK,    "ramdisk",	  "RAMDisk Image",	},
 	{	IH_TYPE_SCRIPT,     "script",	  "Script",		},
+	{	IH_TYPE_SOCFPGAIMAGE,  "socfpgaimage",  "Altera SOCFPGA preloader",},
 	{	IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
 	{	IH_TYPE_UBLIMAGE,   "ublimage",   "Davinci UBL image",},
 	{	IH_TYPE_MXSIMAGE,   "mxsimage",   "Freescale MXS Boot Image",},
diff --git a/include/crc32_alt.h b/include/crc32_alt.h
new file mode 100644
index 0000000..813d55d
--- /dev/null
+++ b/include/crc32_alt.h
@@ -0,0 +1,17 @@ 
+/*
+ * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Note that the CRC is **not** the zlib/Adler crc32 in crc32.c.
+ * It is the CRC-32 used in bzip2, ethernet and elsewhere.
+ */
+
+#ifndef __CRC32_ALT_H__
+#define __CRC32_ALT_H__
+
+#include <stdint.h>
+
+uint32_t crc32_alt(uint32_t crc, const void *_buf, int length);
+
+#endif
diff --git a/include/image.h b/include/image.h
index 6afd57b..bde31d9 100644
--- a/include/image.h
+++ b/include/image.h
@@ -215,6 +215,7 @@  struct lmb;
 #define IH_TYPE_KERNEL_NOLOAD	14	/* OS Kernel Image, can run from any load address */
 #define IH_TYPE_PBLIMAGE	15	/* Freescale PBL Boot Image	*/
 #define IH_TYPE_MXSIMAGE	16	/* Freescale MXSBoot Image	*/
+#define IH_TYPE_SOCFPGAIMAGE	17	/* Altera SOCFPGA Preloader	*/
 
 /*
  * Compression Types
diff --git a/lib/Makefile b/lib/Makefile
index 8c483c9..7ee07a5 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -52,6 +52,7 @@  obj-y += errno.o
 obj-y += display_options.o
 obj-$(CONFIG_BCH) += bch.o
 obj-y += crc32.o
+obj-y += crc32_alt.o
 obj-y += ctype.o
 obj-y += div64.o
 obj-y += hang.o
diff --git a/lib/crc32_alt.c b/lib/crc32_alt.c
new file mode 100644
index 0000000..e0db335
--- /dev/null
+++ b/lib/crc32_alt.c
@@ -0,0 +1,94 @@ 
+/*
+ * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Note that the CRC is **not** the zlib/Adler crc32 in crc32.c.
+ * It is the CRC-32 used in bzip2, ethernet and elsewhere.
+ */
+
+#include <crc32_alt.h>
+#include <stdint.h>
+
+static uint32_t crc_table[256] = {
+	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+	0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+	0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+	0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+	0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+	0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+	0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+	0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+	0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+	0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+	0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+	0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+	0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+	0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+	0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+	0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+	0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+	0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+	0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+	0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+	0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+	0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+	0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+	0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+	0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+	0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+	0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+	0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+	0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+	0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+	0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+	0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+	0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+	0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+	0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+	0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+	0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+	0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+	0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+	0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+	0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+	0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+	0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+	0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+	0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+	0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+	0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+	0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+	0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+	0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+	0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+	0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
+};
+
+uint32_t crc32_alt(uint32_t crc, const void *_buf, int length)
+{
+	const uint8_t *buf = _buf;
+
+	crc ^= ~0;
+
+	while (length--) {
+		crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *buf) & 0xff];
+		buf++;
+	}
+
+	crc ^= ~0;
+
+	return crc;
+}
diff --git a/spl/Makefile b/spl/Makefile
index bf98024..bce9055 100644
--- a/spl/Makefile
+++ b/spl/Makefile
@@ -181,6 +181,11 @@  $(objtree)/SPL : $(obj)/u-boot-spl.bin
 
 ALL-y	+= $(obj)/$(SPL_BIN).bin
 
+$(OBJTREE)/socfpga-signed-preloader.bin: $(obj)/u-boot-spl.bin
+	$(OBJTREE)/tools/mkimage -T socfpgaimage -d $< $@
+
+ALL-$(CONFIG_SOCFPGA) += $(OBJTREE)/socfpga-signed-preloader.bin
+
 ifdef CONFIG_SAMSUNG
 ALL-y	+= $(obj)/$(BOARD)-spl.bin
 endif
diff --git a/tools/Makefile b/tools/Makefile
index dcd49f8..46af0b1 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -71,6 +71,7 @@  RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := rsa-sign.o
 dumpimage-mkimage-objs := aisimage.o \
 			$(FIT_SIG_OBJS-y) \
 			crc32.o \
+			crc32_alt.o \
 			default_image.o \
 			fit_image.o \
 			image-fit.o \
@@ -85,6 +86,7 @@  dumpimage-mkimage-objs := aisimage.o \
 			os_support.o \
 			pblimage.o \
 			sha1.o \
+			socfpgaimage.o \
 			ublimage.o \
 			$(LIBFDT_OBJS) \
 			$(RSA_OBJS-y)
diff --git a/tools/crc32_alt.c b/tools/crc32_alt.c
new file mode 100644
index 0000000..3faa222
--- /dev/null
+++ b/tools/crc32_alt.c
@@ -0,0 +1 @@ 
+#include "../lib/crc32_alt.c"
diff --git a/tools/imagetool.c b/tools/imagetool.c
index 29d2189..1ef20b1 100644
--- a/tools/imagetool.c
+++ b/tools/imagetool.c
@@ -45,6 +45,8 @@  void register_image_tool(imagetool_register_t image_register)
 	init_ubl_image_type();
 	/* Init Davinci AIS support */
 	init_ais_image_type();
+	/* Init Altera SOCFPGA support */
+	init_socfpga_image_type();
 }
 
 /*
diff --git a/tools/imagetool.h b/tools/imagetool.h
index c2c9aea..c4833b1 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -167,6 +167,7 @@  void init_mxs_image_type(void);
 void init_fit_image_type(void);
 void init_ubl_image_type(void);
 void init_omap_image_type(void);
+void init_socfpga_image_type(void);
 
 void pbl_load_uboot(int fd, struct image_tool_params *mparams);
 
diff --git a/tools/socfpgaimage.c b/tools/socfpgaimage.c
new file mode 100644
index 0000000..842c1b0
--- /dev/null
+++ b/tools/socfpgaimage.c
@@ -0,0 +1,278 @@ 
+/*
+ * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Reference doc http://www.altera.com.cn/literature/hb/cyclone-v/cv_5400A.pdf
+ * Note this doc is not entirely accurate. Of particular interest to us is the
+ * "header" length field being in U32s and not bytes.
+ *
+ * "Header" is a structure of the following format.
+ * this is positioned at 0x40.
+ *
+ * Endian is LSB.
+ *
+ * Offset   Length   Usage
+ * -----------------------
+ *   0x40        4   Validation word 0x31305341
+ *   0x44        1   Version (whatever, zero is fine)
+ *   0x45        1   Flags   (unused, zero is fine)
+ *   0x46        2   Length  (in units of u32, including the end checksum).
+ *   0x48        2   Zero
+ *   0x4A        2   Checksum over the heder. NB Not CRC32
+ *
+ * At the end of the code we have a 32-bit CRC checksum over whole binary
+ * excluding the CRC.
+ *
+ * Note that the CRC used here is **not** the zlib/Adler crc32. It is the
+ * CRC-32 used in bzip2, ethernet and elsewhere.
+ *
+ * The image is padded out to 64k, because that is what is
+ * typically used to write the image to the boot medium.
+ */
+
+#include <crc32_alt.h>
+#include "imagetool.h"
+#include <image.h>
+
+#define HEADER_OFFSET	0x40
+#define HEADER_SIZE	0xC
+#define VALIDATION_WORD	0x31305341
+#define PADDED_SIZE	0x10000
+
+/* To allow for adding CRC, the max input size is a bit smaller. */
+#define MAX_INPUT_SIZE	(PADDED_SIZE - sizeof(uint32_t))
+
+static uint8_t buffer[PADDED_SIZE];
+
+/*
+ * The header checksum is just a very simple checksum over
+ * the header area.
+ * There is still a crc32 over the whole lot.
+ */
+static uint16_t hdr_checksum(const uint8_t *buf, int len)
+{
+	uint16_t ret = 0;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		ret += (((uint16_t) *buf) & 0xff);
+		buf++;
+	}
+	return ret;
+}
+
+/*
+ * Some byte marshalling functions...
+ * These load or get little endian values to/from the
+ * buffer.
+ */
+static void load_le16(uint8_t *buf, uint16_t v)
+{
+	buf[0] = (v >> 0) & 0xff;
+	buf[1] = (v >> 8) & 0xff;
+}
+
+static void load_le32(uint8_t *buf, uint32_t v)
+{
+	buf[0] = (v >>  0) & 0xff;
+	buf[1] = (v >>  8) & 0xff;
+	buf[2] = (v >> 16) & 0xff;
+	buf[3] = (v >> 24) & 0xff;
+}
+
+static uint16_t get_le16(const uint8_t *buf)
+{
+	uint16_t retval;
+
+	retval = (((uint16_t) buf[0]) << 0) |
+		 (((uint16_t) buf[1]) << 8);
+	return retval;
+}
+
+static uint32_t get_le32(const uint8_t *buf)
+{
+	uint32_t retval;
+
+	retval = (((uint32_t) buf[0]) <<  0) |
+		 (((uint32_t) buf[1]) <<  8) |
+		 (((uint32_t) buf[2]) << 16) |
+		 (((uint32_t) buf[3]) << 24);
+	return retval;
+}
+
+static int align4(int v)
+{
+	return ((v + 3) / 4) * 4;
+}
+
+static void build_header(uint8_t *buf,
+			  uint8_t version,
+			  uint8_t flags,
+			  uint16_t length_bytes)
+{
+	memset(buf, 0, HEADER_SIZE);
+
+	load_le32(buf + 0, VALIDATION_WORD);
+	buf[4] = version;
+	buf[5] = flags;
+	load_le16(buf + 6, length_bytes/4);
+	load_le16(buf + 10, hdr_checksum(buf, 10));
+}
+
+/*
+ * Perform a rudimentary verification of header and return
+ * size of image.
+ */
+static int verify_header(const uint8_t *buf)
+{
+	if (get_le32(buf) != VALIDATION_WORD)
+		return -1;
+	if (get_le16(buf + 10) != hdr_checksum(buf, 10))
+		return -1;
+
+	return get_le16(buf + 6) * 4;
+}
+
+/* Sign the buffer and return the signed buffer size */
+static int sign_buffer(uint8_t *buf,
+			uint8_t version, uint8_t flags,
+			int len, int pad_64k)
+{
+	uint32_t crcval;
+
+	/* Align the length up */
+	len = align4(len);
+
+	/* Build header, adding 4 bytes to length to hold the CRC32. */
+	build_header(buf + HEADER_OFFSET,  version, flags, len + 4);
+
+	crcval = crc32_alt(0, buf, len);
+
+	load_le32(buf + len, crcval);
+
+	if (!pad_64k)
+		return len + 4;
+
+	return PADDED_SIZE;
+}
+
+/* Verify that the buffer looks sane */
+static int verify_buffer(const uint8_t *buf)
+{
+	int len; /* Including 32bit CRC */
+	uint32_t crccalc;
+
+	len = verify_header(buf + HEADER_OFFSET);
+	if (len < 0)
+		return -1;
+	if (len < HEADER_OFFSET || len > PADDED_SIZE)
+		return -1;
+
+	/* Adjust length, removing CRC */
+	len -= 4;
+
+	crccalc = crc32_alt(0, buf, len);
+
+	if (get_le32(buf + len) != crccalc)
+		return -1;
+
+	return 0;
+}
+
+/* mkimage glue functions */
+static int socfpgaimage_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	if (image_size != PADDED_SIZE)
+		return -1;
+
+	return verify_buffer(ptr);
+}
+
+static void socfpgaimage_print_header(const void *ptr)
+{
+	if (verify_buffer(ptr) == 0)
+		printf("Looks like a sane SOCFPGA preloader\n");
+	else
+		printf("Not a sane SOCFPGA preloader\n");
+}
+
+static int socfpgaimage_check_params(struct image_tool_params *params)
+{
+	/* Not sure if we should be accepting fflags */
+	return	(params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag));
+}
+
+static int socfpgaimage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_SOCFPGAIMAGE)
+		return EXIT_SUCCESS;
+	return EXIT_FAILURE;
+}
+
+/*
+ * To work in with the mkimage framework, we do some ugly stuff...
+ *
+ * First, socfpgaimage_vrec_header() is called.
+ * We prepend a fake header big enough to make the file PADDED_SIZE.
+ * This gives us enough space to do what we want later.
+ *
+ * Next, socfpgaimage_set_header() is called.
+ * We fix up the buffer by moving the image to the start of the buffer.
+ * We now have some room to do what we need (add CRC and padding).
+ */
+
+static int data_size;
+#define FAKE_HEADER_SIZE (PADDED_SIZE - data_size)
+
+static int socfpgaimage_vrec_header(struct image_tool_params *params,
+				struct image_type_params *tparams)
+{
+	struct stat sbuf;
+
+	if (params->datafile &&
+	    stat(params->datafile, &sbuf) == 0 &&
+	    sbuf.st_size <= MAX_INPUT_SIZE) {
+		data_size = sbuf.st_size;
+		tparams->header_size = FAKE_HEADER_SIZE;
+	}
+	return 0;
+}
+
+static void socfpgaimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	uint8_t *buf = (uint8_t *)ptr;
+
+	/*
+	 * This function is called after vrec_header() has been called.
+	 * At this stage we have the FAKE_HEADER_SIZE dummy bytes followed by
+	 * data_size image bytes. Total = PADDED_SIZE.
+	 * We need to fix the buffer by moving the image bytes back to
+	 * the beginning of the buffer, then actually do the signing stuff...
+	 */
+	memmove(buf, buf + FAKE_HEADER_SIZE, data_size);
+	memset(buf + data_size, 0, FAKE_HEADER_SIZE);
+
+	sign_buffer(buf, 0, 0, data_size, 0);
+}
+
+static struct image_type_params socfpgaimage_params = {
+	.name		= "Altera SOCFPGA preloader support",
+	.vrec_header	= socfpgaimage_vrec_header,
+	.header_size	= 0, /* This will be modified by vrec_header() */
+	.hdr		= (void *)buffer,
+	.check_image_type = socfpgaimage_check_image_types,
+	.verify_header	= socfpgaimage_verify_header,
+	.print_header	= socfpgaimage_print_header,
+	.set_header	= socfpgaimage_set_header,
+	.check_params	= socfpgaimage_check_params,
+};
+
+void init_socfpga_image_type(void)
+{
+	register_image_type(&socfpgaimage_params);
+}