1/* 2 * Copyright (C) 2010 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 10#include <stdio.h> 11#include <stdlib.h> 12#include <stdint.h> 13#include <string.h> 14#include <unistd.h> /* for unlink() */ 15#include <libgen.h> 16#include <getopt.h> /* for getopt() */ 17#include <stdarg.h> 18#include <errno.h> 19#include <sys/stat.h> 20 21#include "cyg_crc.h" 22 23#if (__BYTE_ORDER == __BIG_ENDIAN) 24# define HOST_TO_BE32(x) (x) 25# define BE32_TO_HOST(x) (x) 26# define HOST_TO_LE32(x) bswap_32(x) 27# define LE32_TO_HOST(x) bswap_32(x) 28#else 29# define HOST_TO_BE32(x) bswap_32(x) 30# define BE32_TO_HOST(x) bswap_32(x) 31# define HOST_TO_LE32(x) (x) 32# define LE32_TO_HOST(x) (x) 33#endif 34 35#define MAGIC_FIRMWARE 0x6d726966 /* 'firm' */ 36#define MAGIC_KERNEL 0x676d694b /* 'Kimg' */ 37#define MAGIC_ROOTFS 0x676d6952 /* 'Rimg' */ 38 39struct file_info { 40 char *file_name; /* name of the file */ 41 uint32_t file_size; /* length of the file */ 42}; 43 44struct fw_header { 45 uint32_t magic; 46 uint32_t length; 47 uint32_t unk1; 48 uint32_t unk2; 49} __attribute__ ((packed)); 50 51struct fw_tail { 52 uint32_t hw_id; 53 uint32_t crc; 54} __attribute__ ((packed)); 55 56struct board_info { 57 char *id; 58 uint32_t hw_id; 59 uint32_t kernel_len; 60 uint32_t rootfs_len; 61}; 62 63/* 64 * Globals 65 */ 66static char *ofname; 67static char *progname; 68 69static char *board_id; 70static struct board_info *board; 71static struct file_info kernel_info; 72static struct file_info rootfs_info; 73 74 75static struct board_info boards[] = { 76 { 77 .id = "ZCN-1523H-2-8", 78 .hw_id = 0x66661523, 79 .kernel_len = 0x170000, 80 .rootfs_len = 0x610000, 81 }, { 82 .id = "ZCN-1523H-5-16", 83 .hw_id = 0x6615235A, 84 .kernel_len = 0x170000, 85 .rootfs_len = 0x610000, 86 }, { 87 /* terminating entry */ 88 } 89}; 90 91/* 92 * Message macros 93 */ 94#define ERR(fmt, ...) do { \ 95 fflush(0); \ 96 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 97 progname, ## __VA_ARGS__ ); \ 98} while (0) 99 100#define ERRS(fmt, ...) do { \ 101 int save = errno; \ 102 fflush(0); \ 103 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 104 progname, ## __VA_ARGS__, strerror(save)); \ 105} while (0) 106 107#define DBG(fmt, ...) do { \ 108 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \ 109} while (0) 110 111static struct board_info *find_board(char *id) 112{ 113 struct board_info *ret; 114 struct board_info *board; 115 116 ret = NULL; 117 for (board = boards; board->id != NULL; board++){ 118 if (strcasecmp(id, board->id) == 0) { 119 ret = board; 120 break; 121 } 122 }; 123 124 return ret; 125} 126 127static void usage(int status) 128{ 129 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 130 struct board_info *board; 131 132 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 133 fprintf(stream, 134"\n" 135"Options:\n" 136" -B <board> create image for the board specified with <board>\n" 137" -k <file> read kernel image from the file <file>\n" 138" -r <file> read rootfs image from the file <file>\n" 139" -o <file> write output to the file <file>\n" 140" -h show this screen\n" 141 ); 142 143 exit(status); 144} 145 146static int get_file_stat(struct file_info *fdata) 147{ 148 struct stat st; 149 int res; 150 151 if (fdata->file_name == NULL) 152 return 0; 153 154 res = stat(fdata->file_name, &st); 155 if (res){ 156 ERRS("stat failed on %s", fdata->file_name); 157 return res; 158 } 159 160 fdata->file_size = st.st_size; 161 return 0; 162} 163 164static int read_to_buf(struct file_info *fdata, char *buf) 165{ 166 FILE *f; 167 int ret = EXIT_FAILURE; 168 169 f = fopen(fdata->file_name, "r"); 170 if (f == NULL) { 171 ERRS("could not open \"%s\" for reading", fdata->file_name); 172 goto out; 173 } 174 175 errno = 0; 176 fread(buf, fdata->file_size, 1, f); 177 if (errno != 0) { 178 ERRS("unable to read from file \"%s\"", fdata->file_name); 179 goto out_close; 180 } 181 182 ret = EXIT_SUCCESS; 183 184 out_close: 185 fclose(f); 186 out: 187 return ret; 188} 189 190static int check_options(void) 191{ 192 int ret; 193 194 if (board_id == NULL) { 195 ERR("no board specified"); 196 return -1; 197 } 198 199 board = find_board(board_id); 200 if (board == NULL) { 201 ERR("unknown/unsupported board id \"%s\"", board_id); 202 return -1; 203 } 204 205 if (kernel_info.file_name == NULL) { 206 ERR("no kernel image specified"); 207 return -1; 208 } 209 210 ret = get_file_stat(&kernel_info); 211 if (ret) 212 return ret; 213 214 if (kernel_info.file_size > board->kernel_len) { 215 ERR("kernel image is too big"); 216 return -1; 217 } 218 219 if (rootfs_info.file_name == NULL) { 220 ERR("no rootfs image specified"); 221 return -1; 222 } 223 224 ret = get_file_stat(&rootfs_info); 225 if (ret) 226 return ret; 227 228 if (rootfs_info.file_size > board->rootfs_len) { 229 ERR("rootfs image is too big"); 230 return -1; 231 } 232 233 if (ofname == NULL) { 234 ERR("no output file specified"); 235 return -1; 236 } 237 238 return 0; 239} 240 241static int write_fw(char *data, int len) 242{ 243 FILE *f; 244 int ret = EXIT_FAILURE; 245 246 f = fopen(ofname, "w"); 247 if (f == NULL) { 248 ERRS("could not open \"%s\" for writing", ofname); 249 goto out; 250 } 251 252 errno = 0; 253 fwrite(data, len, 1, f); 254 if (errno) { 255 ERRS("unable to write output file"); 256 goto out_flush; 257 } 258 259 DBG("firmware file \"%s\" completed", ofname); 260 261 ret = EXIT_SUCCESS; 262 263 out_flush: 264 fflush(f); 265 fclose(f); 266 if (ret != EXIT_SUCCESS) { 267 unlink(ofname); 268 } 269 out: 270 return ret; 271} 272 273static int build_fw(void) 274{ 275 int buflen; 276 char *buf; 277 char *p; 278 int ret = EXIT_FAILURE; 279 int writelen = 0; 280 uint32_t crc; 281 struct fw_header *hdr; 282 struct fw_tail *tail; 283 284 buflen = 3 * sizeof(struct fw_header) + 285 kernel_info.file_size + rootfs_info.file_size + 286 3 * sizeof(struct fw_tail); 287 288 buf = malloc(buflen); 289 if (!buf) { 290 ERR("no memory for buffer\n"); 291 goto out; 292 } 293 294 p = buf; 295 memset(p, 0, buflen); 296 297 /* fill firmware header */ 298 hdr = (struct fw_header *) p; 299 hdr->magic = HOST_TO_LE32(MAGIC_FIRMWARE); 300 hdr->length = HOST_TO_LE32(buflen - sizeof(struct fw_header)); 301 p += sizeof(struct fw_header); 302 303 /* fill kernel block header */ 304 hdr = (struct fw_header *) p; 305 hdr->magic = HOST_TO_LE32(MAGIC_KERNEL); 306 hdr->length = HOST_TO_LE32(kernel_info.file_size + 307 sizeof(struct fw_tail)); 308 p += sizeof(struct fw_header); 309 310 /* read kernel data */ 311 ret = read_to_buf(&kernel_info, p); 312 if (ret) 313 goto out_free_buf; 314 315 /* fill firmware tail */ 316 tail = (struct fw_tail *) (p + kernel_info.file_size); 317 tail->hw_id = HOST_TO_BE32(board->hw_id); 318 tail->crc = HOST_TO_BE32(cyg_crc32(p, kernel_info.file_size + 319 sizeof(struct fw_tail) - 4)); 320 321 p += kernel_info.file_size + sizeof(struct fw_tail); 322 323 /* fill rootfs block header */ 324 hdr = (struct fw_header *) p; 325 hdr->magic = HOST_TO_LE32(MAGIC_ROOTFS); 326 hdr->length = HOST_TO_LE32(rootfs_info.file_size + 327 sizeof(struct fw_tail)); 328 p += sizeof(struct fw_header); 329 330 /* read rootfs data */ 331 ret = read_to_buf(&rootfs_info, p); 332 if (ret) 333 goto out_free_buf; 334 335 /* fill firmware tail */ 336 tail = (struct fw_tail *) (p + rootfs_info.file_size); 337 tail->hw_id = HOST_TO_BE32(board->hw_id); 338 tail->crc = HOST_TO_BE32(cyg_crc32(p, rootfs_info.file_size + 339 sizeof(struct fw_tail) - 4)); 340 341 p += rootfs_info.file_size + sizeof(struct fw_tail); 342 343 /* fill firmware tail */ 344 tail = (struct fw_tail *) p; 345 tail->hw_id = HOST_TO_BE32(board->hw_id); 346 tail->crc = HOST_TO_BE32(cyg_crc32(buf + sizeof(struct fw_header), 347 buflen - sizeof(struct fw_header) - 4)); 348 349 ret = write_fw(buf, buflen); 350 if (ret) 351 goto out_free_buf; 352 353 ret = EXIT_SUCCESS; 354 355 out_free_buf: 356 free(buf); 357 out: 358 return ret; 359} 360 361int main(int argc, char *argv[]) 362{ 363 int ret = EXIT_FAILURE; 364 int err; 365 366 FILE *outfile; 367 368 progname = basename(argv[0]); 369 370 while ( 1 ) { 371 int c; 372 373 c = getopt(argc, argv, "B:k:r:o:h"); 374 if (c == -1) 375 break; 376 377 switch (c) { 378 case 'B': 379 board_id = optarg; 380 break; 381 case 'k': 382 kernel_info.file_name = optarg; 383 break; 384 case 'r': 385 rootfs_info.file_name = optarg; 386 break; 387 case 'o': 388 ofname = optarg; 389 break; 390 case 'h': 391 usage(EXIT_SUCCESS); 392 break; 393 default: 394 usage(EXIT_FAILURE); 395 break; 396 } 397 } 398 399 ret = check_options(); 400 if (ret) 401 goto out; 402 403 ret = build_fw(); 404 405 out: 406 return ret; 407} 408 409