1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com> 4 * Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com> 5 * 6 * The format of the header this tool generates was first documented by 7 * Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the 8 * same purpose. I have created this reimplementation at his request. The 9 * original script can be found at: 10 * <https://github.com/riptidewave93/meraki-partbuilder> 11 * 12 * Support for the old header format, which is used by the Cisco Z1 AP 13 * has been reverse engineered from the nandloader's nand_load_bk function. 14 * The original code is part of Cisco's GPL code and can be found at: 15 * <https://github.com/riptidewave93/meraki-linux> 16 */ 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <stdbool.h> 21 #include <string.h> 22 #include <libgen.h> 23 #include <endian.h> 24 #include <getopt.h> 25 #include <errno.h> 26 #include <arpa/inet.h> 27 28 #define PADDING_BYTE 0xff 29 30 #define HDR_LENGTH 0x00000020 31 #define HDR_OFF_MAGIC1 0 32 #define HDR_OFF_LOAD_ADDR 4 33 #define HDR_OFF_IMAGELEN 8 34 #define HDR_OFF_ENTRY 12 35 #define HDR_OFF_CHECKSUM 16 36 #define HDR_OFF_FILLER0 20 37 #define HDR_OFF_FILLER1 24 38 #define HDR_OFF_FILLER2 28 39 40 struct board_info { 41 char *id; 42 char *description; 43 uint32_t magic; 44 uint32_t imagelen; 45 uint32_t load_addr; 46 uint32_t entry; 47 bool le32; 48 }; 49 50 /* 51 * Globals 52 */ 53 static char *progname; 54 static bool strip_padding; 55 56 static char *board_id; 57 static const struct board_info *board; 58 59 static const struct board_info boards[] = { 60 { 61 .id = "z1", 62 .description = "Meraki Z1 Access Point", 63 .magic = 0x4d495053, 64 .imagelen = 0x007e0000, 65 .load_addr = 0x80060000, 66 .entry = 0x80060000, 67 .le32 = 0, 68 }, { 69 .id = "mx64", 70 .description = "Meraki MX64/MX65", 71 .magic = 0x4d495053, 72 .imagelen = 0x00000000, 73 .load_addr = 0x60008000, 74 .entry = 0x60008000, 75 .le32 = 1, 76 }, { 77 /* terminating entry */ 78 } 79 }; 80 81 /* 82 * Message macros 83 */ 84 #define ERR(fmt, ...) do { \ 85 fflush(0); \ 86 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 87 progname, ## __VA_ARGS__); \ 88 } while (0) 89 90 #define ERRS(fmt, ...) do { \ 91 int save = errno; \ 92 fflush(0); \ 93 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 94 progname, ## __VA_ARGS__, strerror(save)); \ 95 } while (0) 96 97 static const struct board_info *find_board(const char *id) 98 { 99 const struct board_info *ret; 100 const struct board_info *board; 101 102 ret = NULL; 103 for (board = boards; board->id != NULL; board++) { 104 if (strcasecmp(id, board->id) == 0) { 105 ret = board; 106 break; 107 } 108 } 109 110 return ret; 111 } 112 113 static void usage(int status) 114 { 115 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 116 const struct board_info *board; 117 118 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 119 fprintf(stream, 120 "\n" 121 "Options:\n" 122 " -B <board> create image for the board specified with <board>\n" 123 " -i <file> read kernel image from the file <file>\n" 124 " -o <file> write output to the file <file>\n" 125 " -s strip padding from the end of the image\n" 126 " -h show this screen\n" 127 ); 128 129 fprintf(stream, "\nBoards:\n"); 130 for (board = boards; board->id != NULL; board++) 131 fprintf(stream, " %-16s%s\n", board->id, board->description); 132 133 exit(status); 134 } 135 136 static void writel(unsigned char *buf, size_t offset, uint32_t value, bool le32) 137 { 138 if (!le32) 139 value = htonl(value); 140 141 memcpy(buf + offset, &value, sizeof(uint32_t)); 142 } 143 144 static const uint32_t crc32_table[] = { 145 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 146 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 147 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 148 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 149 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 150 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 151 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 152 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 153 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 154 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 155 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 156 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 157 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 158 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 159 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 160 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 161 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 162 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 163 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 164 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 165 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 166 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 167 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 168 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 169 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 170 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 171 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 172 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 173 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 174 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 175 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 176 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 177 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 178 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 179 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 180 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 181 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 182 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 183 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 184 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 185 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 186 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 187 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 188 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 189 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 190 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 191 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 192 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 193 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 194 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 195 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 196 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 197 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 198 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 199 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 200 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 201 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 202 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 203 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 204 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 205 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 206 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 207 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 208 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 209 }; 210 211 static inline uint32_t crc32_accumulate_8(const uint32_t crc, const uint8_t ch) 212 { 213 return crc32_table[(crc ^ ch) & 0xff] ^ (crc >> 8); 214 } 215 216 static void crc32_csum(uint8_t *buf, const size_t len, bool le32) 217 { 218 int j, k, l, m; 219 uint32_t crc; 220 size_t i; 221 222 crc = ~0; 223 k = le32 * 3; 224 l = le32 * -2 + 1; 225 226 for (i = 0; i < len; i += 4) { 227 for (j = 3; j >= 0; j -= 1) { 228 m = (j - k) * l; 229 crc = crc32_accumulate_8(crc, buf[i + m]); 230 } 231 } 232 crc = ~crc; 233 234 writel(buf, HDR_OFF_CHECKSUM, crc, le32); 235 } 236 237 238 static int meraki_build_hdr(const struct board_info *board, const size_t klen, 239 FILE *out, FILE *in) 240 { 241 unsigned char *kernel; 242 unsigned char *buf; 243 size_t buflen; 244 size_t kspace; 245 246 size_t rc; 247 buflen = board->imagelen; 248 249 if (buflen > 0) { 250 kspace = buflen - HDR_LENGTH; 251 252 if (klen > kspace) { 253 ERR("kernel file is too big - max size: 0x%08lX\n", kspace); 254 return EXIT_FAILURE; 255 } 256 } 257 258 /* If requested, resize buffer to remove padding */ 259 if (strip_padding) 260 buflen = klen + HDR_LENGTH; 261 262 /* Allocate and initialize buffer for final image */ 263 buf = malloc(buflen); 264 if (buf == NULL) { 265 ERRS("no memory for buffer: %s\n"); 266 return EXIT_FAILURE; 267 } 268 memset(buf, PADDING_BYTE, buflen); 269 270 /* Load kernel */ 271 kernel = buf + HDR_LENGTH; 272 fread(kernel, klen, 1, in); 273 274 /* Write magic values and filler */ 275 writel(buf, HDR_OFF_MAGIC1, board->magic, board->le32); 276 writel(buf, HDR_OFF_FILLER0, 0, board->le32); 277 writel(buf, HDR_OFF_FILLER1, 0, board->le32); 278 writel(buf, HDR_OFF_FILLER2, 0, board->le32); 279 280 /* Write load and kernel entry point address */ 281 writel(buf, HDR_OFF_LOAD_ADDR, board->load_addr, board->le32); 282 writel(buf, HDR_OFF_ENTRY, board->entry, board->le32); 283 284 /* Write header and image length */ 285 writel(buf, HDR_OFF_IMAGELEN, klen, board->le32); 286 287 /* this gets replaced later, after the checksum has been calculated */ 288 writel(buf, HDR_OFF_CHECKSUM, 0, board->le32); 289 290 /* Write checksum */ 291 crc32_csum(buf, klen + HDR_LENGTH, board->le32); 292 293 rc = fwrite(buf, buflen, 1, out); 294 295 free(buf); 296 297 return rc == 1 ? EXIT_SUCCESS : EXIT_FAILURE; 298 } 299 300 int main(int argc, char *argv[]) 301 { 302 int ret = EXIT_FAILURE; 303 char *ofname = NULL, *ifname = NULL; 304 FILE *out, *in; 305 size_t klen; 306 307 progname = basename(argv[0]); 308 309 while (1) { 310 int c; 311 312 c = getopt(argc, argv, "B:i:o:sh"); 313 if (c == -1) 314 break; 315 316 switch (c) { 317 case 'B': 318 board_id = optarg; 319 break; 320 case 'i': 321 ifname = optarg; 322 break; 323 case 'o': 324 ofname = optarg; 325 break; 326 case 's': 327 strip_padding = true; 328 break; 329 case 'h': 330 usage(EXIT_SUCCESS); 331 break; 332 default: 333 usage(EXIT_FAILURE); 334 break; 335 } 336 } 337 338 if (board_id == NULL) { 339 ERR("no board specified"); 340 goto err; 341 } 342 343 board = find_board(board_id); 344 if (board == NULL) { 345 ERR("unknown board \"%s\"", board_id); 346 goto err; 347 } 348 349 if (ifname == NULL) { 350 ERR("no input file specified"); 351 goto err; 352 } 353 354 if (ofname == NULL) { 355 ERR("no output file specified"); 356 goto err; 357 } 358 359 in = fopen(ifname, "r"); 360 if (in == NULL) { 361 ERRS("could not open \"%s\" for reading: %s", ifname); 362 goto err; 363 } 364 365 /* Get kernel length */ 366 fseek(in, 0, SEEK_END); 367 klen = ftell(in); 368 rewind(in); 369 370 out = fopen(ofname, "w"); 371 if (out == NULL) { 372 ERRS("could not open \"%s\" for writing: %s", ofname); 373 goto err_close_in; 374 } 375 376 ret = meraki_build_hdr(board, klen, out, in); 377 fclose(out); 378 379 err_close_in: 380 fclose(in); 381 382 err: 383 return ret; 384 } 385
This page was automatically generated by LXR 0.3.1. • OpenWrt