summaryrefslogtreecommitdiff
path: root/ao-tools/lib
diff options
context:
space:
mode:
authorBdale Garbee <bdale@gag.com>2016-05-06 17:59:39 -0600
committerBdale Garbee <bdale@gag.com>2016-05-06 17:59:39 -0600
commitac7be4a40df88ee3a0992e041635e4ac4cf5ac48 (patch)
treeee3c747b2ee98b772e02dce604b58878e9336def /ao-tools/lib
parentb53c78e75879d647935a30acb88fdd69467617a7 (diff)
parentce4c8a8ad57515e851207b0a82f3af791bb30d3e (diff)
Merge branch 'master' into branch-1.6
Diffstat (limited to 'ao-tools/lib')
-rw-r--r--ao-tools/lib/Makefile.am2
-rw-r--r--ao-tools/lib/ao-dfu.c202
-rw-r--r--ao-tools/lib/ao-dfu.h35
-rw-r--r--ao-tools/lib/ao-elf.c6
-rw-r--r--ao-tools/lib/ao-hex.c33
-rw-r--r--ao-tools/lib/ao-hex.h3
6 files changed, 274 insertions, 7 deletions
diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am
index a03a976c..a33d682d 100644
--- a/ao-tools/lib/Makefile.am
+++ b/ao-tools/lib/Makefile.am
@@ -46,6 +46,8 @@ libao_tools_a_SOURCES = \
ao-editaltos.h \
ao-elf.c \
ao-elf.h \
+ ao-dfu.c \
+ ao-dfu.h \
ao-selfload.c \
ao-selfload.h \
ao-verbose.c \
diff --git a/ao-tools/lib/ao-dfu.c b/ao-tools/lib/ao-dfu.c
new file mode 100644
index 00000000..b6778495
--- /dev/null
+++ b/ao-tools/lib/ao-dfu.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include "ao-hex.h"
+#include "ao-dfu.h"
+
+static uint32_t dfu_crc;
+static FILE *dfu_file;
+static int dfu_failed;
+static int dfu_error;
+
+static uint32_t update_crc(uint32_t crc, uint8_t byte)
+{
+ int j;
+ uint32_t mask;
+
+ crc = crc ^ byte;
+ for (j = 0; j < 8; j++) {
+ mask = -(crc & 1);
+ crc = (crc >> 1) ^ (0xEDB88320 & mask);
+ }
+ return crc;
+}
+
+static void dfu_init(FILE *file)
+{
+ dfu_crc = 0xffffffff;
+ dfu_file = file;
+ dfu_failed = 0;
+ dfu_error = 0;
+}
+
+static int dfu_fini(void)
+{
+ if (fflush(dfu_file) == EOF) {
+ if (!dfu_failed) {
+ dfu_failed = 1;
+ dfu_error = errno;
+ }
+ }
+ if (dfu_failed)
+ errno = dfu_error;
+ return !dfu_failed;
+}
+
+static void dfu_8(uint8_t byte) {
+ if (putc(byte, dfu_file) == EOF) {
+ if (!dfu_failed) {
+ dfu_failed = 1;
+ dfu_error = errno;
+ }
+ }
+ dfu_crc = update_crc(dfu_crc, byte);
+}
+
+static void dfu_pad(int len) {
+ while (len--)
+ dfu_8(0);
+}
+
+static void dfu_string(char *string) {
+ char c;
+
+ while ((c = *string++))
+ dfu_8((uint8_t) c);
+}
+
+static void dfu_string_pad(char *string, int len) {
+ char c;
+
+ while ((c = *string++)) {
+ dfu_8((uint8_t) c);
+ len--;
+ }
+ dfu_pad(len);
+}
+
+static void dfu_block(uint8_t *bytes, int len) {
+ while (len--)
+ dfu_8(*bytes++);
+}
+
+static void dfu_lsb16(uint16_t value) {
+ dfu_8(value);
+ dfu_8(value>>8);
+}
+
+static void dfu_lsb32(uint32_t value) {
+ dfu_8(value);
+ dfu_8(value >> 8);
+ dfu_8(value >> 16);
+ dfu_8(value >> 24);
+}
+
+static uint32_t dfu_image_size(struct ao_hex_image *image) {
+ return 8 + image->length;
+}
+
+static uint32_t dfu_images_size(int num_image, struct ao_hex_image images[])
+{
+ uint32_t size = 0;
+ int i;
+
+ for (i = 0; i < num_image; i++)
+ size += dfu_image_size(&images[i]);
+ return size;
+}
+
+static void dfu_image(struct ao_hex_image *image)
+{
+ dfu_lsb32(image->address);
+ dfu_lsb32(image->length);
+ dfu_block(image->data, image->length);
+}
+
+static void dfu_target(char *name, int num_image, struct ao_hex_image images[])
+{
+ uint32_t images_size = dfu_images_size(num_image, images);
+ int i;
+
+ dfu_string("Target");
+ dfu_8(0);
+ if (name) {
+ dfu_8(1);
+ dfu_pad(3);
+ dfu_string_pad(name, 255);
+ } else {
+ dfu_8(0);
+ dfu_pad(3);
+ dfu_pad(255);
+ }
+ dfu_lsb32(images_size);
+ dfu_lsb32(num_image);
+ for (i = 0; i < num_image; i++)
+ dfu_image(&images[i]);
+}
+
+static uint32_t dfu_target_size(int num_image, struct ao_hex_image images[])
+{
+ return 274 + dfu_images_size(num_image, images);
+}
+
+static uint32_t
+dfu_size(int num_image, struct ao_hex_image images[])
+{
+ uint32_t size = 0;
+ size += 11; /* DFU Prefix */
+
+ size += dfu_target_size(num_image, images);
+
+ return size;
+}
+
+int
+ao_dfu_write(FILE *file, struct ao_dfu_info *info, int num_image, struct ao_hex_image images[])
+{
+ uint32_t total_size;
+
+ total_size = dfu_size(num_image, images);
+
+ dfu_init(file);
+ /* DFU Prefix */
+ dfu_string(DFU_SIGNATURE);
+ dfu_8(0x01);
+ dfu_lsb32(total_size);
+ dfu_8(0x01);
+
+ dfu_target("ST...", num_image, images);
+
+ /* DFU Suffix */
+ dfu_lsb16(info->bcdDevice);
+ dfu_lsb16(info->idProduct);
+ dfu_lsb16(info->idVendor);
+ dfu_lsb16(DFU_SPEC_VERSION);
+ dfu_string("UFD");
+ dfu_8(16);
+ dfu_lsb32(dfu_crc);
+ return dfu_fini();
+}
+
diff --git a/ao-tools/lib/ao-dfu.h b/ao-tools/lib/ao-dfu.h
new file mode 100644
index 00000000..c3dfc496
--- /dev/null
+++ b/ao-tools/lib/ao-dfu.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_DFU_H_
+#define _AO_DFU_H_
+
+struct ao_dfu_info {
+ uint16_t bcdDevice;
+ uint16_t idProduct;
+ uint16_t idVendor;
+};
+
+#define DFU_SIGNATURE "DfuSe"
+#define DFU_SPEC_VERSION 0x011a
+
+#define DFU_TARGET_SIGNATURE "Target"
+
+int
+ao_dfu_write(FILE *file, struct ao_dfu_info *info, int num_image, struct ao_hex_image images[]);
+
+#endif /* _AO_DFU_H_ */
diff --git a/ao-tools/lib/ao-elf.c b/ao-tools/lib/ao-elf.c
index 99b37210..680a80f0 100644
--- a/ao-tools/lib/ao-elf.c
+++ b/ao-tools/lib/ao-elf.c
@@ -206,7 +206,7 @@ get_load(Elf *e)
#endif
size_t nshdr;
size_t s;
-
+
if (elf_getshdrstrndx(e, &shstrndx) < 0)
return 0;
@@ -238,7 +238,7 @@ get_load(Elf *e)
(uint32_t) phdr.p_filesz,
(uint32_t) phdr.p_memsz);
#endif
-
+
for (s = 0; s < nshdr; s++) {
scn = elf_getscn(e, s);
@@ -256,7 +256,7 @@ get_load(Elf *e)
#endif
if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) {
-
+
if (shdr.sh_size == 0)
continue;
diff --git a/ao-tools/lib/ao-hex.c b/ao-tools/lib/ao-hex.c
index 5cfc63c1..2ceed7ab 100644
--- a/ao-tools/lib/ao-hex.c
+++ b/ao-tools/lib/ao-hex.c
@@ -294,7 +294,7 @@ load_symbols(struct ao_hex_file *hex,
struct ao_sym *symbol;
int num_symbols = 0;
int size_symbols = 0;
-
+
extended_addr = 0;
for (i = 0; i < hex->nrecord; i++) {
record = hex->records[i];
@@ -451,6 +451,31 @@ ao_hex_image_free(struct ao_hex_image *image)
free(image);
}
+uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
+uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
+
+struct ao_hex_image *
+ao_hex_image_cat(struct ao_hex_image *a, struct ao_hex_image *b)
+{
+ struct ao_hex_image *n;
+ uint32_t base, bound;
+ uint32_t length;
+
+ base = min(a->address, b->address);
+ bound = max(a->address + a->length, b->address + b->length);
+ length = bound - base;
+
+ n = calloc (sizeof (struct ao_hex_image) + length, 1);
+ if (!n)
+ return NULL;
+ n->address = base;
+ n->length = length;
+ memset(n->data, 0xff, length);
+ memcpy(n->data + a->address - n->address, a->data, a->length);
+ memcpy(n->data + b->address - n->address, b->data, b->length);
+ return n;
+}
+
int
ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b)
{
@@ -471,7 +496,7 @@ ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbolsp)
file = fopen (filename, "r");
if (!file)
return NULL;
-
+
hex_file = ao_hex_file_read(file, filename);
fclose(file);
if (!hex_file)
@@ -549,7 +574,7 @@ ao_hex_file_create(struct ao_hex_image *image, struct ao_sym *symbols, int num_s
ao_hex_record_set_checksum(record);
hex_file->records[nrecord++] = record;
-
+
/* Add the symbols
*/
@@ -616,7 +641,7 @@ ao_hex_save(FILE *file, struct ao_hex_image *image,
goto write_failed;
}
ret = true;
-
+
if (fflush(file) != 0)
ret = false;
write_failed:
diff --git a/ao-tools/lib/ao-hex.h b/ao-tools/lib/ao-hex.h
index eb510ba2..a1ab490c 100644
--- a/ao-tools/lib/ao-hex.h
+++ b/ao-tools/lib/ao-hex.h
@@ -71,6 +71,9 @@ ao_hex_image_free(struct ao_hex_image *image);
struct ao_hex_image *
ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbols);
+struct ao_hex_image *
+ao_hex_image_cat(struct ao_hex_image *a, struct ao_hex_image *b);
+
int
ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b);