[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);