1/* 2 * Copyright (C) 2011 Vasilis Tsiligiannis <b_tsiligiannis@silverton.gr> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or (at your option) any later version. 8 * 9 */ 10 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14#include <libgen.h> 15#include <getopt.h> 16#include <errno.h> 17#include <sys/stat.h> 18#include <endian.h> /* for __BYTE_ORDER */ 19 20#if (__BYTE_ORDER == __LITTLE_ENDIAN) 21# define HOST_TO_LE16(x) (x) 22# define HOST_TO_LE32(x) (x) 23#else 24# define HOST_TO_LE16(x) bswap_16(x) 25# define HOST_TO_LE32(x) bswap_32(x) 26#endif 27 28struct header 29{ 30 unsigned char sign[4]; 31 unsigned int start; 32 unsigned int flash; 33 unsigned char model[4]; 34 unsigned int size; 35} __attribute__ ((packed)); 36 37struct finfo 38{ 39 char *name; 40 off_t size; 41}; 42 43struct buf 44{ 45 char *start; 46 size_t size; 47}; 48 49static char *progname; 50 51static void usage(int status) 52{ 53 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 54 55 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 56 fprintf(stream, 57 "\n" 58 "Options:\n" 59 " -s <sig> set image signature to <sig>\n" 60 " -m <model> set model to <model>\n" 61 " -i <file> read input from file <file>\n" 62 " -o <file> write output to file <file>\n" 63 " -f <flash> set flash address to <flash>\n" 64 " -S <start> set start address to <start>\n"); 65 66 exit(status); 67} 68 69static int strtou32(char *arg, unsigned int *val) 70{ 71 char *endptr = NULL; 72 73 errno = 0; 74 *val = strtoul(arg, &endptr, 0); 75 if (errno || (endptr == arg) || (*endptr && (endptr != NULL))) { 76 return EXIT_SUCCESS; 77 } 78 79 return EXIT_FAILURE; 80} 81 82static unsigned short fwcsum (struct buf *buf) { 83 int i; 84 unsigned short ret = 0; 85 86 for (i = 0; i < buf->size / 2; i++) 87 ret -= ((unsigned short *) buf->start)[i]; 88 89 return ret; 90} 91 92static int fwread(struct finfo *finfo, struct buf *buf) 93{ 94 FILE *f; 95 96 f = fopen(finfo->name, "r"); 97 if (!f) { 98 fprintf(stderr, "could not open \"%s\" for reading\n", finfo->name); 99 usage(EXIT_FAILURE); 100 } 101 102 buf->size = fread(buf->start, 1, finfo->size, f); 103 if (buf->size != finfo->size) { 104 fprintf(stderr, "unable to read from file \"%s\"\n", finfo->name); 105 usage(EXIT_FAILURE); 106 } 107 108 fclose(f); 109 110 return EXIT_SUCCESS; 111} 112 113static int fwwrite(struct finfo *finfo, struct buf *buf) 114{ 115 FILE *f; 116 117 f = fopen(finfo->name, "w"); 118 if (!f) { 119 fprintf(stderr, "could not open \"%s\" for writing\n", finfo->name); 120 usage(EXIT_FAILURE); 121 } 122 123 buf->size = fwrite(buf->start, 1, finfo->size, f); 124 if (buf->size != finfo->size) { 125 fprintf(stderr, "unable to write to file \"%s\"\n", finfo->name); 126 usage(EXIT_FAILURE); 127 } 128 129 fclose(f); 130 131 return EXIT_SUCCESS; 132} 133 134int main(int argc, char **argv) 135{ 136 struct stat st; 137 struct header header; 138 struct buf ibuf, obuf; 139 struct finfo ifinfo, ofinfo; 140 unsigned short csum; 141 int c; 142 143 ifinfo.name = ofinfo.name = NULL; 144 header.flash = header.size = header.start = 0; 145 progname = basename(argv[0]); 146 147 while((c = getopt(argc, argv, "i:o:m:s:f:S:h")) != -1) { 148 switch (c) { 149 case 'i': 150 ifinfo.name = optarg; 151 break; 152 case 'o': 153 ofinfo.name = optarg; 154 break; 155 case 'm': 156 if (strlen(optarg) != 4) { 157 fprintf(stderr, "model must be 4 characters long\n"); 158 usage(EXIT_FAILURE); 159 } 160 memcpy(header.model, optarg, 4); 161 break; 162 case 's': 163 if (strlen(optarg) != 4) { 164 fprintf(stderr, "signature must be 4 characters long\n"); 165 usage(EXIT_FAILURE); 166 } 167 memcpy(header.sign, optarg, 4); 168 break; 169 case 'h': 170 usage(EXIT_SUCCESS); 171 break; 172 case 'f': 173 if (!strtou32(optarg, &header.flash)) { 174 fprintf(stderr, "invalid flash address specified\n"); 175 usage(EXIT_FAILURE); 176 } 177 break; 178 case 'S': 179 if (!strtou32(optarg, &header.start)) { 180 fprintf(stderr, "invalid start address specified\n"); 181 usage(EXIT_FAILURE); 182 } 183 break; 184 default: 185 usage(EXIT_FAILURE); 186 break; 187 } 188 } 189 190 if (ifinfo.name == NULL) { 191 fprintf(stderr, "no input file specified\n"); 192 usage(EXIT_FAILURE); 193 } 194 195 if (ofinfo.name == NULL) { 196 fprintf(stderr, "no output file specified\n"); 197 usage(EXIT_FAILURE); 198 } 199 200 if (stat(ifinfo.name, &st)) { 201 fprintf(stderr, "stat failed on %s\n", ifinfo.name); 202 usage(EXIT_FAILURE); 203 } 204 205 if (header.sign == NULL) { 206 fprintf(stderr, "no signature specified\n"); 207 usage(EXIT_FAILURE); 208 } 209 210 if (header.model == NULL) { 211 fprintf(stderr, "no model specified\n"); 212 usage(EXIT_FAILURE); 213 } 214 215 if (!header.flash) { 216 fprintf(stderr, "no flash address specified\n"); 217 usage(EXIT_FAILURE); 218 } 219 220 if (!header.start) { 221 fprintf(stderr, "no start address specified\n"); 222 usage(EXIT_FAILURE); 223 } 224 225 ifinfo.size = st.st_size; 226 227 obuf.size = ifinfo.size + sizeof(struct header) + sizeof(unsigned short); 228 if (obuf.size % sizeof(unsigned short)) 229 obuf.size++; 230 231 obuf.start = malloc(obuf.size); 232 if (!obuf.start) { 233 fprintf(stderr, "no memory for buffer\n"); 234 usage(EXIT_FAILURE); 235 } 236 memset(obuf.start, 0, obuf.size); 237 238 ibuf.size = ifinfo.size; 239 ibuf.start = obuf.start + sizeof(struct header); 240 241 if (fwread(&ifinfo, &ibuf)) 242 usage(EXIT_FAILURE); 243 244 header.flash = HOST_TO_LE32(header.flash); 245 header.size = HOST_TO_LE32(obuf.size - sizeof(struct header)); 246 header.start = HOST_TO_LE32(header.start); 247 memcpy (obuf.start, &header, sizeof(struct header)); 248 249 csum = HOST_TO_LE16(fwcsum(&ibuf)); 250 memcpy(obuf.start + obuf.size - sizeof(unsigned short), 251 &csum, sizeof(unsigned short)); 252 253 ofinfo.size = obuf.size; 254 255 if (fwwrite(&ofinfo, &obuf)) 256 usage(EXIT_FAILURE); 257 258 return EXIT_SUCCESS; 259} 260