1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com> 4 * 5 * The format of the header this tool generates was first documented by 6 * Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the 7 * same purpose. I have created this reimplementation at his request. The 8 * original script can be found at: 9 * <https://github.com/riptidewave93/meraki-partbuilder> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <stdbool.h> 15 #include <string.h> 16 #include <libgen.h> 17 #include <getopt.h> 18 #include <errno.h> 19 #include <arpa/inet.h> 20 21 #include "sha1.h" 22 23 #define PADDING_BYTE 0xff 24 25 #define HDR_LENGTH 0x00000400 26 #define HDR_OFF_MAGIC1 0 27 #define HDR_OFF_HDRLEN 4 28 #define HDR_OFF_IMAGELEN 8 29 #define HDR_OFF_CHECKSUM 12 30 #define HDR_OFF_MAGIC2 32 31 #define HDR_OFF_MAGIC3 36 32 #define HDR_OFF_STATICHASH 40 33 #define HDR_OFF_KERNEL_OFFSET 40 34 #define HDR_OFF_RAMDISK_OFFSET 44 35 #define HDR_OFF_FDT_OFFSET 48 36 #define HDR_OFF_UNKNOWN_OFFSET 52 37 38 struct board_info { 39 uint32_t magic1; 40 uint32_t magic2; 41 uint32_t magic3; 42 uint32_t imagelen; 43 union { 44 unsigned char statichash[20]; 45 struct { 46 uint32_t kernel_offset; 47 uint32_t ramdisk_offset; 48 uint32_t fdt_offset; 49 uint32_t unknown_offset; 50 } mx60; 51 } u; 52 char *id; 53 char *description; 54 }; 55 56 /* 57 * Globals 58 */ 59 static char *progname; 60 61 static char *board_id; 62 static const struct board_info *board; 63 64 static const struct board_info boards[] = { 65 { 66 .id = "mr18", 67 .description = "Meraki MR18 Access Point", 68 .magic1 = 0x8e73ed8a, 69 .magic2 = 0x8e73ed8a, 70 .imagelen = 0x00800000, 71 .u.statichash = {0xda, 0x39, 0xa3, 0xee, 0x5e, 72 0x6b, 0x4b, 0x0d, 0x32, 0x55, 73 0xbf, 0xef, 0x95, 0x60, 0x18, 74 0x90, 0xaf, 0xd8, 0x07, 0x09}, 75 }, { 76 .id = "mr24", 77 .description = "Meraki MR24 Access Point", 78 .magic1 = 0x8e73ed8a, 79 .magic2 = 0x8e73ed8a, 80 .imagelen = 0x00800000, 81 .u.statichash = {0xff, 0xff, 0xff, 0xff, 0xff, 82 0xff, 0xff, 0xff, 0xff, 0xff, 83 0xff, 0xff, 0xff, 0xff, 0xff, 84 0xff, 0xff, 0xff, 0xff, 0xff}, 85 }, { 86 .id = "mx60", 87 .description = "Meraki MX60/MX60W Security Appliance", 88 .magic1 = 0x8e73ed8a, 89 .magic2 = 0xa1f0beef, /* Enables use of load addr in statichash */ 90 .magic3 = 0x00060001, /* This goes along with magic2 */ 91 .imagelen = 0x3fd00000, 92 /* The static hash below does the following: 93 * 1st Row: Kernel Offset 94 * 2nd Row: Ramdisk Offset 95 * 3rd Row: FDT Offset 96 * 4th Row: ? Unused/Unknown ? 97 * 5th Row: ? Unused/Unknown ? 98 */ 99 .u.mx60 = { 100 .kernel_offset = 0x10000, 101 .ramdisk_offset = 0x3FFC00, 102 .fdt_offset = 0x0400, 103 .unknown_offset = 0x0400, 104 }, 105 }, { 106 /* terminating entry */ 107 } 108 }; 109 110 /* 111 * Message macros 112 */ 113 #define ERR(fmt, ...) do { \ 114 fflush(0); \ 115 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 116 progname, ## __VA_ARGS__); \ 117 } while (0) 118 119 #define ERRS(fmt, ...) do { \ 120 int save = errno; \ 121 fflush(0); \ 122 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 123 progname, ## __VA_ARGS__, strerror(save)); \ 124 } while (0) 125 126 static const struct board_info *find_board(const char *id) 127 { 128 const struct board_info *ret; 129 const struct board_info *board; 130 131 ret = NULL; 132 for (board = boards; board->id != NULL; board++) { 133 if (strcasecmp(id, board->id) == 0) { 134 ret = board; 135 break; 136 } 137 } 138 139 return ret; 140 } 141 142 static void usage(int status) 143 { 144 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 145 const struct board_info *board; 146 147 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 148 fprintf(stream, 149 "\n" 150 "Options:\n" 151 " -B <board> create image for the board specified with <board>\n" 152 " -i <file> read kernel image from the file <file>\n" 153 " -o <file> write output to the file <file>\n" 154 " -s strip padding from the end of the image\n" 155 " -h show this screen\n" 156 ); 157 158 fprintf(stream, "\nBoards:\n"); 159 for (board = boards; board->id != NULL; board++) 160 fprintf(stream, " %-16s%s\n", board->id, board->description); 161 162 exit(status); 163 } 164 165 void writel(unsigned char *buf, size_t offset, uint32_t value) 166 { 167 value = htonl(value); 168 memcpy(buf + offset, &value, sizeof(uint32_t)); 169 } 170 171 int main(int argc, char *argv[]) 172 { 173 int ret = EXIT_FAILURE; 174 long klen; 175 size_t kspace; 176 unsigned char *kernel; 177 size_t buflen; 178 unsigned char *buf; 179 bool strip_padding = false; 180 char *ofname = NULL, *ifname = NULL; 181 FILE *out, *in; 182 183 progname = basename(argv[0]); 184 185 while (1) { 186 int c; 187 188 c = getopt(argc, argv, "B:i:o:sh"); 189 if (c == -1) 190 break; 191 192 switch (c) { 193 case 'B': 194 board_id = optarg; 195 break; 196 case 'i': 197 ifname = optarg; 198 break; 199 case 'o': 200 ofname = optarg; 201 break; 202 case 's': 203 strip_padding = true; 204 break; 205 case 'h': 206 usage(EXIT_SUCCESS); 207 break; 208 default: 209 usage(EXIT_FAILURE); 210 break; 211 } 212 } 213 214 if (board_id == NULL) { 215 ERR("no board specified"); 216 goto err; 217 } 218 219 board = find_board(board_id); 220 if (board == NULL) { 221 ERR("unknown board \"%s\"", board_id); 222 goto err; 223 } 224 225 if (ifname == NULL) { 226 ERR("no input file specified"); 227 goto err; 228 } 229 230 if (ofname == NULL) { 231 ERR("no output file specified"); 232 goto err; 233 } 234 235 in = fopen(ifname, "r"); 236 if (in == NULL) { 237 ERRS("could not open \"%s\" for reading: %s", ifname); 238 goto err; 239 } 240 241 buflen = board->imagelen; 242 kspace = buflen - HDR_LENGTH; 243 244 /* Get kernel length */ 245 fseek(in, 0, SEEK_END); 246 klen = ftell(in); 247 rewind(in); 248 249 if (klen > kspace) { 250 ERR("file \"%s\" is too big - max size: 0x%08lX\n", 251 ifname, kspace); 252 goto err_close_in; 253 } 254 255 /* If requested, resize buffer to remove padding */ 256 if (strip_padding) 257 buflen = klen + HDR_LENGTH; 258 259 /* Allocate and initialize buffer for final image */ 260 buf = malloc(buflen); 261 if (buf == NULL) { 262 ERRS("no memory for buffer: %s\n"); 263 goto err_close_in; 264 } 265 memset(buf, PADDING_BYTE, buflen); 266 267 /* Load kernel */ 268 kernel = buf + HDR_LENGTH; 269 fread(kernel, klen, 1, in); 270 271 /* Write magic values */ 272 writel(buf, HDR_OFF_MAGIC1, board->magic1); 273 writel(buf, HDR_OFF_MAGIC2, board->magic2); 274 writel(buf, HDR_OFF_MAGIC3, board->magic3); 275 276 /* Write header and image length */ 277 writel(buf, HDR_OFF_HDRLEN, HDR_LENGTH); 278 writel(buf, HDR_OFF_IMAGELEN, klen); 279 280 /* Write checksum and static hash */ 281 sha1_csum(kernel, klen, buf + HDR_OFF_CHECKSUM); 282 283 switch (board->magic2) { 284 case 0xa1f0beef: 285 writel(buf, HDR_OFF_KERNEL_OFFSET, board->u.mx60.kernel_offset); 286 writel(buf, HDR_OFF_RAMDISK_OFFSET, board->u.mx60.ramdisk_offset); 287 writel(buf, HDR_OFF_FDT_OFFSET, board->u.mx60.fdt_offset), 288 writel(buf, HDR_OFF_UNKNOWN_OFFSET, board->u.mx60.unknown_offset); 289 break; 290 291 case 0x8e73ed8a: 292 memcpy(buf + HDR_OFF_STATICHASH, board->u.statichash, 20); 293 break; 294 } 295 296 /* Save finished image */ 297 out = fopen(ofname, "w"); 298 if (out == NULL) { 299 ERRS("could not open \"%s\" for writing: %s", ofname); 300 goto err_free; 301 } 302 fwrite(buf, buflen, 1, out); 303 304 ret = EXIT_SUCCESS; 305 306 fclose(out); 307 308 err_free: 309 free(buf); 310 311 err_close_in: 312 fclose(in); 313 314 err: 315 return ret; 316 } 317
This page was automatically generated by LXR 0.3.1. • OpenWrt