1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2007-2008 OpenWrt.org 5 * Copyright (C) 2007-2008 Gabor Juhos <juhosg at openwrt.org> 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <stdint.h> 11 #include <string.h> 12 #include <byteswap.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 #include <endian.h> /* for __BYTE_ORDER */ 20 #if defined(__CYGWIN__) 21 # include <byteswap.h> 22 #endif 23 #include <inttypes.h> 24 25 #include "zynos.h" 26 27 #if (__BYTE_ORDER == __LITTLE_ENDIAN) 28 # define HOST_TO_LE16(x) (x) 29 # define HOST_TO_LE32(x) (x) 30 # define LE16_TO_HOST(x) (x) 31 # define LE32_TO_HOST(x) (x) 32 # define HOST_TO_BE16(x) bswap_16(x) 33 # define HOST_TO_BE32(x) bswap_32(x) 34 # define BE16_TO_HOST(x) bswap_16(x) 35 # define BE32_TO_HOST(x) bswap_32(x) 36 #else 37 # define HOST_TO_BE16(x) (x) 38 # define HOST_TO_BE32(x) (x) 39 # define BE16_TO_HOST(x) (x) 40 # define BE32_TO_HOST(x) (x) 41 # define HOST_TO_LE16(x) bswap_16(x) 42 # define HOST_TO_LE32(x) bswap_32(x) 43 # define LE16_TO_HOST(x) bswap_16(x) 44 # define LE32_TO_HOST(x) bswap_32(x) 45 #endif 46 47 #define ALIGN(x,y) (((x)+((y)-1)) & ~((y)-1)) 48 49 #define MAX_NUM_BLOCKS 8 50 #define MAX_ARG_COUNT 32 51 #define MAX_ARG_LEN 1024 52 #define FILE_BUF_LEN (16*1024) 53 54 55 struct csum_state{ 56 int odd; 57 uint32_t sum; 58 uint32_t tmp; 59 }; 60 61 struct fw_block { 62 uint32_t align; /* alignment of this block */ 63 char *file_name; /* name of the file */ 64 uint32_t file_size; /* length of the file */ 65 char *mmap_name; /* name in the MMAP table */ 66 int type; /* block type */ 67 uint32_t padlen; 68 uint8_t padc; 69 }; 70 71 #define BLOCK_TYPE_BOOTEXT 0 72 #define BLOCK_TYPE_RAW 1 73 74 struct fw_mmap { 75 uint32_t addr; 76 uint32_t size; 77 uint32_t user_addr; 78 uint32_t user_size; 79 }; 80 #define MMAP_DATA_SIZE 1024 81 #define MMAP_ALIGN 16 82 83 struct board_info { 84 char *name; /* model name */ 85 char *desc; /* description */ 86 uint16_t vendor; /* vendor id */ 87 uint16_t model; /* model id */ 88 uint32_t flash_base; /* flash base address */ 89 uint32_t flash_size; /* board flash size */ 90 uint32_t code_start; /* code start address */ 91 uint32_t romio_offs; /* offset of the firmware within the flash */ 92 uint32_t bootext_size; /* maximum size of bootext block */ 93 }; 94 95 /* 96 * Globals 97 */ 98 char *progname; 99 char *ofname = NULL; 100 int verblevel = 0; 101 102 struct board_info *board = NULL; 103 104 struct fw_block blocks[MAX_NUM_BLOCKS]; 105 struct fw_block *bootext_block = NULL; 106 int num_blocks = 0; 107 108 #define ADM5120_FLASH_BASE 0xBFC00000 109 #define ADM5120_CODE_START 0x80008000 110 111 /* TODO: check values for AR7 */ 112 #define AR7_FLASH_BASE 0xB0000000 113 #define AR7_CODE_START 0x94008000 114 115 #define ATHEROS_FLASH_BASE 0xBFC00000 116 #define ATHEROS_CODE_START 0x80e00000 117 118 #define AR71XX_FLASH_BASE 0xBFC00000 119 #define AR71XX_CODE_START 0x81E00000 120 121 #define RTL_OTTO_FLASH_BASE 0xB4000000 122 #define RTL_OTTO_CODE_START 0x80220000 123 #define RTL_OTTO_BOOTEXT_SIZE 0x10000 124 125 #define BOARD(n, d, v, m, fb, fs, cs, fo) { \ 126 .name = (n), .desc=(d), \ 127 .vendor = (v), .model = (m), \ 128 .flash_base = (fb), .flash_size = (fs)<<20, \ 129 .code_start = (cs), .romio_offs = (fo), \ 130 .bootext_size = BOOTEXT_DEF_SIZE \ 131 } 132 133 #define ADMBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \ 134 ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x8000) 135 136 #define ADMBOARD2(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \ 137 ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x10000) 138 139 #define AR7BOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \ 140 AR7_FLASH_BASE, fs, AR7_CODE_START, 0x8000) 141 142 #define ATHEROSBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \ 143 ATHEROS_FLASH_BASE, fs, ATHEROS_CODE_START, 0x30000) 144 145 #define AR71XXBOARD1(n, d, m, fs) { \ 146 .name = (n), .desc=(d), \ 147 .vendor = (ZYNOS_VENDOR_ID_ZYXEL), .model = (m), \ 148 .flash_base = (AR71XX_FLASH_BASE), .flash_size = (fs)<<20, \ 149 .code_start = (AR71XX_CODE_START), .romio_offs = (0x40000), \ 150 .bootext_size = 0x30000 \ 151 } 152 153 #define RTL_OTTO_BOARD(n, d, m, fs, fo) { \ 154 .name = (n), .desc = (d), \ 155 .vendor = (ZYNOS_VENDOR_ID_ZYXEL), .model = (m), \ 156 .flash_base = (RTL_OTTO_FLASH_BASE), .flash_size = (fs)<<20, \ 157 .code_start = (RTL_OTTO_CODE_START), .romio_offs = (fo), \ 158 .bootext_size = (RTL_OTTO_BOOTEXT_SIZE) \ 159 } 160 161 static struct board_info boards[] = { 162 /* 163 * Infineon/ADMtek ADM5120 based boards 164 */ 165 ADMBOARD2("ES-2024A", "ZyXEL ES-2024A", ZYNOS_MODEL_ES_2024A, 4), 166 ADMBOARD2("ES-2024PWR", "ZyXEL ES-2024PWR", ZYNOS_MODEL_ES_2024PWR, 4), 167 ADMBOARD2("ES-2108", "ZyXEL ES-2108", ZYNOS_MODEL_ES_2108, 4), 168 ADMBOARD2("ES-2108-F", "ZyXEL ES-2108-F", ZYNOS_MODEL_ES_2108_F, 4), 169 ADMBOARD2("ES-2108-G", "ZyXEL ES-2108-G", ZYNOS_MODEL_ES_2108_G, 4), 170 ADMBOARD2("ES-2108-LC", "ZyXEL ES-2108-LC", ZYNOS_MODEL_ES_2108_LC, 4), 171 ADMBOARD2("ES-2108PWR", "ZyXEL ES-2108PWR", ZYNOS_MODEL_ES_2108PWR, 4), 172 ADMBOARD1("HS-100", "ZyXEL HomeSafe 100", ZYNOS_MODEL_HS_100, 2), 173 ADMBOARD1("HS-100W", "ZyXEL HomeSafe 100W", ZYNOS_MODEL_HS_100W, 2), 174 ADMBOARD1("P-334", "ZyXEL Prestige 334", ZYNOS_MODEL_P_334, 2), 175 ADMBOARD1("P-334U", "ZyXEL Prestige 334U", ZYNOS_MODEL_P_334U, 4), 176 ADMBOARD1("P-334W", "ZyXEL Prestige 334W", ZYNOS_MODEL_P_334W, 2), 177 ADMBOARD1("P-334WH", "ZyXEL Prestige 334WH", ZYNOS_MODEL_P_334WH, 4), 178 ADMBOARD1("P-334WHD", "ZyXEL Prestige 334WHD", ZYNOS_MODEL_P_334WHD, 4), 179 ADMBOARD1("P-334WT", "ZyXEL Prestige 334WT", ZYNOS_MODEL_P_334WT, 4), 180 ADMBOARD1("P-335", "ZyXEL Prestige 335", ZYNOS_MODEL_P_335, 4), 181 ADMBOARD1("P-335Plus", "ZyXEL Prestige 335Plus", ZYNOS_MODEL_P_335PLUS, 4), 182 ADMBOARD1("P-335U", "ZyXEL Prestige 335U", ZYNOS_MODEL_P_335U, 4), 183 ADMBOARD1("P-335WT", "ZyXEL Prestige 335WT", ZYNOS_MODEL_P_335WT, 4), 184 185 { 186 .name = "P-2602HW-D1A", 187 .desc = "ZyXEL P-2602HW-D1A", 188 .vendor = ZYNOS_VENDOR_ID_ZYXEL, 189 .model = ZYNOS_MODEL_P_2602HW_D1A, 190 .flash_base = AR7_FLASH_BASE, 191 .flash_size = 4*1024*1024, 192 .code_start = 0x94008000, 193 .romio_offs = 0x20000, 194 .bootext_size = BOOTEXT_DEF_SIZE, 195 }, 196 197 #if 0 198 /* 199 * Texas Instruments AR7 based boards 200 */ 201 AR7BOARD1("P-660H-61", "ZyXEL P-660H-61", ZYNOS_MODEL_P_660H_61, 2), 202 AR7BOARD1("P-660H-63", "ZyXEL P-660H-63", ZYNOS_MODEL_P_660H_63, 2), 203 AR7BOARD1("P-660H-D1", "ZyXEL P-660H-D1", ZYNOS_MODEL_P_660H_D1, 2), 204 AR7BOARD1("P-660H-D3", "ZyXEL P-660H-D3", ZYNOS_MODEL_P_660H_D3, 2), 205 AR7BOARD1("P-660HW-61", "ZyXEL P-660HW-61", ZYNOS_MODEL_P_660HW_61, 2), 206 AR7BOARD1("P-660HW-63", "ZyXEL P-660HW-63", ZYNOS_MODEL_P_660HW_63, 2), 207 AR7BOARD1("P-660HW-67", "ZyXEL P-660HW-67", ZYNOS_MODEL_P_660HW_67, 2), 208 AR7BOARD1("P-660HW-D1", "ZyXEL P-660HW-D1", ZYNOS_MODEL_P_660HW_D1, 2), 209 AR7BOARD1("P-660HW-D3", "ZyXEL P-660HW-D3", ZYNOS_MODEL_P_660HW_D3, 2), 210 AR7BOARD1("P-660R-61", "ZyXEL P-660R-61", ZYNOS_MODEL_P_660R_61, 2), 211 AR7BOARD1("P-660R-61C", "ZyXEL P-660R-61C", ZYNOS_MODEL_P_660R_61C, 2), 212 AR7BOARD1("P-660R-63", "ZyXEL P-660R-63", ZYNOS_MODEL_P_660R_63, 2), 213 AR7BOARD1("P-660R-63C", "ZyXEL P-660R-63C", ZYNOS_MODEL_P_660R_63C, 2), 214 AR7BOARD1("P-660R-67", "ZyXEL P-660R-67", ZYNOS_MODEL_P_660R_67, 2), 215 AR7BOARD1("P-660R-D1", "ZyXEL P-660R-D1", ZYNOS_MODEL_P_660R_D1, 2), 216 AR7BOARD1("P-660R-D3", "ZyXEL P-660R-D3", ZYNOS_MODEL_P_660R_D3, 2), 217 #endif 218 { 219 .name = "O2SURF", 220 .desc = "O2 DSL Surf & Phone", 221 .vendor = ZYNOS_VENDOR_ID_O2, 222 .model = ZYNOS_MODEL_O2SURF, 223 .flash_base = AR7_FLASH_BASE, 224 .flash_size = 8*1024*1024, 225 .code_start = 0x94014000, 226 .romio_offs = 0x40000, 227 .bootext_size = BOOTEXT_DEF_SIZE, 228 }, 229 230 /* 231 :x 232 */ 233 ATHEROSBOARD1("NBG-318S", "ZyXEL NBG-318S", ZYNOS_MODEL_NBG_318S, 4), 234 235 /* 236 * Atheros ar71xx based boards 237 */ 238 AR71XXBOARD1("NBG-460N", "ZyXEL NBG-460N", ZYNOS_MODEL_NBG_460N, 4), 239 240 /* 241 * Realtek Otto based boards 242 */ 243 RTL_OTTO_BOARD("GS1920-24-v1", "Zyxel GS1920-24", MID(20994), 16, 0xB0000), /* AAOB */ 244 RTL_OTTO_BOARD("GS1920-24HP-v1", "Zyxel GS1920-24HP", MID(21250), 16, 0xB0000), /* AAOC */ 245 RTL_OTTO_BOARD("GS1920-48-v1", "Zyxel GS1920-48", MID(20482), 16, 0xB0000), /* AANZ */ 246 RTL_OTTO_BOARD("GS1920-48HP-v1", "Zyxel GS1920-48HP", MID(20738), 16, 0xB0000), /* AAOA */ 247 RTL_OTTO_BOARD("GS1920-8HP-v2", "Zyxel GS1920-8HPv2", MID(27138), 32, 0x200000), /* ABKZ */ 248 RTL_OTTO_BOARD("GS1920-24-v2", "Zyxel GS1920-24v2", MID(27394), 32, 0x200000), /* ABMH */ 249 RTL_OTTO_BOARD("GS1920-24HP-v2", "Zyxel GS1920-24HPv2", MID(27650), 32, 0x200000), /* ABMI */ 250 RTL_OTTO_BOARD("GS1920-48-v2", "Zyxel GS1920-48v2", MID(27906), 32, 0x200000), /* ABMJ */ 251 RTL_OTTO_BOARD("GS1920-48HP-v2", "Zyxel GS1920-48HPv2", MID(28162), 32, 0x200000), /* ABMK */ 252 RTL_OTTO_BOARD("GS2210-8", "Zyxel GS2210-8", MID(21506), 32, 0xB0000), /* AASP */ 253 RTL_OTTO_BOARD("GS2210-8HP", "Zyxel GS2210-8HP", MID(21762), 32, 0xB0000), /* AASQ */ 254 RTL_OTTO_BOARD("GS2210-24", "Zyxel GS2210-24", MID(19458), 32, 0xB0000), /* AAND */ 255 RTL_OTTO_BOARD("GS2210-24HP", "Zyxel GS2210-24HP", MID(19714), 32, 0xB0000), /* AANE */ 256 RTL_OTTO_BOARD("GS2210-24LP", "Zyxel GS2210-24LP", MID(24322), 32, 0xB0000), /* ABEO */ 257 RTL_OTTO_BOARD("GS2210-48", "Zyxel GS2210-48", MID(18946), 32, 0xB0000), /* AAHV */ 258 RTL_OTTO_BOARD("GS2210-48HP", "Zyxel GS2210-48HP", MID(19202), 32, 0xB0000), /* AAHW */ 259 RTL_OTTO_BOARD("XGS1930-28", "Zyxel XGS1930-28", MID(24834), 32, 0x260000), /* ABHT */ 260 RTL_OTTO_BOARD("XGS1930-28HP", "Zyxel XGS1930-28HP", MID(25090), 32, 0x260000), /* ABHS */ 261 RTL_OTTO_BOARD("XGS1930-52", "Zyxel XGS1930-52", MID(25346), 32, 0x260000), /* ABHU */ 262 RTL_OTTO_BOARD("XGS1930-52HP", "Zyxel XGS1930-52HP", MID(25602), 32, 0x260000), /* ABHV */ 263 RTL_OTTO_BOARD("XGS2220-30", "Zyxel XGS2220-30", MID(34306), 64, 0x280000), /* ABXN */ 264 RTL_OTTO_BOARD("XGS2220-30HP", "Zyxel XGS2220-30HP", MID(34562), 64, 0x280000), /* ABXO */ 265 RTL_OTTO_BOARD("XGS2220-30F", "Zyxel XGS2220-30F", MID(34818), 64, 0x280000), /* ABYE */ 266 RTL_OTTO_BOARD("XGS2220-54", "Zyxel XGS2220-54", MID(35074), 64, 0x280000), /* ABXP */ 267 RTL_OTTO_BOARD("XGS2220-54HP", "Zyxel XGS2220-54HP", MID(35330), 64, 0x280000), /* ABXQ */ 268 RTL_OTTO_BOARD("XGS2220-54FP", "Zyxel XGS2220-54FP", MID(35586), 64, 0x280000), /* ACCE */ 269 RTL_OTTO_BOARD("XMG1915-10E", "Zyxel XMG1915-10E", MID(37378), 32, 0x260000), /* ACGO */ 270 RTL_OTTO_BOARD("XMG1915-10EP", "Zyxel XMG1915-10EP", MID(37634), 32, 0x260000), /* ACGP */ 271 RTL_OTTO_BOARD("XMG1915-18EP", "Zyxel XMG1915-18EP", MID(37890), 32, 0x260000), /* ACGQ */ 272 RTL_OTTO_BOARD("XMG1930-30", "Zyxel XMG1930-30", MID(33794), 32, 0x280000), /* ACAR */ 273 RTL_OTTO_BOARD("XMG1930-30HP", "Zyxel XMG1930-30HP", MID(34050), 32, 0x280000), /* ACAS */ 274 RTL_OTTO_BOARD("XS1930-10", "Zyxel XS1930-10", MID(29698), 32, 0x280000), /* ABQE */ 275 RTL_OTTO_BOARD("XS1930-12F", "Zyxel XS1930-12F", MID(33026), 32, 0x280000), /* ABZV */ 276 RTL_OTTO_BOARD("XS1930-12HP", "Zyxel XS1930-12HP", MID(29954), 32, 0x280000), /* ABQF */ 277 278 {.name = NULL} 279 }; 280 281 /* 282 * Message macros 283 */ 284 #define ERR(fmt, ...) do { \ 285 fflush(0); \ 286 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 287 progname, ## __VA_ARGS__ ); \ 288 } while (0) 289 290 #define ERRS(fmt, ...) do { \ 291 int save = errno; \ 292 fflush(0); \ 293 fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \ 294 progname, ## __VA_ARGS__, strerror(save)); \ 295 } while (0) 296 297 #define WARN(fmt, ...) do { \ 298 fprintf(stderr, "[%s] *** warning: " fmt "\n", \ 299 progname, ## __VA_ARGS__ ); \ 300 } while (0) 301 302 #define DBG(lev, fmt, ...) do { \ 303 if (verblevel < lev) \ 304 break;\ 305 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \ 306 } while (0) 307 308 #define ERR_FATAL -1 309 #define ERR_INVALID_IMAGE -2 310 311 /* 312 * Helper routines 313 */ 314 void 315 usage(int status) 316 { 317 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 318 struct board_info *board; 319 320 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 321 fprintf(stream, 322 "\n" 323 "Options:\n" 324 " -B <board> create image for the board specified with <board>.\n" 325 " valid <board> values:\n" 326 ); 327 for (board = boards; board->name != NULL; board++){ 328 fprintf(stream, 329 " %-12s= %s\n", 330 board->name, board->desc); 331 }; 332 fprintf(stream, 333 " -b <file>[:<align>]\n" 334 " add boot extension block to the image\n" 335 " -r <file>[:<align>]\n" 336 " add raw block to the image\n" 337 " -o <file> write output to the file <file>\n" 338 " -h show this screen\n" 339 ); 340 341 exit(status); 342 } 343 344 345 /* 346 * argument parsing 347 */ 348 int 349 str2u32(char *arg, uint32_t *val) 350 { 351 char *err = NULL; 352 uint32_t t; 353 354 errno=0; 355 t = strtoul(arg, &err, 0); 356 if (errno || (err==arg) || ((err != NULL) && *err)) { 357 return -1; 358 } 359 360 *val = t; 361 return 0; 362 } 363 364 365 int 366 str2u16(char *arg, uint16_t *val) 367 { 368 char *err = NULL; 369 uint32_t t; 370 371 errno=0; 372 t = strtoul(arg, &err, 0); 373 if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) { 374 return -1; 375 } 376 377 *val = t & 0xFFFF; 378 return 0; 379 } 380 381 int 382 str2u8(char *arg, uint8_t *val) 383 { 384 char *err = NULL; 385 uint32_t t; 386 387 errno=0; 388 t = strtoul(arg, &err, 0); 389 if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) { 390 return -1; 391 } 392 393 *val = t & 0xFF; 394 return 0; 395 } 396 397 int 398 str2sig(char *arg, uint32_t *sig) 399 { 400 if (strlen(arg) != 4) 401 return -1; 402 403 *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24); 404 405 return 0; 406 } 407 408 409 int 410 parse_arg(char *arg, char *buf, char *argv[]) 411 { 412 int res = 0; 413 size_t argl; 414 char *tok; 415 char **ap = &buf; 416 int i; 417 418 memset(argv, 0, MAX_ARG_COUNT * sizeof(void *)); 419 420 if ((arg == NULL)) { 421 /* no arguments */ 422 return 0; 423 } 424 425 argl = strlen(arg); 426 if (argl == 0) { 427 /* no arguments */ 428 return 0; 429 } 430 431 if (argl >= MAX_ARG_LEN) { 432 /* argument is too long */ 433 argl = MAX_ARG_LEN-1; 434 } 435 436 memcpy(buf, arg, argl); 437 buf[argl] = '\0'; 438 439 for (i = 0; i < MAX_ARG_COUNT; i++) { 440 tok = strsep(ap, ":"); 441 if (tok == NULL) { 442 break; 443 } 444 #if 0 445 else if (tok[0] == '\0') { 446 break; 447 } 448 #endif 449 argv[i] = tok; 450 res++; 451 } 452 453 return res; 454 } 455 456 457 int 458 required_arg(char c, char *arg) 459 { 460 if (arg == NULL || *arg != '-') 461 return 0; 462 463 ERR("option -%c requires an argument\n", c); 464 return -1; 465 } 466 467 468 int 469 is_empty_arg(char *arg) 470 { 471 int ret = 1; 472 if (arg != NULL) { 473 if (*arg) ret = 0; 474 }; 475 return ret; 476 } 477 478 479 void 480 csum_init(struct csum_state *css) 481 { 482 css->odd = 0; 483 css->sum = 0; 484 css->tmp = 0; 485 } 486 487 488 void 489 csum_update(void *data, uint32_t len, struct csum_state *css) 490 { 491 uint8_t *p = data; 492 493 if (len == 0) 494 return; 495 496 if (css->odd) { 497 css->sum += (css->tmp << 8) + p[0]; 498 if (css->sum > 0xFFFF) { 499 css->sum += 1; 500 css->sum &= 0xFFFF; 501 } 502 css->odd = 0; 503 len--; 504 p++; 505 } 506 507 for ( ; len > 1; len -= 2, p +=2 ) { 508 css->sum += (p[0] << 8) + p[1]; 509 if (css->sum > 0xFFFF) { 510 css->sum += 1; 511 css->sum &= 0xFFFF; 512 } 513 } 514 515 if (len == 1){ 516 css->tmp = p[0]; 517 css->odd = 1; 518 } 519 } 520 521 522 uint16_t 523 csum_get(struct csum_state *css) 524 { 525 char pad = 0; 526 527 csum_update(&pad, 1, css); 528 return css->sum; 529 } 530 531 uint16_t 532 csum_buf(uint8_t *p, uint32_t len) 533 { 534 struct csum_state css; 535 536 csum_init(&css); 537 csum_update(p, len, &css); 538 return csum_get(&css); 539 540 } 541 542 /* 543 * routines to write data to the output file 544 */ 545 int 546 write_out_data(FILE *outfile, void *data, size_t len, 547 struct csum_state *css) 548 { 549 uint8_t *ptr = data; 550 551 errno = 0; 552 553 fwrite(ptr, len, 1, outfile); 554 if (errno) { 555 ERR("unable to write output file"); 556 return -1; 557 } 558 559 if (css) { 560 csum_update(ptr, len, css); 561 } 562 563 return 0; 564 } 565 566 567 int 568 write_out_padding(FILE *outfile, size_t len, uint8_t padc, 569 struct csum_state *css) 570 { 571 uint8_t buf[512]; 572 size_t buflen = sizeof(buf); 573 574 memset(buf, padc, buflen); 575 while (len > 0) { 576 if (len < buflen) 577 buflen = len; 578 579 if (write_out_data(outfile, buf, buflen, css)) 580 return -1; 581 582 len -= buflen; 583 } 584 585 return 0; 586 } 587 588 589 int 590 write_out_data_align(FILE *outfile, void *data, size_t len, size_t align, 591 struct csum_state *css) 592 { 593 size_t padlen; 594 int res; 595 596 res = write_out_data(outfile, data, len, css); 597 if (res) 598 return res; 599 600 padlen = ALIGN(len,align) - len; 601 res = write_out_padding(outfile, padlen, 0xFF, css); 602 603 return res; 604 } 605 606 607 int 608 write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr) 609 { 610 struct zyn_rombin_hdr t; 611 612 errno = 0; 613 if (fseek(outfile, 0, SEEK_SET) != 0) { 614 ERRS("fseek failed on output file"); 615 return -1; 616 } 617 618 /* setup temporary header fields */ 619 memset(&t, 0, sizeof(t)); 620 t.addr = HOST_TO_BE32(hdr->addr); 621 memcpy(&t.sig, ROMBIN_SIGNATURE, ROMBIN_SIG_LEN); 622 t.type = hdr->type; 623 t.flags = hdr->flags; 624 t.osize = HOST_TO_BE32(hdr->osize); 625 t.csize = HOST_TO_BE32(hdr->csize); 626 t.ocsum = HOST_TO_BE16(hdr->ocsum); 627 t.ccsum = HOST_TO_BE16(hdr->ccsum); 628 t.mmap_addr = HOST_TO_BE32(hdr->mmap_addr); 629 630 DBG(2, "hdr.addr = 0x%08x", hdr->addr); 631 DBG(2, "hdr.type = 0x%02x", hdr->type); 632 DBG(2, "hdr.osize = 0x%08x", hdr->osize); 633 DBG(2, "hdr.csize = 0x%08x", hdr->csize); 634 DBG(2, "hdr.flags = 0x%02x", hdr->flags); 635 DBG(2, "hdr.ocsum = 0x%04x", hdr->ocsum); 636 DBG(2, "hdr.ccsum = 0x%04x", hdr->ccsum); 637 DBG(2, "hdr.mmap_addr = 0x%08x", hdr->mmap_addr); 638 639 return write_out_data(outfile, (uint8_t *)&t, sizeof(t), NULL); 640 } 641 642 643 int 644 write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css) 645 { 646 struct zyn_mmt_hdr *mh; 647 uint8_t buf[MMAP_DATA_SIZE]; 648 uint32_t user_size; 649 char *data; 650 int res; 651 652 memset(buf, 0, sizeof(buf)); 653 654 mh = (struct zyn_mmt_hdr *)buf; 655 656 /* TODO: needs to recreate the memory map too? */ 657 mh->count=0; 658 659 /* Build user data section */ 660 data = (char *)buf + sizeof(*mh); 661 data += sprintf(data, "Vendor 1 %d", board->vendor); 662 *data++ = '\0'; 663 data += sprintf(data, "Model 1 %d", BE16_TO_HOST(board->model)); 664 *data++ = '\0'; 665 /* TODO: make hardware version configurable? */ 666 data += sprintf(data, "HwVerRange 2 %d %d", 0, 0); 667 *data++ = '\0'; 668 669 user_size = (uint8_t *)data - buf; 670 mh->user_start= HOST_TO_BE32(mmap->addr+sizeof(*mh)); 671 mh->user_end= HOST_TO_BE32(mmap->addr+user_size); 672 mh->csum = HOST_TO_BE16(csum_buf(buf+sizeof(*mh), user_size)); 673 674 res = write_out_data(outfile, buf, sizeof(buf), css); 675 676 return res; 677 } 678 679 680 int 681 block_stat_file(struct fw_block *block) 682 { 683 struct stat st; 684 int res; 685 686 if (block->file_name == NULL) 687 return 0; 688 689 res = stat(block->file_name, &st); 690 if (res){ 691 ERRS("stat failed on %s", block->file_name); 692 return res; 693 } 694 695 block->file_size = st.st_size; 696 return 0; 697 } 698 699 700 int 701 read_magic(uint16_t *magic) 702 { 703 FILE *f; 704 int res; 705 706 errno = 0; 707 f = fopen(bootext_block->file_name,"r"); 708 if (errno) { 709 ERRS("unable to open file: %s", bootext_block->file_name); 710 return -1; 711 } 712 713 errno = 0; 714 fread(magic, 2, 1, f); 715 if (errno != 0) { 716 ERRS("unable to read from file: %s", bootext_block->file_name); 717 res = -1; 718 goto err; 719 } 720 721 res = 0; 722 723 err: 724 fclose(f); 725 return res; 726 } 727 728 729 int 730 write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css) 731 { 732 char buf[FILE_BUF_LEN]; 733 size_t buflen = sizeof(buf); 734 FILE *f; 735 int res; 736 737 DBG(2, "writing out file, name=%s, len=%zu", 738 name, len); 739 740 errno = 0; 741 f = fopen(name,"r"); 742 if (errno) { 743 ERRS("unable to open file: %s", name); 744 return -1; 745 } 746 747 while (len > 0) { 748 if (len < buflen) 749 buflen = len; 750 751 /* read data from source file */ 752 errno = 0; 753 fread(buf, buflen, 1, f); 754 if (errno != 0) { 755 ERRS("unable to read from file: %s",name); 756 res = -1; 757 break; 758 } 759 760 res = write_out_data(outfile, buf, buflen, css); 761 if (res) 762 break; 763 764 len -= buflen; 765 } 766 767 fclose(f); 768 return res; 769 } 770 771 772 int 773 write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css) 774 { 775 int res; 776 777 if (block == NULL) 778 return 0; 779 780 if (block->file_name == NULL) 781 return 0; 782 783 if (block->file_size == 0) 784 return 0; 785 786 res = write_out_file(outfile, block->file_name, 787 block->file_size, css); 788 return res; 789 } 790 791 792 int 793 write_out_image(FILE *outfile) 794 { 795 struct fw_block *block; 796 struct fw_mmap mmap; 797 struct zyn_rombin_hdr hdr; 798 struct csum_state css; 799 int i, res; 800 uint32_t offset; 801 uint32_t padlen; 802 uint16_t csum; 803 uint16_t t; 804 805 /* setup header fields */ 806 memset(&hdr, 0, sizeof(hdr)); 807 hdr.addr = board->code_start; 808 hdr.type = OBJECT_TYPE_BOOTEXT; 809 hdr.flags = ROMBIN_FLAG_OCSUM; 810 811 offset = board->romio_offs; 812 813 res = write_out_header(outfile, &hdr); 814 if (res) 815 return res; 816 817 offset += sizeof(hdr); 818 819 csum_init(&css); 820 res = write_out_block(outfile, bootext_block, &css); 821 if (res) 822 return res; 823 824 offset += bootext_block->file_size; 825 if (offset > (board->romio_offs + board->bootext_size)) { 826 ERR("bootext file '%s' is too big", bootext_block->file_name); 827 return -1; 828 } 829 830 padlen = ALIGN(offset, MMAP_ALIGN) - offset; 831 res = write_out_padding(outfile, padlen, 0xFF, &css); 832 if (res) 833 return res; 834 835 offset += padlen; 836 837 mmap.addr = board->flash_base + offset; 838 res = write_out_mmap(outfile, &mmap, &css); 839 if (res) 840 return res; 841 842 offset += MMAP_DATA_SIZE; 843 844 if ((offset - board->romio_offs) < board->bootext_size) { 845 padlen = board->romio_offs + board->bootext_size - offset; 846 res = write_out_padding(outfile, padlen, 0xFF, &css); 847 if (res) 848 return res; 849 offset += padlen; 850 851 DBG(2, "bootext end at %08x", offset); 852 } 853 854 for (i = 0; i < num_blocks; i++) { 855 block = &blocks[i]; 856 857 if (block->type == BLOCK_TYPE_BOOTEXT) 858 continue; 859 860 padlen = ALIGN(offset, block->align) - offset; 861 res = write_out_padding(outfile, padlen, 0xFF, &css); 862 if (res) 863 return res; 864 offset += padlen; 865 866 res = write_out_block(outfile, block, &css); 867 if (res) 868 return res; 869 offset += block->file_size; 870 } 871 872 padlen = ALIGN(offset, 4) - offset; 873 res = write_out_padding(outfile, padlen, 0xFF, &css); 874 if (res) 875 return res; 876 offset += padlen; 877 878 csum = csum_get(&css); 879 hdr.mmap_addr = mmap.addr; 880 hdr.osize = 2; 881 882 res = read_magic(&hdr.ocsum); 883 if (res) 884 return res; 885 hdr.ocsum = BE16_TO_HOST(hdr.ocsum); 886 887 if (csum <= hdr.ocsum) 888 t = hdr.ocsum - csum; 889 else 890 t = hdr.ocsum - csum - 1; 891 892 DBG(2, "ocsum=%04x, csum=%04x, fix=%04x", hdr.ocsum, csum, t); 893 894 t = HOST_TO_BE16(t); 895 res = write_out_data(outfile, (uint8_t *)&t, 2, NULL); 896 if (res) 897 return res; 898 899 900 res = write_out_header(outfile, &hdr); 901 902 return res; 903 } 904 905 906 struct board_info * 907 find_board(char *name) 908 { 909 struct board_info *ret; 910 struct board_info *board; 911 912 ret = NULL; 913 for (board = boards; board->name != NULL; board++){ 914 if (strcasecmp(name, board->name) == 0) { 915 ret = board; 916 break; 917 } 918 }; 919 920 return ret; 921 } 922 923 924 int 925 parse_opt_board(char ch, char *arg) 926 { 927 928 DBG(1,"parsing board option: -%c %s", ch, arg); 929 930 if (board != NULL) { 931 ERR("only one board option allowed"); 932 return -1; 933 } 934 935 if (required_arg(ch, arg)) 936 return -1; 937 938 board = find_board(arg); 939 if (board == NULL){ 940 ERR("invalid/unknown board specified: %s", arg); 941 return -1; 942 } 943 944 return 0; 945 } 946 947 948 int 949 parse_opt_ofname(char ch, char *arg) 950 { 951 952 if (ofname != NULL) { 953 ERR("only one output file allowed"); 954 return -1; 955 } 956 957 if (required_arg(ch, arg)) 958 return -1; 959 960 ofname = arg; 961 962 return 0; 963 } 964 965 966 int 967 parse_opt_block(char ch, char *arg) 968 { 969 char buf[MAX_ARG_LEN]; 970 char *argv[MAX_ARG_COUNT]; 971 char *p; 972 struct fw_block *block; 973 int i; 974 975 if ( num_blocks >= MAX_NUM_BLOCKS ) { 976 ERR("too many blocks specified"); 977 return -1; 978 } 979 980 block = &blocks[num_blocks++]; 981 982 /* setup default field values */ 983 block->padc = 0xFF; 984 985 switch(ch) { 986 case 'b': 987 if (bootext_block) { 988 ERR("only one boot extension block allowed"); 989 break; 990 } 991 block->type = BLOCK_TYPE_BOOTEXT; 992 bootext_block = block; 993 break; 994 case 'r': 995 block->type = BLOCK_TYPE_RAW; 996 break; 997 } 998 999 parse_arg(arg, buf, argv); 1000 1001 i = 0; 1002 p = argv[i++]; 1003 if (is_empty_arg(p)) { 1004 ERR("no file specified in %s", arg); 1005 return -1; 1006 } else { 1007 block->file_name = strdup(p); 1008 if (block->file_name == NULL) { 1009 ERR("not enough memory"); 1010 return -1; 1011 } 1012 } 1013 1014 if (block->type == BLOCK_TYPE_BOOTEXT) 1015 return 0; 1016 1017 p = argv[i++]; 1018 if (!is_empty_arg(p)) { 1019 if (str2u32(p, &block->align) != 0) { 1020 ERR("invalid block align in %s", arg); 1021 return -1; 1022 } 1023 } 1024 1025 return 0; 1026 } 1027 1028 1029 int 1030 calc_block_offsets(int type, uint32_t *offset) 1031 { 1032 struct fw_block *block; 1033 uint32_t next_offs; 1034 uint32_t avail; 1035 int i, res; 1036 1037 DBG(1,"calculating block offsets, starting with %" PRIu32, 1038 *offset); 1039 1040 res = 0; 1041 for (i = 0; i < num_blocks; i++) { 1042 block = &blocks[i]; 1043 1044 if (block->type != type) 1045 continue; 1046 1047 next_offs = ALIGN(*offset, block->align); 1048 avail = board->flash_size - next_offs; 1049 if (block->file_size > avail) { 1050 ERR("file %s is too big, offset = %u, size=%u," 1051 " avail = %u, align = %u", block->file_name, 1052 (unsigned)next_offs, 1053 (unsigned)block->file_size, 1054 (unsigned)avail, 1055 (unsigned)block->align); 1056 res = -1; 1057 break; 1058 } 1059 1060 block->padlen = next_offs - *offset; 1061 *offset += block->file_size; 1062 } 1063 1064 return res; 1065 } 1066 1067 int 1068 process_blocks(void) 1069 { 1070 struct fw_block *block; 1071 uint32_t offset; 1072 int i; 1073 int res; 1074 1075 /* collecting file stats */ 1076 for (i = 0; i < num_blocks; i++) { 1077 block = &blocks[i]; 1078 res = block_stat_file(block); 1079 if (res) 1080 return res; 1081 } 1082 1083 offset = board->romio_offs + bootext_block->file_size; 1084 res = calc_block_offsets(BLOCK_TYPE_RAW, &offset); 1085 1086 return res; 1087 } 1088 1089 1090 int 1091 main(int argc, char *argv[]) 1092 { 1093 int optinvalid = 0; /* flag for invalid option */ 1094 int c; 1095 int res = EXIT_FAILURE; 1096 1097 FILE *outfile; 1098 1099 progname=basename(argv[0]); 1100 1101 opterr = 0; /* could not print standard getopt error messages */ 1102 while ( 1 ) { 1103 optinvalid = 0; 1104 1105 c = getopt(argc, argv, "b:B:ho:r:v"); 1106 if (c == -1) 1107 break; 1108 1109 switch (c) { 1110 case 'b': 1111 case 'r': 1112 optinvalid = parse_opt_block(c,optarg); 1113 break; 1114 case 'B': 1115 optinvalid = parse_opt_board(c,optarg); 1116 break; 1117 case 'o': 1118 optinvalid = parse_opt_ofname(c,optarg); 1119 break; 1120 case 'v': 1121 verblevel++; 1122 break; 1123 case 'h': 1124 usage(EXIT_SUCCESS); 1125 break; 1126 default: 1127 optinvalid = 1; 1128 break; 1129 } 1130 if (optinvalid != 0 ) { 1131 ERR("invalid option: -%c", optopt); 1132 goto out; 1133 } 1134 } 1135 1136 if (board == NULL) { 1137 ERR("no board specified"); 1138 goto out; 1139 } 1140 1141 if (ofname == NULL) { 1142 ERR("no output file specified"); 1143 goto out; 1144 } 1145 1146 if (optind < argc) { 1147 ERR("invalid option: %s", argv[optind]); 1148 goto out; 1149 } 1150 1151 if (process_blocks() != 0) { 1152 goto out; 1153 } 1154 1155 outfile = fopen(ofname, "w"); 1156 if (outfile == NULL) { 1157 ERRS("could not open \"%s\" for writing", ofname); 1158 goto out; 1159 } 1160 1161 if (write_out_image(outfile) != 0) 1162 goto out_flush; 1163 1164 DBG(1,"Image file %s completed.", ofname); 1165 1166 res = EXIT_SUCCESS; 1167 1168 out_flush: 1169 fflush(outfile); 1170 fclose(outfile); 1171 if (res != EXIT_SUCCESS) { 1172 unlink(ofname); 1173 } 1174 out: 1175 return res; 1176 } 1177
This page was automatically generated by LXR 0.3.1. • OpenWrt