1/* 2 * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 as published 6 * by the Free Software Foundation. 7 * 8 */ 9#include <stdio.h> 10#include <stdlib.h> 11#include <stdint.h> 12#include <string.h> 13#include <unistd.h> /* for unlink() */ 14#include <libgen.h> 15#include <getopt.h> /* for getopt() */ 16#include <stdarg.h> 17#include <errno.h> 18#include <sys/stat.h> 19 20#include "cyg_crc.h" 21 22#include <arpa/inet.h> 23#include <netinet/in.h> 24 25#define IH_MAGIC 0x27051956 /* Image Magic Number */ 26#define IH_NMLEN 32 /* Image Name Length */ 27 28#define UM_MAGIC 0x55525F46 29#define UM_HEADER_LEN 12 30 31/* 32 * all data in network byte order (aka natural aka bigendian) 33 */ 34struct u_media_header { 35 uint32_t ih_magic; /* Image Header Magic Number */ 36 uint32_t ih_hcrc; /* Image Header CRC Checksum */ 37 uint32_t ih_time; /* Image Creation Timestamp */ 38 uint32_t ih_size; /* Image Data Size */ 39 uint32_t ih_load; /* Data Load Address */ 40 uint32_t ih_ep; /* Entry Point Address */ 41 uint32_t ih_dcrc; /* Image Data CRC Checksum */ 42 uint8_t ih_os; /* Operating System */ 43 uint8_t ih_arch; /* CPU architecture */ 44 uint8_t ih_type; /* Image Type */ 45 uint8_t ih_comp; /* Compression Type */ 46 uint8_t ih_name[IH_NMLEN - UM_HEADER_LEN]; /* Image Name */ 47 48 uint32_t ih_UMedia_magic; /* U-Media magic number */ 49 uint32_t ih_UMedia_boardID; /* U-Media board ID */ 50 uint8_t ih_UMedia_imageType; /* U-Media image type */ 51 uint8_t ih_UMedia_LoadDefault; /* U-Media load to factory default setting */ 52 uint8_t ih_UMedia_temp1; /* U-Media didn't use this tag */ 53 uint8_t ih_UMedia_temp2; /* U-Media didn't use this tag */ 54} __attribute__ ((packed)); 55 56struct if_info { 57 char *file_name; /* name of the file */ 58 uint32_t file_size; /* length of the file */ 59}; 60 61static char *progname; 62static char *ofname; 63static struct if_info if_info; 64static int factory_defaults; 65static uint32_t board_id; 66static uint8_t image_type; 67 68/* 69 * Message macros 70 */ 71#define ERR(fmt, ...) do { \ 72 fflush(0); \ 73 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 74 progname, ## __VA_ARGS__ ); \ 75} while (0) 76 77#define ERRS(fmt, ...) do { \ 78 int save = errno; \ 79 fflush(0); \ 80 fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \ 81 progname, ## __VA_ARGS__, strerror(save)); \ 82} while (0) 83 84#define DBG(fmt, ...) do { \ 85 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \ 86} while (0) 87 88static void usage(int status) 89{ 90 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 91 92 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 93 fprintf(stream, 94"\n" 95"Options:\n" 96" -B <board_id> set board ID to <board_id>\n" 97" -i <file> read input from the file <file>\n" 98" -F load factory defaults\n" 99" -o <file> write output to the file <file>\n" 100" -T <type> set image type to <type>\n" 101" -h show this screen\n" 102 ); 103 104 exit(status); 105} 106 107static int str2u32(char *arg, uint32_t *val) 108{ 109 char *err = NULL; 110 uint32_t t; 111 112 errno=0; 113 t = strtoul(arg, &err, 0); 114 if (errno || (err==arg) || ((err != NULL) && *err)) { 115 return -1; 116 } 117 118 *val = t; 119 return 0; 120} 121 122static int str2u8(char *arg, uint8_t *val) 123{ 124 char *err = NULL; 125 uint32_t t; 126 127 errno=0; 128 t = strtoul(arg, &err, 0); 129 if (errno || (err==arg) || ((err != NULL) && *err)) { 130 return -1; 131 } 132 133 if (t > 255) 134 return -1; 135 136 *val = t; 137 return 0; 138} 139 140static int get_file_stat(struct if_info *fdata) 141{ 142 struct stat st; 143 int res; 144 145 if (fdata->file_name == NULL) 146 return 0; 147 148 res = stat(fdata->file_name, &st); 149 if (res){ 150 ERRS("stat failed on %s", fdata->file_name); 151 return res; 152 } 153 154 fdata->file_size = st.st_size; 155 return 0; 156} 157 158static int read_to_buf(struct if_info *fdata, char *buf) 159{ 160 FILE *f; 161 int ret = EXIT_FAILURE; 162 163 f = fopen(fdata->file_name, "r"); 164 if (f == NULL) { 165 ERRS("could not open \"%s\" for reading", fdata->file_name); 166 goto out; 167 } 168 169 errno = 0; 170 fread(buf, fdata->file_size, 1, f); 171 if (errno != 0) { 172 ERRS("unable to read from file \"%s\"", fdata->file_name); 173 goto out_close; 174 } 175 176 ret = EXIT_SUCCESS; 177 178out_close: 179 fclose(f); 180out: 181 return ret; 182} 183 184static int check_options(void) 185{ 186 int ret; 187 188 if (ofname == NULL) { 189 ERR("no %s specified", "output file"); 190 return -1; 191 } 192 193 if (if_info.file_name == NULL) { 194 ERR("no %s specified", "input file"); 195 return -1; 196 } 197 198 ret = get_file_stat(&if_info); 199 if (ret) 200 return ret; 201 202 return 0; 203} 204 205static int write_fw(char *data, int len) 206{ 207 FILE *f; 208 int ret = EXIT_FAILURE; 209 210 f = fopen(ofname, "w"); 211 if (f == NULL) { 212 ERRS("could not open \"%s\" for writing", ofname); 213 goto out; 214 } 215 216 errno = 0; 217 fwrite(data, len, 1, f); 218 if (errno) { 219 ERRS("unable to write output file"); 220 goto out_flush; 221 } 222 223 ret = EXIT_SUCCESS; 224 225out_flush: 226 fflush(f); 227 fclose(f); 228 if (ret != EXIT_SUCCESS) { 229 unlink(ofname); 230 } 231out: 232 return ret; 233} 234 235static int fix_header(void) 236{ 237 int buflen; 238 char *buf; 239 uint32_t crc, crc_orig; 240 struct u_media_header *hdr; 241 int ret = EXIT_FAILURE; 242 243 buflen = if_info.file_size; 244 if (buflen < sizeof(*hdr)) { 245 ERR("invalid input file\n"); 246 return ret; 247 } 248 249 buf = malloc(buflen); 250 if (!buf) { 251 ERR("no memory for buffer\n"); 252 goto out; 253 } 254 255 ret = read_to_buf(&if_info, buf); 256 if (ret) 257 goto out_free_buf; 258 259 hdr = (struct u_media_header *) buf; 260 if (ntohl(hdr->ih_magic) != IH_MAGIC) { 261 ERR("invalid input file, bad magic\n"); 262 goto out_free_buf; 263 } 264 265 /* verify header CRC */ 266 crc_orig = ntohl(hdr->ih_hcrc); 267 hdr->ih_hcrc = 0; 268 crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr)); 269 if (crc != crc_orig) { 270 ERR("invalid input file, bad header CRC\n"); 271 goto out_free_buf; 272 } 273 274 hdr->ih_name[IH_NMLEN - UM_HEADER_LEN - 1] = '\0'; 275 276 /* set U-Media specific fields */ 277 hdr->ih_UMedia_magic = htonl(UM_MAGIC); 278 hdr->ih_UMedia_boardID = htonl(board_id); 279 hdr->ih_UMedia_imageType = image_type; 280 hdr->ih_UMedia_LoadDefault = (factory_defaults) ? 1 : 0; 281 282 /* update header CRC */ 283 crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr)); 284 hdr->ih_hcrc = htonl(crc); 285 286 ret = write_fw(buf, buflen); 287 if (ret) 288 goto out_free_buf; 289 290 DBG("U-Media header fixed in \"%s\"", ofname); 291 292 ret = EXIT_SUCCESS; 293 294out_free_buf: 295 free(buf); 296out: 297 return ret; 298} 299 300int main(int argc, char *argv[]) 301{ 302 int ret = EXIT_FAILURE; 303 304 progname = basename(argv[0]); 305 306 while (1) { 307 int c; 308 309 c = getopt(argc, argv, "B:Fi:o:T:h"); 310 if (c == -1) 311 break; 312 313 switch (c) { 314 case 'B': 315 if (str2u32(optarg, &board_id)) { 316 ERR("%s is invalid '%s'", 317 "board ID", optarg); 318 goto out; 319 } 320 break; 321 case 'T': 322 if (str2u8(optarg, &image_type)) { 323 ERR("%s is invalid '%s'", 324 "image type", optarg); 325 goto out; 326 } 327 break; 328 case 'F': 329 factory_defaults = 1; 330 break; 331 case 'i': 332 if_info.file_name = optarg; 333 break; 334 case 'o': 335 ofname = optarg; 336 break; 337 case 'h': 338 usage(EXIT_SUCCESS); 339 break; 340 default: 341 usage(EXIT_FAILURE); 342 break; 343 } 344 } 345 346 ret = check_options(); 347 if (ret) 348 goto out; 349 350 ret = fix_header(); 351 352out: 353 return ret; 354} 355