diff mbox

[1/3] mkpimage: rewrite to support header version 1

Message ID 20170126112831.28107-1-lionel@svkt.org
State Superseded
Headers show

Commit Message

Lionel Flandrin Jan. 26, 2017, 11:28 a.m. UTC
mkpimage is a proprietary tool part of Altera's Embedded Development
Suite which is used to generate the image files supported by their
BootROMs.

Newer versions of their SoCs (such as the Arria 10) use header version
1 which was not supported by the previous version of this tool.

This new version supports header version 1, improves error handling
and tweaks the output to bring it closer to Altera's own tool. In
particular the padding calculations have been changed. In all the
configurations tested this program and Altera's mkpimage produce
exactly the same files (while the previous version didn't).

Signed-off-by: Lionel Flandrin <lionel@svkt.org>
---
 package/mkpimage/mkpimage.c  | 768 ++++++++++++++++++++++++++++---------------
 package/mkpimage/mkpimage.mk |   3 -
 2 files changed, 512 insertions(+), 259 deletions(-)

Comments

Thomas Petazzoni Jan. 27, 2017, 8:17 a.m. UTC | #1
Hello,

On Thu, 26 Jan 2017 12:28:31 +0100, Lionel Flandrin wrote:
> mkpimage is a proprietary tool part of Altera's Embedded Development
> Suite which is used to generate the image files supported by their
> BootROMs.
> 
> Newer versions of their SoCs (such as the Arria 10) use header version
> 1 which was not supported by the previous version of this tool.
> 
> This new version supports header version 1, improves error handling
> and tweaks the output to bring it closer to Altera's own tool. In
> particular the padding calculations have been changed. In all the
> configurations tested this program and Altera's mkpimage produce
> exactly the same files (while the previous version didn't).
> 
> Signed-off-by: Lionel Flandrin <lionel@svkt.org>

Why not import the new version of this program available in Barebox,
which does support V1 headers nowadays?

Otherwise, where does your version comes from?

Best regards,

Thomas
Lionel Flandrin Jan. 27, 2017, 9:52 a.m. UTC | #2
On Fri, Jan 27, 2017 at 09:17:03PM +1300, Thomas Petazzoni wrote:
> Hello,
> 
> On Thu, 26 Jan 2017 12:28:31 +0100, Lionel Flandrin wrote:
> > mkpimage is a proprietary tool part of Altera's Embedded Development
> > Suite which is used to generate the image files supported by their
> > BootROMs.
> > 
> > Newer versions of their SoCs (such as the Arria 10) use header version
> > 1 which was not supported by the previous version of this tool.
> > 
> > This new version supports header version 1, improves error handling
> > and tweaks the output to bring it closer to Altera's own tool. In
> > particular the padding calculations have been changed. In all the
> > configurations tested this program and Altera's mkpimage produce
> > exactly the same files (while the previous version didn't).
> > 
> > Signed-off-by: Lionel Flandrin <lionel@svkt.org>
> 
> Why not import the new version of this program available in Barebox,
> which does support V1 headers nowadays?

Because I only noticed that too late... The comment about the barebox
version was in the mk and when I saw it I was almost already done with
my version. My search engine skills failed me once again.

Furthermore this version supports some additional parameters like
setting the alignment and the entry point offset in the header (which
are also supported in Altera's tool). It's also a little more user
friendly (better error reporting etc...). Not a huge deal but still.

More importantly it's closer to Altera's original mkpimage, both in
command line usage and in the resulting image format making it a
better canditate for drop-in replacement. So I decided that it was
worth finishing it.

> Otherwise, where does your version comes from?

It's original work based on the current version of mkpimage.c in the
buildroot repo and my reverse-engineering of version 16.1 of Altera's
closed source java-based mkpimage.

I realize it might make it a bit "off-topic" for inclusion in source
form in buildroot's repo but it's not exactly complicated code either,
it's a simple 14byte header and a 32bit CRC.

I've compared the output of this code with altera's and barebox's
version and they all generate the same binaries with the caveat that
barebox's version uses different alignment constraints and doesn't
handle certain options.

But really it's up to you, for my current use case I can live with
barebox's updated version if you prefer. Alternatively I could try
getting this version of the code in barebox first, even though I don't
use the project myself.

> Best regards,
> 
> Thomas

Thank you for taking the time to review this,
Thomas Petazzoni Jan. 28, 2017, 8:42 a.m. UTC | #3
Hello,

On Fri, 27 Jan 2017 10:52:51 +0100, Lionel Flandrin wrote:

> But really it's up to you, for my current use case I can live with
> barebox's updated version if you prefer. Alternatively I could try
> getting this version of the code in barebox first, even though I don't
> use the project myself.

If the Barebox version works for you, then I'd prefer if we could stick
to it.

Thomas
Lionel Flandrin Jan. 28, 2017, 11:27 a.m. UTC | #4
On Sat, Jan 28, 2017 at 09:42:28PM +1300, Thomas Petazzoni wrote:
> Hello,
> 
> On Fri, 27 Jan 2017 10:52:51 +0100, Lionel Flandrin wrote:
> 
> > But really it's up to you, for my current use case I can live with
> > barebox's updated version if you prefer. Alternatively I could try
> > getting this version of the code in barebox first, even though I don't
> > use the project myself.
> 
> If the Barebox version works for you, then I'd prefer if we could stick
> to it.

Fair enough, I'll submit an other patch.

> 
> Thomas
> -- 
> Thomas Petazzoni, CTO, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
diff mbox

Patch

diff --git a/package/mkpimage/mkpimage.c b/package/mkpimage/mkpimage.c
index 1a7a66d98..7859ae398 100644
--- a/package/mkpimage/mkpimage.c
+++ b/package/mkpimage/mkpimage.c
@@ -1,287 +1,543 @@ 
+/* Replacement for altera's proprietary mkpimage (part of their EDS)
+ *
+ * Create an Altera BootROM-compatible image of the Second Stage Boot
+ * Loader (SSBL).
+ *
+ * This program should generate the same output as Altera's mkpimage
+ * version 16.1 (build 196). If it doesn't it's a bug.
+ *
+ * The original version of this program was part of barebox.
+ *
+ * Distributed under the GNU GPL v2.
+ */
+
 #include <stdio.h>
-#include <unistd.h>
 #include <getopt.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include <errno.h>
-#include <sys/types.h>
 #include <sys/stat.h>
-#include <fcntl.h>
-#include <endian.h>
 
-#define VALIDATION_WORD 0x31305341
+#define MKPIMAGE_VERSION "1.0"
 
-#define MAX_IMAGE_SIZE (60 * 1024 - 4)
+#define VALIDATION_WORD 0x31305341
 
-static int add_barebox_header;
+struct socfpga_header_v0 {
+  uint8_t validation_word[4];
+  uint8_t version;
+  uint8_t flags;
+  uint8_t program_length[2];
+  uint8_t spare[2];
+  uint8_t checksum[2];
+};
 
-struct socfpga_header {
-	uint8_t validation_word[4];
-	uint8_t version;
-	uint8_t flags;
-	uint8_t program_length[2];
-	uint8_t spare[2];
-	uint8_t checksum[2];
+struct socfpga_header_v1 {
+  uint8_t validation_word[4];
+  uint8_t version;
+  uint8_t flags;
+  uint8_t header_length[2];
+  uint8_t program_length[4];
+  uint8_t program_offset[4];
+  uint8_t spare[2];
+  uint8_t checksum[2];
 };
 
 static uint32_t bb_header[] = {
-	0xea00007e,	/* b 0x200  */
-	0xeafffffe,	/* 1: b 1b  */
-	0xeafffffe,	/* 1: b 1b  */
-	0xeafffffe,	/* 1: b 1b  */
-	0xeafffffe,	/* 1: b 1b  */
-	0xeafffffe,	/* 1: b 1b  */
-	0xeafffffe,	/* 1: b 1b  */
-	0xeafffffe,	/* 1: b 1b  */
-	0x65726162,	/* 'bare'   */
-	0x00786f62,	/* 'box\0'  */
-	0x00000000,	/* padding  */
-	0x00000000,	/* padding  */
-	0x00000000,	/* padding  */
-	0x00000000,	/* padding  */
-	0x00000000,	/* padding  */
-	0x00000000,	/* padding  */
-	0x00000000,	/* socfpga header */
-	0x00000000,	/* socfpga header */
-	0x00000000,	/* socfpga header */
-	0xea00006b,	/* entry. b 0x200  */
+  0xea00007e,	/* b 0x200  */
+  0xeafffffe,	/* 1: b 1b  */
+  0xeafffffe,	/* 1: b 1b  */
+  0xeafffffe,	/* 1: b 1b  */
+  0xeafffffe,	/* 1: b 1b  */
+  0xeafffffe,	/* 1: b 1b  */
+  0xeafffffe,	/* 1: b 1b  */
+  0xeafffffe,	/* 1: b 1b  */
+  0x65726162,	/* 'bare'   */
+  0x00786f62,	/* 'box\0'  */
+  0x00000000,	/* padding  */
+  0x00000000,	/* padding  */
+  0x00000000,	/* padding  */
+  0x00000000,	/* padding  */
+  0x00000000,	/* padding  */
+  0x00000000,	/* padding  */
+  0x00000000,	/* socfpga header */
+  0x00000000,	/* socfpga header */
+  0x00000000,	/* socfpga header */
+  0xea00006b,	/* entry. b 0x200  */
 };
 
-static int read_full(int fd, void *buf, size_t size)
-{
-	size_t insize = size;
-	int now;
-	int total = 0;
-
-	while (size) {
-		now = read(fd, buf, size);
-		if (now == 0)
-			return total;
-		if (now < 0)
-			return now;
-		total += now;
-		size -= now;
-		buf += now;
-	}
-
-	return insize;
+static int add_file(int outfd,
+                    const char *path,
+                    unsigned header_version,
+                    size_t alignment,
+                    int barebox,
+                    unsigned long entry_offset);
+static void add_socfpga_header_v0(uint8_t *buf, size_t size);
+static void add_socfpga_header_v1(uint8_t *buf,
+                                  size_t size,
+                                  unsigned long entry_offset);
+static uint32_t crc32(uint8_t *buf, size_t length);
+static int write_all(int fd, uint8_t *buf, size_t size);
+
+static void usage(const char *bin) {
+  fprintf(stderr,
+"Buildroot mkpimage v" MKPIMAGE_VERSION "\n"
+"\n"
+"Usage:\n"
+" Create quad image:\n"
+"     %1$s [options] -H <num> -o <outfile> <infile> "
+"<infile> <infile> <infile>\n"
+" Create single image:\n"
+"     %1$s [options] -H <num> -o <outfile> <infile>\n"
+"\n"
+"Options:\n"
+"\n"
+"-h (--help)                  Display this help message and exit\n"
+"-H (--header-version) <num>  Header version to be created\n"
+"                             - Arria/Cyclone V = 0\n"
+"                             - Arria 10        = 1\n"
+"                             [default: 0]\n"
+"-a (--alignment) <num>       Address alignment in kilobytes, valid value\n"
+"                             starts from 64, 128, 256 etc, override if the\n"
+"                             NAND flash has a larger block size\n"
+"                             [default: 64 for header v0, 256 for v1]\n"
+"-o (--output) <outfile>      Output file. Relative and absolute path\n"
+"                             supported\n"
+"-b (--barebox)               Add barebox header\n"
+"-O (--offset) <num>          Program entry offset relative to start of\n"
+"                             header (0x40). Used for header version 1 only.\n"
+"                             [default: 20, min: 20]\n", bin);
 }
 
-static int write_full(int fd, void *buf, size_t size)
-{
-	size_t insize = size;
-	int now;
-
-	while (size) {
-		now = write(fd, buf, size);
-		if (now <= 0)
-			return now;
-		size -= now;
-		buf += now;
-	}
-
-	return insize;
+
+int main(int argc, char **argv) {
+  static struct option opts[] = {
+    {"help",           no_argument,       NULL, 'h' },
+    {"header-version", required_argument, NULL, 'H' },
+    {"alignement",     required_argument, NULL, 'a' },
+    {"output",         required_argument, NULL, 'o' },
+    {"barebox",        no_argument,       NULL, 'b' },
+    {"offset",         required_argument, NULL, 'O' },
+    {NULL,             0,                 NULL,  0  },
+  };
+
+  int opt;
+  int barebox = 0;
+  unsigned header_version = 0;
+  size_t alignment = 0;
+  int alignment_set = 0;
+  const char *outfile = NULL;
+  unsigned nfiles;
+  unsigned long entry_offset = 20;
+  int entry_offset_set = 0;
+  int outfd;
+  unsigned i;
+
+  while ((opt = getopt_long(argc, argv, "hH:a:dfo:bO:", opts, NULL)) != -1) {
+    switch (opt) {
+    case 'H':
+      header_version = optarg[0] - '0';
+      if (strlen(optarg) != 1 ||
+          (header_version != 0 && header_version != 1)) {
+        fprintf(stderr, "Invalid header version: %s\n\n", optarg);
+        usage(argv[0]);
+        return EXIT_FAILURE;
+      }
+      break;
+    case 'a':
+      {
+        char *endptr;
+
+        alignment = strtoul(optarg, &endptr, 0);
+
+        if (*endptr != '\0' || alignment == 0) {
+          fprintf(stderr, "Invalid alignment: %s\n\n", optarg);
+          usage(argv[0]);
+          return EXIT_FAILURE;
+        }
+
+        alignment *= 1024;
+        alignment_set = 1;
+      }
+      break;
+    case 'b':
+      barebox = 1;
+      break;
+    case 'o':
+      outfile = optarg;
+      break;
+    case 'O':
+      {
+        char *endptr;
+
+        entry_offset = strtoul(optarg, &endptr, 0);
+
+        if (*endptr != '\0' || entry_offset < 20) {
+          fprintf(stderr, "Invalid entry offset: %s\n\n", optarg);
+          usage(argv[0]);
+          return EXIT_FAILURE;
+        }
+
+        entry_offset_set = 1;
+      }
+      break;
+    case 'h':
+    default:
+      usage(argv[0]);
+      return EXIT_FAILURE;
+    }
+  }
+
+  if (outfile == NULL) {
+    fprintf(stderr, "Missing output file name\n\n");
+    usage(argv[0]);
+    return EXIT_FAILURE;
+  }
+
+  if (!alignment_set) {
+    if (header_version == 0) {
+      /* Default to 64K */
+      alignment = 64 * 1024;
+    } else {
+      /* V1 defaults to 256K */
+      alignment = 256 * 1024;
+    }
+  }
+
+  if (entry_offset_set && header_version == 0) {
+    fprintf(stderr,
+            "Error: entry offset is not available in header version 0\n\n");
+    usage(argv[0]);
+    return EXIT_FAILURE;
+  }
+
+  nfiles = argc - optind;
+
+  if (nfiles != 1 && nfiles != 4) {
+    fprintf(stderr,
+            "Wrong number of input files: expected 1 or 4, got %u\n\n",
+            nfiles);
+    usage(argv[0]);
+    return EXIT_FAILURE;
+  }
+
+  outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+  if (outfd == -1) {
+    fprintf(stderr,
+            "Couldn't open '%s' for writing: %s\n",
+            outfile, strerror(errno));
+    return EXIT_FAILURE;
+  }
+
+  /* Barebox's version of this program doesn't pad the output up to
+     * alignment, however Altera's mkpimage does. */
+  if (ftruncate(outfd, alignment * nfiles) == -1) {
+    fprintf(stderr,
+            "Couldn't truncate '%s' to %lu: %s\n",
+            outfile, alignment * nfiles, strerror(errno));
+    goto unlink;
+  }
+
+  for (i = 0; i < nfiles; i++) {
+    if (lseek(outfd, i * alignment, SEEK_SET) == -1) {
+      fprintf(stderr,
+              "Couldn't seek '%s' to %lu: %s\n",
+              outfile, i * alignment, strerror(errno));
+      goto unlink;
+    }
+
+    if (add_file(outfd,
+                 argv[optind + i],
+                 header_version,
+                 alignment,
+                 barebox,
+                 entry_offset) == -1) {
+      goto unlink;
+    }
+  }
+
+  close(outfd);
+
+  return EXIT_SUCCESS;
+
+ unlink:
+  /* Something went wrong, delete the output*/
+  close(outfd);
+  unlink(outfile);
+  return EXIT_FAILURE;
 }
 
-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
-};
+static int add_file(int outfd,
+                    const char *path,
+                    unsigned header_version,
+                    size_t alignment,
+                    int barebox,
+                    unsigned long entry_offset) {
+  int fd = -1;
+  struct stat st;
+  int ret = -1;
+  size_t file_size;
+  size_t out_size;
+  uint8_t *buffer = NULL;
+  uint8_t *rbuffer = NULL;
+  size_t nread = 0;
+
+  fd = open(path, O_RDONLY);
+
+  if (fd == -1) {
+     fprintf(stderr, "Couldn't open '%s' for reading: %s\n",
+             path, strerror(errno));
+     goto exit;
+  }
+
+  if (fstat(fd, &st) == -1) {
+    fprintf(stderr,
+            "Couldn't stat '%s': %s\n",
+            path, strerror(errno));
+    goto exit;
+  }
+
+  file_size = st.st_size;
+
+  /* Add room for 32bit CRC */
+  out_size = file_size + sizeof(uint32_t);
+
+  if (barebox) {
+    out_size += 512;
+  }
+
+  /* Barebox's version of this program pads the binary to a multiple
+   * of 4bytes, however altera's mkpimage pads to 32bytes. I'm not
+   * sure if it makes a difference in practice but I prefer to be as
+   * close as possible to the reference.
+   */
+  out_size = (out_size + 31UL) & (~31UL);
+
+  if (out_size > alignment) {
+    fprintf(stderr,
+            "Error: File '%s' is too big to fit the alignment of %luKB\n",
+            path,
+            alignment / 1024);
+      goto exit;
+  }
+
+  buffer = malloc(out_size);
+  if (buffer == NULL) {
+    fprintf(stderr, "malloc(%lu) failed\n", out_size);
+    goto exit;
+  }
+
+  memset(buffer, 0, out_size);
+
+  if (barebox) {
+    memcpy(buffer, bb_header, sizeof(bb_header));
+    rbuffer = buffer + 512;
+  } else {
+    rbuffer = buffer;
+  }
+
+  while (nread < file_size) {
+    ssize_t n = read(fd, rbuffer + nread, file_size - nread);
+
+    if (n < 0) {
+      fprintf(stderr, "Error while reading '%s': %s\n",
+              path, strerror(errno));
+      goto exit;
+    }
+
+    if (n == 0) {
+      fprintf(stderr, "Error while reading '%s': %s\n",
+              path, "Short read");
+      goto exit;
+    }
+
+    nread += (size_t)n;
+  }
+
+  if (header_version == 0) {
+    add_socfpga_header_v0(buffer, out_size);
+  } else {
+    add_socfpga_header_v1(buffer, out_size, entry_offset);
+  }
+
+  if (write_all(outfd, buffer, out_size) == -1) {
+    goto exit;
+  }
+
+  ret = 0;
+ exit:
+  if (buffer != NULL) {
+    free(buffer);
+  }
+
+  if (fd >= 0) {
+    close(fd);
+  }
+
+  return ret;
+}
 
-uint32_t crc32(uint32_t crc, void *_buf, int length)
+static void add_socfpga_header_v0(uint8_t *buf, size_t size)
 {
-	uint8_t *buf = _buf;
-
-	while (length--)
-		crc = crc << 8 ^ crc_table[(crc >> 24 ^ *(buf++)) & 0xff];
-
-	return crc;
+  struct socfpga_header_v0 *header = (void*)(buf + 0x40);
+  uint32_t crc;
+  uint32_t crc_idx;
+  unsigned checksum;
+  size_t length = size >> 2;
+  size_t i;
+
+  header->validation_word[0] = VALIDATION_WORD & 0xff;
+  header->validation_word[1] = (VALIDATION_WORD >> 8) & 0xff;
+  header->validation_word[2] = (VALIDATION_WORD >> 16) & 0xff;
+  header->validation_word[3] = (VALIDATION_WORD >> 24) & 0xff;
+  header->version = 0;
+  header->flags = 0;
+  header->program_length[0] = length & 0xff;
+  header->program_length[1] = (length >> 8) & 0xff;
+  header->spare[0] = 0;
+  header->spare[1] = 0;
+
+  /* Header checksum */
+  checksum = 0;
+  for (i = 0; i < sizeof(*header) - 2; i++)
+    checksum += buf[i + 0x40];
+
+  header->checksum[0] = checksum & 0xff;
+  header->checksum[1] = (checksum >> 8) & 0xff;
+
+  crc = crc32(buf, size - sizeof(uint32_t));
+
+  crc_idx = size - sizeof(uint32_t);
+
+  buf[crc_idx++] = crc & 0xff;
+  buf[crc_idx++] = (crc >> 8) & 0xff;
+  buf[crc_idx++] = (crc >> 16) & 0xff;
+  buf[crc_idx++] = (crc >> 24) & 0xff;
 }
 
-static int add_socfpga_header(void *buf, int size)
-{
-	struct socfpga_header *header = buf + 0x40;
-	uint8_t *buf_header = buf + 0x40;
-	uint32_t *crc;
-	unsigned checksum;
-	int length = size >> 2;
-	int i;
-
-	if (size & 0x3) {
-		fprintf(stderr, "%s: size must be multiple of 4\n", __func__);
-		return -EINVAL;
-	}
-
-	header->validation_word[0] = VALIDATION_WORD & 0xff;
-	header->validation_word[1] = (VALIDATION_WORD >> 8) & 0xff;
-	header->validation_word[2] = (VALIDATION_WORD >> 16) & 0xff;
-	header->validation_word[3] = (VALIDATION_WORD >> 24) & 0xff;
-	header->version = 0;
-	header->flags = 0;
-	header->program_length[0] = length & 0xff;
-	header->program_length[1] = (length >> 8) & 0xff;
-	header->spare[0] = 0;
-	header->spare[1] = 0;
-
-	checksum = 0;
-	for (i = 0; i < sizeof(*header) - 2; i++)
-		checksum += buf_header[i];
-
-	header->checksum[0] = checksum & 0xff;;
-	header->checksum[1] = (checksum >> 8) & 0xff;;
-
-	crc = buf + size - sizeof(uint32_t);
-
-	*crc = crc32(0xffffffff, buf, size - sizeof(uint32_t));
-	*crc ^= 0xffffffff;
-
-	return 0;
+static void add_socfpga_header_v1(uint8_t *buf,
+                                  size_t size,
+                                  unsigned long entry_offset) {
+  struct socfpga_header_v1 *header = (void*)(buf + 0x40);
+  uint32_t crc;
+  uint32_t crc_idx;
+  unsigned checksum;
+  int i;
+
+  header->validation_word[0] = VALIDATION_WORD & 0xff;
+  header->validation_word[1] = (VALIDATION_WORD >> 8) & 0xff;
+  header->validation_word[2] = (VALIDATION_WORD >> 16) & 0xff;
+  header->validation_word[3] = (VALIDATION_WORD >> 24) & 0xff;
+  header->version = 1;
+  header->flags = 0;
+  header->header_length[0] = sizeof(*header) & 0xff;
+  header->header_length[1] = (sizeof(*header) >> 8) & 0xff;
+  header->program_length[0] = size & 0xff;
+  header->program_length[1] = (size >> 8) & 0xff;
+  header->program_length[2] = (size >> 16) & 0xff;
+  header->program_length[3] = (size >> 24) & 0xff;
+  header->program_offset[0] = entry_offset & 0xff;
+  header->program_offset[1] = (entry_offset >> 8) & 0xff;
+  header->program_offset[2] = (entry_offset >> 16) & 0xff;
+  header->program_offset[3] = (entry_offset >> 24) & 0xff;
+  header->spare[0] = 0;
+  header->spare[1] = 0;
+
+  /* Header checksum */
+  checksum = 0;
+  for (i = 0; i < sizeof(*header) - 2; i++)
+    checksum += buf[i + 0x40];
+
+  header->checksum[0] = checksum & 0xff;
+  header->checksum[1] = (checksum >> 8) & 0xff;
+
+  crc = crc32(buf, size - sizeof(uint32_t));
+
+  crc_idx = size - sizeof(uint32_t);
+
+  buf[crc_idx++] = crc & 0xff;
+  buf[crc_idx++] = (crc >> 8) & 0xff;
+  buf[crc_idx++] = (crc >> 16) & 0xff;
+  buf[crc_idx++] = (crc >> 24) & 0xff;
 }
 
-static void usage(const char *prgname)
+static int write_all(int fd, uint8_t *buf, size_t size)
 {
-	fprintf(stderr, "usage: %s [OPTIONS] <infile>\n", prgname);
+  while (size) {
+    ssize_t written = write(fd, buf, size);
+
+    if (written < 0) {
+      fprintf(stderr, "Error while writing: %s\n", strerror(errno));
+      return -1;
+    }
+
+    if (written == 0) {
+      fprintf(stderr, "Error while writing: short write\n");
+      return -1;
+    }
+
+    size -= (size_t)written;
+    buf += written;
+  }
+
+  return 0;
 }
 
-int main(int argc, char *argv[])
+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(uint8_t *buf, size_t length)
 {
-	int opt, ret;
-	const char *outfile = NULL, *infile;
-	struct stat s;
-	void *buf;
-	int fd;
-	int min_image_size = 80;
-	int max_image_size = MAX_IMAGE_SIZE;
-	int addsize = 0, pad;
-
-	while ((opt = getopt(argc, argv, "o:hb")) != -1) {
-		switch (opt) {
-		case 'b':
-			add_barebox_header = 1;
-			min_image_size = 0;
-			max_image_size = MAX_IMAGE_SIZE - 512;
-			addsize = 512;
-			break;
-		case 'h':
-			usage(argv[0]);
-			exit(0);
-		case 'o':
-			outfile = optarg;
-			break;
-		default:
-			exit(1);
-		}
-	}
-
-	if (optind == argc) {
-		usage(argv[0]);
-		exit(1);
-	}
-
-	infile = argv[optind];
-
-	ret = stat(infile, &s);
-	if (ret) {
-		perror("stat");
-		exit(1);
-	}
-
-	if (s.st_size < min_image_size) {
-		fprintf(stderr, "input image too small. Minimum is 80 bytes\n");
-		exit(1);
-	}
-
-	if (s.st_size > max_image_size) {
-		fprintf(stderr, "input image too big. Maximum is %d bytes, got %ld bytes\n",
-				max_image_size, s.st_size);
-		exit(1);
-	}
-
-	fd = open(infile, O_RDONLY);
-	if (fd < 0) {
-		perror("open infile");
-		exit(1);
-	}
-
-	pad = s.st_size & 0x3;
-	if (pad)
-		pad = 4 - pad;
-
-	buf = calloc(s.st_size + 4 + addsize + pad, 1);
-	if (!buf) {
-		perror("malloc");
-		exit(1);
-	}
-
-	ret = read_full(fd, buf + addsize, s.st_size);
-	if (ret < 0) {
-		perror("read infile");
-		exit(1);
-	}
-
-	close(fd);
-
-	if (add_barebox_header) {
-		memcpy(buf, bb_header, sizeof(bb_header));
-	}
-
-	ret = add_socfpga_header(buf, s.st_size + 4 + addsize + pad);
-	if (ret)
-		exit(1);
-
-	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-	if (fd < 0) {
-		perror("open outfile");
-		exit(1);
-	}
-
-	ret = write_full(fd, buf, s.st_size + 4 + addsize + pad);
-	if (ret < 0) {
-		perror("write outfile");
-		exit(1);
-	}
-
-	exit(0);
+  uint32_t crc = 0xffffffff;
+
+  while (length--) {
+    crc = crc << 8 ^ crc_table[(crc >> 24 ^ *(buf++)) & 0xff];
+  }
+
+  return crc ^ 0xffffffff;
 }
diff --git a/package/mkpimage/mkpimage.mk b/package/mkpimage/mkpimage.mk
index c30a6809c..0236062b6 100644
--- a/package/mkpimage/mkpimage.mk
+++ b/package/mkpimage/mkpimage.mk
@@ -4,9 +4,6 @@ 
 #
 ################################################################################
 
-# source included in the package
-# came from barebox's repository:
-# http://git.pengutronix.de/?p=barebox.git;a=blob;f=scripts/socfpga_mkimage.c;h=1a7a66d98841e9f52c3ea49c651286aa1412c9a5;hb=HEAD
 HOST_MKPIMAGE_LICENSE = GPLv2
 
 define HOST_MKPIMAGE_BUILD_CMDS