[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/tools/.gitignore b/src/bsp/lk/tools/.gitignore
new file mode 100644
index 0000000..3dc8f62
--- /dev/null
+++ b/src/bsp/lk/tools/.gitignore
@@ -0,0 +1,2 @@
+lkboot
+mkimage
diff --git a/src/bsp/lk/tools/Makefile b/src/bsp/lk/tools/Makefile
new file mode 100644
index 0000000..af4c825
--- /dev/null
+++ b/src/bsp/lk/tools/Makefile
@@ -0,0 +1,17 @@
+
+all: lkboot mkimage
+
+LKBOOT_SRCS := lkboot.c liblkboot.c network.c
+LKBOOT_DEPS := network.h liblkboot.h ../app/lkboot/lkboot_protocol.h
+LKBOOT_INCS :=
+lkboot: $(LKBOOT_SRCS) $(LKBOOT_DEPS)
+	gcc -Wall -o $@ $(LKBOOT_INCS) $(LKBOOT_SRCS)
+
+MKIMAGE_DEPS := bootimage.h ../lib/bootimage/include/lib/bootimage_struct.h
+MKIMAGE_SRCS := mkimage.c bootimage.c ../lib/mincrypt/sha256.c
+MKIMAGE_INCS := -I../lib/mincrypt/include -I../lib/bootimage/include
+mkimage: $(MKIMAGE_SRCS) $(MKIMAGE_DEPS)
+	gcc -Wall -g -o $@ $(MKIMAGE_INCS) $(MKIMAGE_SRCS)
+
+clean::
+	rm -f lkboot mkimage
diff --git a/src/bsp/lk/tools/bin2h.py b/src/bsp/lk/tools/bin2h.py
new file mode 100755
index 0000000..52d4bae
--- /dev/null
+++ b/src/bsp/lk/tools/bin2h.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# vim: set expandtab ts=4 sw=4 tw=100:
+
+import sys
+from optparse import OptionParser
+
+parser = OptionParser()
+parser.add_option("-b", "--before", dest="before", action="append",
+                  help="text to put before, may be specified more than once")
+parser.add_option("-a", "--after", dest="after", action="append",
+                  help="text to put after, may be specified more than once")
+(options, args) = parser.parse_args()
+
+if options.before and len(options.before) > 0:
+    for b in options.before:
+        print b
+
+offset = 0
+f = bytearray(sys.stdin.read())
+for c in f:
+    if offset != 0 and offset % 16 == 0:
+        print ""
+    print "%#04x," % c,
+    offset = offset + 1
+print ""
+
+if options.after and len(options.after) > 0:
+    for a in options.after:
+        print a
+
diff --git a/src/bsp/lk/tools/bootimage.c b/src/bsp/lk/tools/bootimage.c
new file mode 100644
index 0000000..1b0e607
--- /dev/null
+++ b/src/bsp/lk/tools/bootimage.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2014 Brian Swetland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <lib/mincrypt/sha256.h>
+
+#include "bootimage.h"
+
+struct bootimage {
+	bootentry entry[64];
+	void *data[64];
+	uint32_t offset[64];
+	uint32_t length[64];
+	unsigned count;
+	uint32_t next_offset;
+};
+
+bootimage *bootimage_init(void) {
+	bootimage *img;
+
+	if ((img = malloc(sizeof(bootimage))) == NULL) {
+		return NULL;
+	}
+	memset(img, 0, sizeof(bootimage));
+	img->count = 2;
+	img->next_offset = 4096;
+	memset(img->entry, 0, 4096);
+	img->entry[0].file.kind = KIND_FILE;
+	img->entry[0].file.type = TYPE_BOOT_IMAGE;
+	img->entry[0].file.offset = 0;
+	img->entry[0].file.length = 4096;
+	img->entry[1].info.kind = KIND_BOOT_INFO;
+	img->entry[1].info.version = BOOT_VERSION;
+	memcpy(img->entry[0].file.name, BOOT_MAGIC, BOOT_MAGIC_LENGTH);
+	return img;
+}
+
+bootentry_data *bootimage_add_string(bootimage *img, unsigned kind, const char *s) {
+	unsigned n = img->count;
+	int len = strlen(s);
+	if (img->count == 64) return NULL;
+	if (len > 59) return NULL;
+	img->count++;
+
+	img->entry[n].data.kind = kind;
+	strcpy((char*) img->entry[n].data.u.b, s);
+	return &(img->entry[n].data);
+}
+
+bootentry_file *bootimage_add_filedata(bootimage *img, unsigned type, void *data, unsigned len) {
+	unsigned n = img->count;
+	if (img->count == 64) return NULL;
+	img->count++;
+
+	// align to page boundary
+	img->next_offset = (img->next_offset + 4095) & (~4095);
+
+	img->entry[n].file.kind = KIND_FILE;
+	img->entry[n].file.type = type;
+	img->entry[n].file.offset = img->next_offset;
+	img->entry[n].file.length = len;
+	SHA256_hash(data, len, img->entry[n].file.sha256);
+
+	img->data[n] = data;
+	img->offset[n] = img->next_offset;
+	img->length[n] = len;
+
+	img->next_offset += len; 
+
+	return &(img->entry[n].file);
+}
+
+void bootimage_done(bootimage *img) {
+	unsigned sz = img->next_offset;
+	if (sz & 4095) {
+		sz += (4096 - (sz & 4095));
+	}
+	img->entry[1].info.image_size = sz;
+	img->entry[1].info.entry_count = img->count;
+	SHA256_hash((void*) &(img->entry[1]), 4096 - 64, img->entry[0].file.sha256);
+}
+
+static int writex(int fd, void *data, size_t len) {
+	int r;
+	char *x = data;
+	while (len > 0) {
+		r = write(fd, x, len);
+		if (r < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			return -1;
+		}
+		len -= r;
+		x += r;
+	}
+	return 0;
+}
+
+static uint8_t filler[4096] = { 0, };
+
+int bootimage_write(bootimage *img, int fd) {
+	unsigned off = 4096;
+	unsigned n, s;
+	if (writex(fd, img->entry, 4096)) {
+		return -1;
+	}
+	for (n = 1; n < 64; n++) {
+		if (img->offset[n] == 0) continue;
+		if (img->offset[n] < off) return -1;
+		s = img->offset[n] - off;
+		if (s > 4095) return -1;
+		if (writex(fd, filler, s)) {
+			return -1;
+		}
+		off += s;
+		if (writex(fd, img->data[n], img->length[n])) {
+			return -1;
+		}
+		off += img->length[n];
+	}
+	if (off & 4095) {
+		if (writex(fd, filler, 4096 - (off & 4095))) return -1;
+	}
+	return 0;
+}
+
+static void *load_file(const char *fn, size_t *len) {
+	off_t sz;
+	void *data = NULL;
+	char *x;
+	int fd, r;
+
+	if((fd = open(fn, O_RDONLY)) < 0) {
+		return NULL;
+	}
+
+	if ((sz = lseek(fd, 0, SEEK_END)) < 0) {
+		goto fail;
+	}
+	if (lseek(fd, 0, SEEK_SET) != 0) {
+		goto fail;
+	}
+
+	if ((data = malloc(sz)) == NULL) {
+		goto fail;
+	}
+	x = data;
+	if (len) {
+		*len = sz;
+	}
+	while (sz > 0) {
+		r = read(fd, x, sz);
+		if (r < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			goto fail;
+		}
+		sz -= r;
+		x += r;
+	}
+	close(fd);
+	return data;
+
+fail:
+	if (data) {
+		free(data);
+	}
+	close(fd);
+	return NULL;
+}
+
+bootentry_file *bootimage_add_file(bootimage *img, unsigned type, const char *fn) {
+	unsigned char *data;
+	size_t len;
+
+	if ((data = load_file(fn, &len)) == NULL) {
+		fprintf(stderr, "error: cannot load '%s'\n", fn);
+		return NULL;
+	}
+
+	/* if fpga image, trim everything before ffffffaa995566 and wordwise endian swap */
+	if (type == TYPE_FPGA_IMAGE) {
+		static const unsigned char pat[] = { 0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 };
+
+		size_t i;
+		if (len < sizeof(pat)) {
+			free(data);
+			fprintf(stderr, "error: fpga image too short\n");
+			return NULL;
+		}
+
+		for (i = 0; i < len - sizeof(pat); i++) {
+			if (!memcmp(data + i, pat, sizeof(pat))) {
+				/* we've found the pattern, trim everything before it */
+				memmove(data, data + i, len - i);
+				len -= i;
+			}
+		}
+
+		/* wordwise endian swap */
+#define SWAP_32(x) \
+    (((uint32_t)(x) << 24) | (((uint32_t)(x) & 0xff00) << 8) |(((uint32_t)(x) & 0x00ff0000) >> 8) | ((uint32_t)(x) >> 24))
+		uint32_t *w = (uint32_t *)data;
+		for (i = 0; i < len / 4; i++) {
+			*w = SWAP_32(*w);
+			w++;
+		}
+#undef SWAP_32
+	}
+
+	return bootimage_add_filedata(img, type, data, len);
+}
+
diff --git a/src/bsp/lk/tools/bootimage.h b/src/bsp/lk/tools/bootimage.h
new file mode 100644
index 0000000..d66e2b1
--- /dev/null
+++ b/src/bsp/lk/tools/bootimage.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014 Brian Swetland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <lib/bootimage_struct.h>
+
+typedef struct bootimage bootimage;
+
+bootimage *bootimage_init(void);
+
+bootentry_data *bootimage_add_string(
+	bootimage *img, unsigned kind, const char *s);
+
+bootentry_file *bootimage_add_filedata(
+	bootimage *img, unsigned type, void *data, unsigned len);
+
+bootentry_file *bootimage_add_file(
+	bootimage *img, unsigned type, const char *fn);
+
+void bootimage_done(bootimage *img);
+
+int bootimage_write(bootimage *img, int fd);
diff --git a/src/bsp/lk/tools/liblkboot.c b/src/bsp/lk/tools/liblkboot.c
new file mode 100644
index 0000000..be4a3f2
--- /dev/null
+++ b/src/bsp/lk/tools/liblkboot.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2014 Brian Swetland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include "network.h"
+#include "../app/lkboot/lkboot_protocol.h"
+
+static int readx(int s, void *_data, int len) {
+	char *data = _data;
+	int r;
+	while (len > 0) {
+		r = read(s, data, len);
+		if (r == 0) {
+			fprintf(stderr, "error: eof during socket read\n");
+			return -1;
+		}
+		if (r < 0) {
+			if (errno == EINTR) continue;
+			fprintf(stderr, "error: %s during socket read\n", strerror(errno));
+			return -1;
+		}
+		data += r;
+		len -= r;
+	}
+	return 0;
+}
+
+static int upload(int s, int txfd, size_t txlen, int do_endian_swap) {
+	int err = 0;
+	msg_hdr_t hdr;
+
+	char *buf = malloc(txlen);
+	if (!buf)
+		return -1;
+
+	if (readx(txfd, buf, txlen)) {
+		fprintf(stderr, "error: reading from file\n");
+		err = -1;
+		goto done;
+	}
+
+	/* 4 byte swap data if requested */
+	if (do_endian_swap) {
+		size_t i;
+		for (i = 0; i < txlen; i += 4) {
+			char temp = buf[i];
+			buf[i] = buf[i + 3];
+			buf[i + 3] = temp;
+
+			temp = buf[i + 1];
+			buf[i + 1] = buf[i + 2];
+			buf[i + 2] = temp;
+		}
+	}
+
+	size_t pos = 0;
+	while (pos < txlen) {
+		size_t xfer = (txlen - pos > 65536) ? 65536 : txlen - pos;
+
+		hdr.opcode = MSG_SEND_DATA;
+		hdr.extra = 0;
+		hdr.length = xfer - 1;
+		if (write(s, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+			fprintf(stderr, "error: writing socket\n");
+			err = -1;
+			goto done;
+		}
+		if (write(s, buf + pos, xfer) != xfer) {
+			fprintf(stderr, "error: writing socket\n");
+			err = -1;
+			goto done;
+		}
+		pos += xfer;
+	}
+
+	hdr.opcode = MSG_END_DATA;
+	hdr.extra = 0;
+	hdr.length = 0;
+	if (write(s, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+		fprintf(stderr, "error: writing socket\n");
+		err = -1;
+		goto done;
+	}
+
+done:
+	free(buf);
+
+	return err;
+}
+
+static off_t trim_fpga_image(int fd, off_t len)
+{
+	/* fd should be at start of bitfile, seek until the
+	 * ff ff ff ff aa 99 55 66 pattern is found and subtract
+	 * the number of bytes read until pattern found.
+	 */
+	const unsigned char pat[] = { 0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 };
+	unsigned char buf[sizeof(pat)];
+
+	memset(buf, 0, sizeof(buf));
+
+	off_t i;
+	for (i = 0; i < len; i++) {
+		memmove(buf, buf + 1, sizeof(buf) - 1);
+		if (read(fd, &buf[sizeof(buf) - 1], 1) < 1) {
+			return -1;
+		}
+
+		/* look for pattern */
+		if (memcmp(pat, buf, sizeof(pat)) == 0) {
+			/* found it, rewind the fd and return the truncated length */
+			lseek(fd, -sizeof(pat), SEEK_CUR);
+			return len - (i + 1 - sizeof(pat));
+		}
+	}
+
+	return -1;
+}
+
+#define DCC_SUBPROCESS "zynq-dcc"
+
+static int start_dcc_subprocess(int *fd_in, int *fd_out)
+{
+	int outpipe[2];
+	if (pipe(outpipe) != 0)
+		return -1;
+
+	int inpipe[2];
+	if (pipe(inpipe) != 0)
+		return -1;
+
+	*fd_in = inpipe[0];
+	*fd_out = outpipe[1];
+
+	pid_t pid = fork();
+	if (pid == 0) {
+		/* we are the child */
+		close(STDIN_FILENO);
+		close(STDOUT_FILENO);
+
+		dup2(outpipe[0], STDIN_FILENO);
+		close(outpipe[1]);
+
+		dup2(inpipe[1], STDOUT_FILENO);
+		close(inpipe[0]);
+
+		fprintf(stderr, "in the child\n");
+
+		execlp(DCC_SUBPROCESS, DCC_SUBPROCESS, NULL);
+		fprintf(stderr, "after exec, didn't work!\n");
+	} else {
+		fprintf(stderr, "in parent, pid %u\n", pid);
+
+		close(outpipe[0]);
+		close(inpipe[1]);
+	}
+
+	return 0;
+}
+
+#define REPLYMAX (9 * 1024 * 1024)
+static unsigned char replybuf[REPLYMAX];
+static unsigned replylen = 0;
+
+unsigned lkboot_get_reply(void **ptr) {
+	*ptr = replybuf;
+	return replylen;
+}
+
+int lkboot_txn(const char *host, const char *_cmd, int txfd, const char *args) {
+	msg_hdr_t hdr;
+	char cmd[128];
+	char tmp[65536];
+	off_t txlen = 0;
+	int do_endian_swap = 0;
+	int once = 1;
+	int len;
+	int fd_in, fd_out;
+	int ret = 0;
+
+	if (txfd != -1) {
+		txlen = lseek(txfd, 0, SEEK_END);
+		if (txlen > (512*1024*1024)) {
+			fprintf(stderr, "error: file too large\n");
+			return -1;
+		}
+		lseek(txfd, 0, SEEK_SET);
+	}
+
+	if (!strcmp(_cmd, "fpga")) {
+		/* if we were asked to send an fpga image, try to find the sync words and
+		 * trim all the data before it
+		 */
+		txlen = trim_fpga_image(txfd, txlen);
+		if (txlen < 0) {
+			fprintf(stderr, "error: fpga image doesn't contain sync pattern\n");
+			return -1;
+		}
+
+		/* it'll need a 4 byte endian swap as well */
+		do_endian_swap = 1;
+	}
+
+	len = snprintf(cmd, 128, "%s:%d:%s", _cmd, (int) txlen, args);
+	if (len > 127) {
+		fprintf(stderr, "error: command too large\n");
+		return -1;
+	}
+
+	/* if host is -, use stdin/stdout */
+	if (!strcmp(host, "-")) {
+		fprintf(stderr, "using stdin/stdout for io\n");
+		fd_in = STDIN_FILENO;
+		fd_out = STDOUT_FILENO;
+	} else if (!strcasecmp(host, "jtag")) {
+		fprintf(stderr, "using zynq-dcc utility for io\n");
+		if (start_dcc_subprocess(&fd_in, &fd_out) < 0) {
+			fprintf(stderr, "error starting jtag subprocess, is it in your path?\n");
+			return -1;
+		}
+	} else {
+		in_addr_t addr = lookup_hostname(host);
+		if (addr == 0) {
+			fprintf(stderr, "error: cannot find host '%s'\n", host);
+			return -1;
+		}
+		while ((fd_in = tcp_connect(addr, 1023)) < 0) {
+			if (once) {
+				fprintf(stderr, "error: cannot connect to host '%s'. retrying...\n", host);
+				once = 0;
+			}
+			usleep(100000);
+		}
+		fd_out = fd_in;
+	}
+
+	hdr.opcode = MSG_CMD;
+	hdr.extra = 0;
+	hdr.length = len;
+	if (write(fd_out, &hdr, sizeof(hdr)) != sizeof(hdr)) goto iofail;
+	if (write(fd_out, cmd, len) != len) goto iofail;
+
+	for (;;) {
+		if (readx(fd_in, &hdr, sizeof(hdr))) goto iofail;
+		switch (hdr.opcode) {
+		case MSG_GO_AHEAD:
+			if (upload(fd_out, txfd, txlen, do_endian_swap)) {
+				ret = -1;
+				goto out;
+			}
+			break;
+		case MSG_OKAY:
+			ret = 0;
+			goto out;
+		case MSG_FAIL:
+			len = (hdr.length > 127) ? 127 : hdr.length;
+			if (readx(fd_in, cmd, len)) {
+				cmd[0] = 0;
+			} else {
+				cmd[len] = 0;
+			}
+			fprintf(stderr,"error: remote failure: %s\n", cmd);
+			ret = -1;
+			goto out;
+		case MSG_SEND_DATA:
+			len = hdr.length + 1;
+			if (readx(fd_in, tmp, len)) goto iofail;
+			if (len > (REPLYMAX - replylen)) {
+				fprintf(stderr, "error: too much reply data\n");
+				ret = -1;
+				goto out;
+			}
+			memcpy(replybuf + replylen, tmp, len);
+			replylen += len;
+			break;
+		default:
+			fprintf(stderr, "error: unknown opcode %d\n", hdr.opcode);
+			ret = -1;
+			goto out;
+		}
+	}
+
+iofail:
+	fprintf(stderr, "error: socket io\n");
+	ret = -1;
+
+out:
+	close(fd_in);
+	if (fd_out != fd_in)
+		close(fd_out);
+	return ret;
+}
+
+// vim: noexpandtab
diff --git a/src/bsp/lk/tools/liblkboot.h b/src/bsp/lk/tools/liblkboot.h
new file mode 100644
index 0000000..7297160
--- /dev/null
+++ b/src/bsp/lk/tools/liblkboot.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014 Brian Swetland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+// connect to host, issue cmd:args, and if txfd != -1, send the contents
+// of that file as the command payload
+int lkboot_txn(const char *host, const char *cmd, int txfd, const char *args);
+
+// return number of bytes of data the last txn resulted in and if nonzero
+// set *ptr = the buffer (which remains valid until next lkboot_txn())
+unsigned lkboot_get_reply(void **ptr);
diff --git a/src/bsp/lk/tools/lkboot.c b/src/bsp/lk/tools/lkboot.c
new file mode 100644
index 0000000..459e17d
--- /dev/null
+++ b/src/bsp/lk/tools/lkboot.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2014 Brian Swetland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include "liblkboot.h"
+
+void usage(void) {
+	fprintf(stderr,
+"usage: lkboot <hostname> <command> ...\n"
+"\n"
+"       lkboot <hostname> flash <partition> <filename>\n"
+"       lkboot <hostname> erase <partition>\n"
+"       lkboot <hostname> remove <partition>\n"
+"       lkboot <hostname> fpga <bitfile>\n"
+"       lkboot <hostname> boot <binary>\n"
+"       lkboot <hostname> getsysparam <name>\n"
+"       lkboot <hostname> reboot\n"
+"       lkboot <hostname> :<commandname> [ <arg>* ]\n"
+"\n"
+"NOTE: If <hostname> is 'jtag', lkboot will attempt to use\n"
+"       a tool 'zynq-dcc' to communicate with the device.\n"
+"       Make sure it is in your path.\n"
+"\n"
+	);
+	exit(1);
+}
+
+void printsysparam(void *data, int len) {
+	unsigned char *x = data;
+	int i;
+	for (i = 0; i < len; i++) {
+		if ((x[i] < ' ') || (x[1] > 127)) goto printhex;
+	}
+	write(STDERR_FILENO, "\"", 1);
+	write(STDERR_FILENO, data, len);
+	write(STDERR_FILENO, "\"\n", 2);
+	return;
+printhex:
+	fprintf(stderr, "[");
+	for (i = 0; i < len; i++) fprintf(stderr, " %02x", x[i]);
+	fprintf(stderr, " ]\n");
+}
+
+int main(int argc, char **argv) {
+	const char *host = argv[1];
+	const char *cmd = argv[2];
+	const char *args = argv[3];
+	const char *fn = NULL;
+	int fd = -1;
+
+	if (argc == 3) {
+		if (!strcmp(cmd, "reboot")) {
+			return lkboot_txn(host, cmd, fd, "");
+		} else if (cmd[0] == ':') {
+			return lkboot_txn(host, cmd + 1, fd, "");
+		} else {
+			usage();
+		}
+	}
+
+	if (argc < 4) usage();
+
+	if (!strcmp(cmd, "flash")) {
+		if (argc < 5) usage();
+		fn = argv[4];
+	} else if (!strcmp(cmd, "fpga")) {
+		fn = args;
+		args = "";
+	} else if (!strcmp(cmd, "boot")) {
+		fn = args;
+		args = "";
+	} else if (!strcmp(cmd, "erase")) {
+	} else if (!strcmp(cmd, "remove")) {
+	} else if (!strcmp(cmd, "getsysparam")) {
+		if (lkboot_txn(host, cmd, -1, args) == 0) {
+			void *rbuf = NULL;
+			printsysparam(rbuf, lkboot_get_reply(&rbuf));
+			return 0;
+		} else {
+			return -1;
+		}
+	} else if (cmd[0] == ':') {
+		return lkboot_txn(host, cmd + 1, -1, args);
+	} else {
+		usage();
+	}
+	if (fn) {
+		if ((fd = open(fn, O_RDONLY)) < 0) {
+			fprintf(stderr, "error; cannot open '%s'\n", fn);
+			return -1;
+		}
+	}
+	return lkboot_txn(host, cmd, fd, args);
+}
+
+// vim: noexpandtab
diff --git a/src/bsp/lk/tools/mkimage.c b/src/bsp/lk/tools/mkimage.c
new file mode 100644
index 0000000..aceaa86
--- /dev/null
+++ b/src/bsp/lk/tools/mkimage.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014 Brian Swetland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "bootimage.h"
+
+static const char *outname = "boot.img";
+
+static struct {
+	const char *cmd;
+	unsigned kind;
+	unsigned type;
+} types[] = {
+	{ "lk", KIND_FILE, TYPE_LK },
+	{ "fpga", KIND_FILE, TYPE_FPGA_IMAGE },
+	{ "linux", KIND_FILE, TYPE_LINUX_KERNEL },
+	{ "initrd", KIND_FILE, TYPE_LINUX_INITRD },
+	{ "devicetree", KIND_FILE, TYPE_DEVICE_TREE },
+	{ "sysparams", KIND_FILE, TYPE_SYSPARAMS },
+	{ "board", KIND_BOARD, 0 },
+	{ "build", KIND_BUILD, 0 },
+	{ NULL, 0 },
+};
+
+void usage(const char *binary) {
+	unsigned n;
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, "%s [-h] [-o <output file] section:file ...\n\n", binary);
+
+	fprintf(stderr, "Supported section types:\n");
+	for (n = 0; types[n].cmd != NULL; n++) {
+		if (types[n].kind == KIND_FILE) {
+			fprintf(stderr, "\t%s\n", types[n].cmd);
+		}
+	}
+
+	fprintf(stderr, "\nSupported string types:\n");
+	for (n = 0; types[n].cmd != NULL; n++) {
+		if (types[n].kind != KIND_FILE) {
+			fprintf(stderr, "\t%s\n", types[n].cmd);
+		}
+	}
+}
+
+int process(bootimage *img, char *cmd, char *arg) {
+	unsigned n;
+
+	for (n = 0; types[n].cmd != NULL; n++) {
+		if (strcmp(cmd, types[n].cmd)) {
+			continue;
+		}
+		if (types[n].kind == KIND_FILE) {
+			if (bootimage_add_file(img, types[n].type, arg) == NULL) {
+				return -1;
+			}
+		} else {
+			if (bootimage_add_string(img, types[n].kind, arg) == NULL) {
+				return -1;
+			}
+		}
+		return 0;
+	}
+
+	fprintf(stderr, "unknown command '%s'\n", cmd);
+	return -1;
+}
+
+int main(int argc, char **argv) {
+	const char *binary = argv[0];
+	bootimage *img;
+	int fd;
+	int count = 0;
+
+	img = bootimage_init();
+
+	while (argc > 1) {
+		char *cmd = argv[1];
+		char *arg = strchr(cmd, ':');
+		argc--;
+		argv++;
+
+		if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
+			usage(binary);
+			return 1;
+		} else if (!strcmp(cmd, "-o")) {
+			outname = argv[1];
+			argc--;
+			argv++;
+		} else {
+			if (arg == NULL) {
+				fprintf(stderr, "error: invalid argument '%s'\n", cmd);
+				return 1;
+			}
+
+			*arg++ = 0;
+
+			if (process(img, cmd, arg)) {
+				return 1;
+			}
+			count++;
+		}
+	}
+
+	if (count == 0) {
+		fprintf(stderr, "no sections to process\n");
+		return 1;
+	}
+
+	bootimage_done(img);
+
+	if ((fd = open(outname, O_CREAT|O_TRUNC|O_WRONLY, 0644)) < 0) {
+		fprintf(stderr, "error: cannot open '%s' for writing\n", outname);
+		return 1;
+	}
+	if (bootimage_write(img, fd)) {
+		fprintf(stderr, "error: failed to write '%s'\n", outname);
+		unlink(outname);
+		return 1;
+	}
+	close(fd);
+	return 0;
+}
+
+// vim: set noexpandtab:
diff --git a/src/bsp/lk/tools/network.c b/src/bsp/lk/tools/network.c
new file mode 100644
index 0000000..bf805a2
--- /dev/null
+++ b/src/bsp/lk/tools/network.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014 Brian Swetland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "network.h"
+
+in_addr_t lookup_hostname(const char *hostname) {
+	int err;
+	struct addrinfo *info, *temp;
+	in_addr_t addr = 0;
+
+	struct addrinfo hints;
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_INET;
+	hints.ai_socktype = SOCK_STREAM;
+
+	err = getaddrinfo(hostname, NULL, &hints, &info);
+	if (err < 0) {
+		printf("getaddrinfo() returns %d, error '%s'\n", err, gai_strerror(err));
+		return 0;
+	}
+
+	for (temp = info; temp; temp = temp->ai_next) {
+//		printf("flags 0x%x, family %d, socktype %d, protocol %d, addrlen %d\n",
+//			temp->ai_flags, temp->ai_family, temp->ai_socktype, temp->ai_protocol, temp->ai_addrlen);
+
+		if (temp->ai_family == AF_INET && temp->ai_protocol == IPPROTO_TCP) {
+			struct sockaddr_in *sa = (struct sockaddr_in *)temp->ai_addr;
+//			printf("port %d, addr 0x%x\n", sa->sin_port, sa->sin_addr.s_addr);
+			addr = sa->sin_addr.s_addr;
+		}
+	}
+
+	freeaddrinfo(info);
+
+	return addr;
+}
+
+static int inet_listen(in_addr_t addr, int type, unsigned port, int shared) {
+	struct sockaddr_in sa;
+	int s;
+	if ((s = socket(AF_INET, type, 0)) < 0) {
+		return -1;
+	}
+	if (shared) {
+		int opt = 1;
+    		setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+    		//setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
+	}
+	memset(&sa, 0, sizeof(sa));
+	sa.sin_family = AF_INET;
+	sa.sin_port = htons(port);
+	sa.sin_addr.s_addr = addr;
+	if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+		close(s);
+		return -1;
+	}
+	return s;
+}
+
+static int inet_connect(in_addr_t addr, int type, unsigned port) {
+	struct sockaddr_in sa;
+	int s;
+	if ((s = socket(AF_INET, type, 0)) < 0) {
+		return -1;
+	}
+	if (addr == 0xFFFFFFFF) {
+		int opt = 1;
+		setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
+	}
+	memset(&sa, 0, sizeof(sa));
+	sa.sin_family = AF_INET;
+	sa.sin_port = htons(port);
+	sa.sin_addr.s_addr = addr;
+	if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+		close(s);
+		return -1;
+	}
+	return s;
+}
+
+int udp_listen(in_addr_t addr, unsigned port, int shared) {
+	return inet_listen(addr, SOCK_DGRAM, port, shared);
+}
+
+int udp_connect(in_addr_t addr, unsigned port) {
+	return inet_connect(addr, SOCK_DGRAM, port);
+}
+
+int tcp_listen(in_addr_t addr, unsigned port) {
+	return inet_listen(addr, SOCK_STREAM, port, 0);
+}
+
+int tcp_connect(in_addr_t addr, unsigned port) {
+	return inet_connect(addr, SOCK_STREAM, port);
+}
+
+// vim: noexpandtab
diff --git a/src/bsp/lk/tools/network.h b/src/bsp/lk/tools/network.h
new file mode 100644
index 0000000..30bdca9
--- /dev/null
+++ b/src/bsp/lk/tools/network.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014 Brian Swetland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#pragma once
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+int udp_listen(in_addr_t addr, unsigned port, int shared);
+int udp_connect(in_addr_t addr, unsigned port);
+
+int tcp_listen(in_addr_t addr, unsigned port);
+int tcp_connect(in_addr_t addr, unsigned port);
+
+in_addr_t lookup_hostname(const char *hostname);