Hi Charles, On Sun, 2014-09-21 at 14:58 +0200, ma...@denx.de wrote: > From: Charles Manning <cdhmann...@gmail.com> > > 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 <cdhmann...@gmail.com> > Signed-off-by: Marek Vasut <ma...@denx.de> > Cc: Chin Liang See <cl...@altera.com> > Cc: Dinh Nguyen <dingu...@altera.com> > Cc: Albert Aribaud <albert.u.b...@aribaud.net> > Cc: Tom Rini <tr...@ti.com> > Cc: Wolfgang Denk <w...@denx.de> > Cc: Pavel Machek <pa...@denx.de> > --- > common/image.c | 1 + > include/image.h | 1 + > tools/Makefile | 1 + > tools/imagetool.c | 2 + > tools/imagetool.h | 1 + > tools/socfpgaimage.c | 255 > +++++++++++++++++++++++++++++++++++++++++++++++++++ > 6 files changed, 261 insertions(+) > create mode 100644 tools/socfpgaimage.c > > diff --git a/common/image.c b/common/image.c > index 38b56e3..085771c 100644 > --- a/common/image.c > +++ b/common/image.c > @@ -138,6 +138,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/image.h b/include/image.h > index 3401056..4347532 100644 > --- a/include/image.h > +++ b/include/image.h > @@ -232,6 +232,7 @@ struct lmb; > #define IH_TYPE_MXSIMAGE 16 /* Freescale MXSBoot Image */ > #define IH_TYPE_GPIMAGE 17 /* TI Keystone GPHeader Image > */ > #define IH_TYPE_ATMELIMAGE 18 /* ATMEL ROM bootable Image */ > +#define IH_TYPE_SOCFPGAIMAGE 19 /* Altera SOCFPGA Preloader */ > > /* > * Compression Types > diff --git a/tools/Makefile b/tools/Makefile > index 90e966d..2b05b20 100644 > --- a/tools/Makefile > +++ b/tools/Makefile > @@ -87,6 +87,7 @@ dumpimage-mkimage-objs := aisimage.o \ > os_support.o \ > pblimage.o \ > pbl_crc32.o \ > + socfpgaimage.o \ > lib/sha1.o \ > lib/sha256.o \ > ublimage.o \ > diff --git a/tools/imagetool.c b/tools/imagetool.c > index 32d6278..98717bd 100644 > --- a/tools/imagetool.c > +++ b/tools/imagetool.c > @@ -47,6 +47,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(); > /* Init TI Keystone boot image generation/list support */ > init_gpimage_type(); > } > diff --git a/tools/imagetool.h b/tools/imagetool.h > index c8af0e8..8bce059 100644 > --- a/tools/imagetool.h > +++ b/tools/imagetool.h > @@ -168,6 +168,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 init_gpimage_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..32fa09f > --- /dev/null > +++ b/tools/socfpgaimage.c > @@ -0,0 +1,255 @@ > +/* > + * Copyright (C) 2014 Charles Manning <cdhmann...@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 header. 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 "pbl_crc32.h"
Seems I cannot find this file > +#include "imagetool.h" > +#include <image.h> > + > +#define HEADER_OFFSET 0x40 > +#define HEADER_SIZE 0xC Unused > +#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]; > + > +static struct { > + uint32_t validation; > + uint8_t version; > + uint8_t flags; > + uint16_t length_u32; > + uint16_t zero; > + uint16_t checksum; > +} header; > + > +/* > + * 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; > +} > + > + > +static void build_header(uint8_t *buf, > + uint8_t version, > + uint8_t flags, > + uint16_t length_bytes) > +{ > + header.validation = htole32(VALIDATION_WORD); > + header.version = version; > + header.flags = flags; > + header.length_u32 = htole16(length_bytes/4); > + header.zero = 0; > + header.checksum = htole16(hdr_checksum((const uint8_t *)&header, 10)); Seems 10 is a magic number here. Suggest to use sizeof(header) - sizeof(header.checksum) > + > + memcpy(buf, &header, sizeof(header)); > +} > + > +/* > + * Perform a rudimentary verification of header and return > + * size of image. > + */ > +static int verify_header(const uint8_t *buf) > +{ > + memcpy(&header, buf, sizeof(header)); > + > + if (le32toh(header.validation) != VALIDATION_WORD) > + return -1; > + if (le16toh(header.checksum) != > + hdr_checksum((const uint8_t *)&header, 10)) Ditto > + return -1; > + > + return le16toh(header.length_u32) * 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 calc_crc; > + > + /* Align the length up */ > + len = (len + 3) & (~3); > + > + /* Build header, adding 4 bytes to length to hold the CRC32. */ > + build_header(buf + HEADER_OFFSET, version, flags, len + 4); > + > + /* Calculate and apply the CRC */ > + calc_crc = ~pbl_crc32(0, (char *)buf, len); > + For this, we can reuse the lib/bzlib_private.h /* Calculate and apply the CRC */ BZ_INITIALISE_CRC(calc_crc); while (len--) { BZ_UPDATE_CRC(calc_crc, *buf); buf++; } calc_crc ^= ~0; > + *((uint32_t *)(buf + len)) = htole32(calc_crc); > + > + 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 calc_crc; > + uint32_t buf_crc; > + > + len = verify_header(buf + HEADER_OFFSET); > + if (len < 0) > + return -1; > + if (len < HEADER_OFFSET || len > PADDED_SIZE) > + return -1; Suggest to have some printout to indicate failure type > + > + /* > + * Adjust length to the base of the CRC. > + * Check the CRC. > + */ > + len -= 4; > + > + calc_crc = ~pbl_crc32(0, (const char *)buf, len); > + Ditto > + buf_crc = le32toh(*((uint32_t *)(buf + len))); > + > + if (buf_crc != calc_crc) > + return -1; > + Suggest to have some printout to indicate failure type > + 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); > +} _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot