diff options
Diffstat (limited to 'ao-tools/lib')
-rw-r--r-- | ao-tools/lib/Makefile.am | 2 | ||||
-rw-r--r-- | ao-tools/lib/ao-dfu.c | 202 | ||||
-rw-r--r-- | ao-tools/lib/ao-dfu.h | 35 | ||||
-rw-r--r-- | ao-tools/lib/ao-elf.c | 6 | ||||
-rw-r--r-- | ao-tools/lib/ao-hex.c | 33 | ||||
-rw-r--r-- | ao-tools/lib/ao-hex.h | 3 |
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); |