2 * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
4 * The format of the header this tool generates was first documented by
5 * Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the
6 * same purpose. I have created this reimplementation at his request. The
7 * original script can be found at:
8 * <https://github.com/riptidewave93/meraki-partbuilder>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published
12 * by the Free Software Foundation.
23 #include <arpa/inet.h>
27 #define PADDING_BYTE 0xff
29 #define HDR_LENGTH 0x00000400
30 #define HDR_OFF_MAGIC1 0
31 #define HDR_OFF_HDRLEN 4
32 #define HDR_OFF_IMAGELEN 8
33 #define HDR_OFF_CHECKSUM 12
34 #define HDR_OFF_MAGIC2 32
35 #define HDR_OFF_MAGIC3 36
36 #define HDR_OFF_STATICHASH 40
37 #define HDR_OFF_KERNEL_OFFSET 40
38 #define HDR_OFF_RAMDISK_OFFSET 44
39 #define HDR_OFF_FDT_OFFSET 48
40 #define HDR_OFF_UNKNOWN_OFFSET 52
48 unsigned char statichash
[20];
50 uint32_t kernel_offset
;
51 uint32_t ramdisk_offset
;
53 uint32_t unknown_offset
;
63 static char *progname
;
65 static char *board_id
;
66 static const struct board_info
*board
;
68 static const struct board_info boards
[] = {
71 .description
= "Meraki MR18 Access Point",
74 .imagelen
= 0x00800000,
75 .u
.statichash
= {0xda, 0x39, 0xa3, 0xee, 0x5e,
76 0x6b, 0x4b, 0x0d, 0x32, 0x55,
77 0xbf, 0xef, 0x95, 0x60, 0x18,
78 0x90, 0xaf, 0xd8, 0x07, 0x09},
81 .description
= "Meraki MR24 Access Point",
84 .imagelen
= 0x00800000,
85 .u
.statichash
= {0xff, 0xff, 0xff, 0xff, 0xff,
86 0xff, 0xff, 0xff, 0xff, 0xff,
87 0xff, 0xff, 0xff, 0xff, 0xff,
88 0xff, 0xff, 0xff, 0xff, 0xff},
91 .description
= "Meraki MX60/MX60W Security Appliance",
93 .magic2
= 0xa1f0beef, /* Enables use of load addr in statichash */
94 .magic3
= 0x00060001, /* This goes along with magic2 */
95 .imagelen
= 0x3fd00000,
96 /* The static hash below does the following:
97 * 1st Row: Kernel Offset
98 * 2nd Row: Ramdisk Offset
100 * 4th Row: ? Unused/Unknown ?
101 * 5th Row: ? Unused/Unknown ?
104 .kernel_offset
= 0x10000,
105 .ramdisk_offset
= 0x3FFC00,
106 .fdt_offset
= 0x0400,
107 .unknown_offset
= 0x0400,
110 /* terminating entry */
117 #define ERR(fmt, ...) do { \
119 fprintf(stderr, "[%s] *** error: " fmt "\n", \
120 progname, ## __VA_ARGS__); \
123 #define ERRS(fmt, ...) do { \
126 fprintf(stderr, "[%s] *** error: " fmt "\n", \
127 progname, ## __VA_ARGS__, strerror(save)); \
130 static const struct board_info
*find_board(const char *id
)
132 const struct board_info
*ret
;
133 const struct board_info
*board
;
136 for (board
= boards
; board
->id
!= NULL
; board
++) {
137 if (strcasecmp(id
, board
->id
) == 0) {
146 static void usage(int status
)
148 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
149 const struct board_info
*board
;
151 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
155 " -B <board> create image for the board specified with <board>\n"
156 " -i <file> read kernel image from the file <file>\n"
157 " -o <file> write output to the file <file>\n"
158 " -s strip padding from the end of the image\n"
159 " -h show this screen\n"
162 fprintf(stream
, "\nBoards:\n");
163 for (board
= boards
; board
->id
!= NULL
; board
++)
164 fprintf(stream
, " %-16s%s\n", board
->id
, board
->description
);
169 void writel(unsigned char *buf
, size_t offset
, uint32_t value
)
171 value
= htonl(value
);
172 memcpy(buf
+ offset
, &value
, sizeof(uint32_t));
175 int main(int argc
, char *argv
[])
177 int ret
= EXIT_FAILURE
;
180 unsigned char *kernel
;
183 bool strip_padding
= false;
184 char *ofname
= NULL
, *ifname
= NULL
;
187 progname
= basename(argv
[0]);
192 c
= getopt(argc
, argv
, "B:i:o:sh");
207 strip_padding
= true;
218 if (board_id
== NULL
) {
219 ERR("no board specified");
223 board
= find_board(board_id
);
225 ERR("unknown board \"%s\"", board_id
);
229 if (ifname
== NULL
) {
230 ERR("no input file specified");
234 if (ofname
== NULL
) {
235 ERR("no output file specified");
239 in
= fopen(ifname
, "r");
241 ERRS("could not open \"%s\" for reading: %s", ifname
);
245 buflen
= board
->imagelen
;
246 kspace
= buflen
- HDR_LENGTH
;
248 /* Get kernel length */
249 fseek(in
, 0, SEEK_END
);
254 ERR("file \"%s\" is too big - max size: 0x%08lX\n",
259 /* If requested, resize buffer to remove padding */
261 buflen
= klen
+ HDR_LENGTH
;
263 /* Allocate and initialize buffer for final image */
264 buf
= malloc(buflen
);
266 ERRS("no memory for buffer: %s\n");
269 memset(buf
, PADDING_BYTE
, buflen
);
272 kernel
= buf
+ HDR_LENGTH
;
273 fread(kernel
, klen
, 1, in
);
275 /* Write magic values */
276 writel(buf
, HDR_OFF_MAGIC1
, board
->magic1
);
277 writel(buf
, HDR_OFF_MAGIC2
, board
->magic2
);
278 writel(buf
, HDR_OFF_MAGIC3
, board
->magic3
);
280 /* Write header and image length */
281 writel(buf
, HDR_OFF_HDRLEN
, HDR_LENGTH
);
282 writel(buf
, HDR_OFF_IMAGELEN
, klen
);
284 /* Write checksum and static hash */
285 sha1_csum(kernel
, klen
, buf
+ HDR_OFF_CHECKSUM
);
287 switch (board
->magic2
) {
289 writel(buf
, HDR_OFF_KERNEL_OFFSET
, board
->u
.mx60
.kernel_offset
);
290 writel(buf
, HDR_OFF_RAMDISK_OFFSET
, board
->u
.mx60
.ramdisk_offset
);
291 writel(buf
, HDR_OFF_FDT_OFFSET
, board
->u
.mx60
.fdt_offset
),
292 writel(buf
, HDR_OFF_UNKNOWN_OFFSET
, board
->u
.mx60
.unknown_offset
);
296 memcpy(buf
+ HDR_OFF_STATICHASH
, board
->u
.statichash
, 20);
300 /* Save finished image */
301 out
= fopen(ofname
, "w");
303 ERRS("could not open \"%s\" for writing: %s", ofname
);
306 fwrite(buf
, buflen
, 1, out
);