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