1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
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>
19 #include <arpa/inet.h>
23 #define PADDING_BYTE 0xff
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
44 unsigned char statichash
[20];
46 uint32_t kernel_offset
;
47 uint32_t ramdisk_offset
;
49 uint32_t unknown_offset
;
59 static char *progname
;
61 static char *board_id
;
62 static const struct board_info
*board
;
64 static const struct board_info boards
[] = {
67 .description
= "Meraki MR18 Access Point",
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},
77 .description
= "Meraki MR24 Access Point",
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},
87 .description
= "Meraki MX60/MX60W Security Appliance",
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
96 * 4th Row: ? Unused/Unknown ?
97 * 5th Row: ? Unused/Unknown ?
100 .kernel_offset
= 0x10000,
101 .ramdisk_offset
= 0x3FFC00,
102 .fdt_offset
= 0x0400,
103 .unknown_offset
= 0x0400,
106 /* terminating entry */
113 #define ERR(fmt, ...) do { \
115 fprintf(stderr, "[%s] *** error: " fmt "\n", \
116 progname, ## __VA_ARGS__); \
119 #define ERRS(fmt, ...) do { \
122 fprintf(stderr, "[%s] *** error: " fmt "\n", \
123 progname, ## __VA_ARGS__, strerror(save)); \
126 static const struct board_info
*find_board(const char *id
)
128 const struct board_info
*ret
;
129 const struct board_info
*board
;
132 for (board
= boards
; board
->id
!= NULL
; board
++) {
133 if (strcasecmp(id
, board
->id
) == 0) {
142 static void usage(int status
)
144 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
145 const struct board_info
*board
;
147 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
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"
158 fprintf(stream
, "\nBoards:\n");
159 for (board
= boards
; board
->id
!= NULL
; board
++)
160 fprintf(stream
, " %-16s%s\n", board
->id
, board
->description
);
165 void writel(unsigned char *buf
, size_t offset
, uint32_t value
)
167 value
= htonl(value
);
168 memcpy(buf
+ offset
, &value
, sizeof(uint32_t));
171 int main(int argc
, char *argv
[])
173 int ret
= EXIT_FAILURE
;
176 unsigned char *kernel
;
179 bool strip_padding
= false;
180 char *ofname
= NULL
, *ifname
= NULL
;
183 progname
= basename(argv
[0]);
188 c
= getopt(argc
, argv
, "B:i:o:sh");
203 strip_padding
= true;
214 if (board_id
== NULL
) {
215 ERR("no board specified");
219 board
= find_board(board_id
);
221 ERR("unknown board \"%s\"", board_id
);
225 if (ifname
== NULL
) {
226 ERR("no input file specified");
230 if (ofname
== NULL
) {
231 ERR("no output file specified");
235 in
= fopen(ifname
, "r");
237 ERRS("could not open \"%s\" for reading: %s", ifname
);
241 buflen
= board
->imagelen
;
242 kspace
= buflen
- HDR_LENGTH
;
244 /* Get kernel length */
245 fseek(in
, 0, SEEK_END
);
250 ERR("file \"%s\" is too big - max size: 0x%08lX\n",
255 /* If requested, resize buffer to remove padding */
257 buflen
= klen
+ HDR_LENGTH
;
259 /* Allocate and initialize buffer for final image */
260 buf
= malloc(buflen
);
262 ERRS("no memory for buffer: %s\n");
265 memset(buf
, PADDING_BYTE
, buflen
);
268 kernel
= buf
+ HDR_LENGTH
;
269 fread(kernel
, klen
, 1, in
);
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
);
276 /* Write header and image length */
277 writel(buf
, HDR_OFF_HDRLEN
, HDR_LENGTH
);
278 writel(buf
, HDR_OFF_IMAGELEN
, klen
);
280 /* Write checksum and static hash */
281 sha1_csum(kernel
, klen
, buf
+ HDR_OFF_CHECKSUM
);
283 switch (board
->magic2
) {
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
);
292 memcpy(buf
+ HDR_OFF_STATICHASH
, board
->u
.statichash
, 20);
296 /* Save finished image */
297 out
= fopen(ofname
, "w");
299 ERRS("could not open \"%s\" for writing: %s", ofname
);
302 fwrite(buf
, buflen
, 1, out
);