Here is another try with fixes Tormod earlier suggested plus a change that make Stellaris prefix extension happen with different options between adding (-s address) and deleting (-T).
>From c97fa17e41aa3de0e9cfed27e41176c030066b23 Mon Sep 17 00:00:00 2001 From: Tommi Keisala <tommi.keis...@ray.fi> Date: Tue, 10 Jul 2012 12:42:04 +0300 Subject: [PATCH] add, remove and check TI Stellaris DFU prefix
Patch adds functionality to add, remove and check TI Stellaris DFU prefix with dfu-suffix tool. TI Stellaris bootloader expects to have 8 byte prefix in the beginning of binary image. Patch adds option -s --stellaris to dfu-suffix to add that prefix (with -a). When adding (-a) prefix (and suffix) option -s requires address as an argument. To delete prefix use -D and -T option. If -D is used to Stellaris prefixed file only suffix gets removed. Use -D again with -T option to delete prefix. To check for TI Stellaris prefix use -c with -T option. To add DFU suffix and prefix use: dfu-suffix -s 0x2000 -v 0x1cbe -p 0x00ff -d 0x0000 -a image.bin To remove DFU suffix and prefix use: dfu-suffix -T -D image.bin To check DFU suffix use: dfu-suffix -T -c image.bin Signed-off-by: Tommi Keisala <tommi.keis...@ray.fi> --- src/Makefile.am | 4 +- src/lmdfu.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lmdfu.h | 30 +++++++++ src/suffix.c | 96 +++++++++++++++++++++++----- 4 files changed, 296 insertions(+), 19 deletions(-) create mode 100644 src/lmdfu.c create mode 100644 src/lmdfu.h diff --git a/src/Makefile.am b/src/Makefile.am index df2ef36..99df307 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,4 +19,6 @@ dfu_util_SOURCES = main.c \ dfu_suffix_SOURCES = suffix.c \ dfu_file.h \ - dfu_file.c + dfu_file.c \ + lmdfu.c \ + lmdfu.h diff --git a/src/lmdfu.c b/src/lmdfu.c new file mode 100644 index 0000000..0989056 --- /dev/null +++ b/src/lmdfu.c @@ -0,0 +1,185 @@ +/* This implements the TI Stellaris DFU + * as per the Application Update Using the USB Device Firmware Upgrade Class + * (Document AN012373) + * http://www.ti.com/general/docs/lit/getliterature.tsp?literatureNumber=spma003&fileType=pdf + * + * Copyright 2012 Tommi Keisala <tommi.keis...@ray.fi> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "portable.h" +#include "dfu.h" +#include "dfu_file.h" +#include "quirks.h" + +/* lmdfu_dfu_prefix payload length excludes prefix and suffix */ +unsigned char lmdfu_dfu_prefix[] = { + 0x01, /* STELLARIS_DFU_PROG */ + 0x00, /* Reserved */ + 0x00, /* LSB start address / 1024 */ + 0x20, /* MSB start address / 1024 */ + 0x00, /* LSB file payload length */ + 0x00, /* Byte 2 file payload length */ + 0x00, /* Byte 3 file payload length */ + 0x00, /* MSB file payload length */ +}; + +int lmdfu_add_prefix(struct dfu_file file, unsigned int address) +{ + int ret; + uint16_t addr; + uint32_t len; + + unsigned char *data = NULL; + + fseek(file.filep, 0, SEEK_END); + len = ftell(file.filep); + rewind(file.filep); + + data = (unsigned char *)malloc(len); + if (!data) { + fprintf(stderr, "Unable to allocate buffer.\n"); + exit(1); + } + + ret = fread(data, 1, len, file.filep); + if (ret < 0) { + fprintf(stderr, "Could not read file\n"); + perror(file.name); + free(data); + return ret; + } else if (ret < len) { + fprintf(stderr, "Could not read whole file\n"); + free(data); + return -EIO; + } + + /* fill Stellaris lmdfu_dfu_prefix with correct data */ + addr = address / 1024; + lmdfu_dfu_prefix[2] = (unsigned char)addr & 0xff; + lmdfu_dfu_prefix[3] = (unsigned char)addr >> 8; + lmdfu_dfu_prefix[4] = (unsigned char)len & 0xff; + lmdfu_dfu_prefix[5] = (unsigned char)(len >> 8) & 0xff; + lmdfu_dfu_prefix[6] = (unsigned char)(len >> 16) & 0xff; + lmdfu_dfu_prefix[7] = (unsigned char)(len) >> 24; + + rewind(file.filep); + ret = fwrite(lmdfu_dfu_prefix, 1, sizeof(lmdfu_dfu_prefix), file.filep); + if (ret < 0) { + fprintf(stderr, "Could not write TI Stellaris DFU prefix\n"); + perror(file.name); + } else if (ret < sizeof(lmdfu_dfu_prefix)) { + fprintf(stderr, "Could not write while file\n"); + ret = -EIO; + } + + ret = fwrite(data, 1, len, file.filep); + if (ret < 0) { + fprintf(stderr, "Could not write data after TI Stellaris DFU " + "prefix\n"); + perror(file.name); + } else if (ret < sizeof(lmdfu_dfu_prefix)) { + fprintf(stderr, "Could not write whole file\n"); + ret = -EIO; + } + + rewind(file.filep); + printf("TI Stellaris DFU prefix added.\n"); + return 0; +} + +int lmdfu_remove_prefix(struct dfu_file *file) +{ + long len; + unsigned char *data; + int ret; + +#ifdef HAVE_FTRUNCATE + printf("Remove TI Stellaris prefix\n"); + + fseek(file->filep, 0, SEEK_END); + len = ftell(file->filep); + rewind(file->filep); + + data = (unsigned char *)malloc(len); + if (!data) { + fprintf(stderr, "Unable to allocate buffer.\n"); + exit(1); + } + + ret = fread(data, 1, len, file->filep); + if (ret < 0) { + fprintf(stderr, "Could not read file\n"); + perror(file->name); + free(data); + return ret; + } else if (ret < len) { + fprintf(stderr, "Could not read whole file\n"); + free(data); + return -EIO; + } + + ret = ftruncate(fileno(file->filep), 0); + if (ret < 0) { + fprintf(stderr, "Error truncating\n"); + } + rewind(file->filep); + + fwrite(data + sizeof(lmdfu_dfu_prefix), 1, len - sizeof(lmdfu_dfu_prefix), + file->filep); + + printf("TI Stellaris prefix removed\n"); +#else + printf("Prefix removal not implemented on this platform\n"); +#endif /* HAVE_FTRUNCATE */ + + return ret; +} + +int lmdfu_check_prefix(struct dfu_file *file) +{ + unsigned char *data; + int ret; + + data = malloc(sizeof(lmdfu_dfu_prefix)); + + ret = fread(data, 1, sizeof(lmdfu_dfu_prefix), file->filep); + if (ret < sizeof(lmdfu_dfu_prefix)) { + fprintf(stderr, "Could not read prefix\n"); + perror(file->name); + } + + if ((data[0] != 0x01) && (data[1] != 0x00)) { + printf("Not valid TI Stellaris DFU prefix\n"); + ret = 0; + goto out_rewind; + } else { + printf + ("Possible TI Stellaris DFU prefix with the following properties\n"); + printf("Address: 0x%08x\n", + 1024 * (data[3] << 8 | data[2])); + printf("Payload length: %d\n", + data[4] | data[5] << 8 | data[6] << 16 | data[7] << 14); + } + +out_rewind: + rewind(file->filep); + return ret; +} diff --git a/src/lmdfu.h b/src/lmdfu.h new file mode 100644 index 0000000..8af689f --- /dev/null +++ b/src/lmdfu.h @@ -0,0 +1,30 @@ + +/* This implements the TI Stellaris DFU + * as per the Application Update Using the USB Device Firmware Upgrade Class + * (Document AN012373) + * + * Copyright 2012 Tommi Keisala <tommi.keis...@ray.fi> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 LMDFU_H +#define LMDFU_H + +int lmdfu_add_prefix(struct dfu_file file, unsigned int address); +int lmdfu_remove_prefix(struct dfu_file *file); +int lmdfu_check_prefix(struct dfu_file *file); + +#endif /* LMDFU_H */ diff --git a/src/suffix.c b/src/suffix.c index fe19194..4ebfee7 100644 --- a/src/suffix.c +++ b/src/suffix.c @@ -20,8 +20,10 @@ #include <stdio.h> #include <stdint.h> #include <getopt.h> +#include <string.h> #include "dfu_file.h" +#include "lmdfu.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -36,17 +38,28 @@ enum mode { MODE_CHECK }; +enum lmdfu_mode { + LMDFU_NONE, + LMDFU_ADD, + LMDFU_DEL, + LMDFU_CHECK +}; + static void help(void) { printf("Usage: dfu-suffix [options] <file>\n" - " -h --help\tPrint this help message\n" - " -V --version\tPrint the version number\n" - " -D --delete\tDelete DFU suffix from <file>\n" - " -p --pid\tAdd product ID into DFU suffix in <file>\n" - " -v --vid\tAdd vendor ID into DFU suffix in <file>\n" - " -d --did\tAdd device ID into DFU suffix in <file>\n" - " -c --check\tCheck DFU suffix of <file>\n" - " -a --add\tAdd DFU suffix to <file>\n" + " -h --help\t\t\tPrint this help message\n" + " -V --version\t\t\tPrint the version number\n" + " -D --delete\t\t\tDelete DFU suffix from <file>\n" + " -p --pid\t\t\tAdd product ID into DFU suffix in <file>\n" + " -v --vid\t\t\tAdd vendor ID into DFU suffix in <file>\n" + " -d --did\t\t\tAdd device ID into DFU suffix in <file>\n" + " -c --check\t\t\tCheck DFU suffix of <file>\n" + " -a --add\t\t\tAdd DFU suffix to <file>\n" + " -s --stellaris-add address \tAdd TI Stellaris address " + "prefix to <file>.\n\t\t\t\tUse with -a\n" + " -T --stellaris\t\tTI Stellaris prefix extension from " + "<file>.\n\t\t\t\tUse with -D or -c\n" ); } @@ -67,6 +80,8 @@ static struct option opts[] = { { "did", 1, 0, 'd' }, { "check", 1, 0, 'c' }, { "add", 1, 0, 'a' }, + { "stellaris-add", 1, 0, 's' }, + { "stellaris", 0, 0, 'T' }, }; static int check_suffix(struct dfu_file *file) { @@ -86,13 +101,13 @@ static int check_suffix(struct dfu_file *file) { return ret; } -static void remove_suffix(struct dfu_file *file) +static int remove_suffix(struct dfu_file *file) { int ret; ret = parse_dfu_suffix(file); if (ret <= 0) - exit(1); + return 0; #ifdef HAVE_FTRUNCATE /* There is no easy way to truncate to a size with stdio */ @@ -106,17 +121,12 @@ static void remove_suffix(struct dfu_file *file) #else printf("Suffix removal not implemented on this platform\n"); #endif /* HAVE_FTRUNCATE */ + return 1; } static void add_suffix(struct dfu_file *file, int pid, int vid, int did) { int ret; - ret = check_suffix(file); - if (ret > 0) { - printf("Please remove existing DFU suffix before adding a new one.\n"); - exit(1); - } - file->idProduct = pid; file->idVendor = vid; file->bcdDevice = did; @@ -134,6 +144,10 @@ int main(int argc, char **argv) struct dfu_file file; int pid, vid, did; enum mode mode = MODE_NONE; + enum lmdfu_mode lmdfu_mode = LMDFU_NONE; + unsigned int lmdfu_flash_address=0; + int lmdfu_prefix=0; + char *end; print_version(); @@ -142,7 +156,7 @@ int main(int argc, char **argv) while (1) { int c, option_index = 0; - c = getopt_long(argc, argv, "hVD:p:v:d:c:a:", opts, + c = getopt_long(argc, argv, "hVD:p:v:d:c:a:s:T", opts, &option_index); if (c == -1) break; @@ -176,12 +190,30 @@ int main(int argc, char **argv) file.name = optarg; mode = MODE_ADD; break; + case 's': + lmdfu_mode = LMDFU_ADD; + lmdfu_flash_address = strtoul(optarg, NULL, 0); + if (strcmp(optarg, "default")) { + lmdfu_flash_address = strtoul(optarg, &end, 0); + if (!lmdfu_flash_address || (*end)) { + fprintf(stderr, "Error: Invalid lmdfu " + "address: %s\n", optarg); + exit(2); + } + } + break; + case 'T': + lmdfu_mode = LMDFU_CHECK; + break; default: help(); exit(2); } } + if(mode == MODE_DEL && lmdfu_mode == LMDFU_CHECK) + lmdfu_mode = LMDFU_DEL; + if (!file.name) { fprintf(stderr, "You need to specify a filename\n"); help(); @@ -198,20 +230,48 @@ int main(int argc, char **argv) switch(mode) { case MODE_ADD: + if (check_suffix(&file)) { + if(lmdfu_prefix) lmdfu_check_prefix(&file); + printf("Please remove existing DFU suffix before adding a new one.\n"); + exit(1); + } + if(lmdfu_mode == LMDFU_ADD) { + if(lmdfu_check_prefix(&file)) { + fprintf(stderr, "Adding new anyway\n"); + } + lmdfu_add_prefix(file, lmdfu_flash_address); + } add_suffix(&file, pid, vid, did); break; case MODE_CHECK: /* FIXME: could open read-only here */ check_suffix(&file); + if(lmdfu_mode == LMDFU_CHECK) + lmdfu_check_prefix(&file); break; case MODE_DEL: - remove_suffix(&file); + if(!remove_suffix(&file)) { + if(lmdfu_mode == LMDFU_DEL) + if (lmdfu_check_prefix(&file)) + lmdfu_remove_prefix(&file); + exit(1); + } break; default: help(); exit(2); } + if(lmdfu_mode == LMDFU_DEL) { + if (check_suffix(&file)) { + fprintf(stderr, "DFU suffix exist. Remove suffix before using -T or use it with -D to delete suffix\n"); + exit(1); + } else { + if(lmdfu_check_prefix(&file)) + lmdfu_remove_prefix(&file); + } + } + fclose(file.filep); exit(0); } -- 1.7.0.4
_______________________________________________ devel mailing list devel@lists.openmoko.org https://lists.openmoko.org/mailman/listinfo/devel