OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Make CHK Image |
||
3 | * |
||
4 | * This utility creates Netgear .chk files. |
||
5 | * |
||
6 | * Copyright (C) 2008 Dave C. Reeve <Dave.Reeve@dreeve.org> |
||
7 | * |
||
8 | * This program is free software; you can redistribute it and/or modify |
||
9 | * it under the terms of the GNU General Public License as published by |
||
10 | * the Free Software Foundation; either version 2 of the License, or |
||
11 | * (at your option) any later version. |
||
12 | * |
||
13 | * This program is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | * GNU General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU General Public License along |
||
19 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
21 | */ |
||
22 | #include <stdio.h> |
||
23 | #include <stdlib.h> |
||
24 | #include <string.h> |
||
25 | #include <stdarg.h> |
||
26 | #include <errno.h> |
||
27 | #include <arpa/inet.h> |
||
28 | #include <unistd.h> |
||
29 | |||
30 | #define BUF_LEN (2048) |
||
31 | |||
32 | #define MAX_BOARD_ID_LEN (64) |
||
33 | |||
34 | /* |
||
35 | * Note on the reserved field of the chk_header: |
||
36 | * OFW naming scheme is typically: DEVICENAME-VA.B.C.D_E.F.G.chk, with A-G |
||
37 | * between 0 and 255. For instance: EX3700_EX3800-V1.0.0.58_1.0.38.chk |
||
38 | * The reserved field works like this: |
||
39 | * reserved[0]: region code. 1 for WW (WorldWide) and 2 for NA (North America) |
||
40 | * reserved[1]: A |
||
41 | * reserved[2]: B |
||
42 | * reserved[3]: C |
||
43 | * reserved[4]: D |
||
44 | * reserved[5]: E |
||
45 | * reserved[6]: F |
||
46 | * reserved[7]: G |
||
47 | */ |
||
48 | struct chk_header { |
||
49 | uint32_t magic; |
||
50 | uint32_t header_len; |
||
51 | uint8_t reserved[8]; |
||
52 | uint32_t kernel_chksum; |
||
53 | uint32_t rootfs_chksum; |
||
54 | uint32_t kernel_len; |
||
55 | uint32_t rootfs_len; |
||
56 | uint32_t image_chksum; |
||
57 | uint32_t header_chksum; |
||
58 | /* char board_id[] - upto MAX_BOARD_ID_LEN */ |
||
59 | }; |
||
60 | |||
61 | static void __attribute__ ((format (printf, 2, 3))) |
||
62 | fatal_error (int maybe_errno, const char * format, ...) |
||
63 | { |
||
64 | va_list ap; |
||
65 | |||
66 | fprintf (stderr, "mkchkimg: "); |
||
67 | va_start (ap, format); |
||
68 | vfprintf (stderr, format, ap); |
||
69 | va_end (ap); |
||
70 | |||
71 | if (maybe_errno) { |
||
72 | fprintf (stderr, ": %s\n", strerror (maybe_errno)); |
||
73 | } else { |
||
74 | fprintf (stderr, "\n"); |
||
75 | } |
||
76 | |||
77 | exit (EXIT_FAILURE); |
||
78 | } |
||
79 | |||
80 | static void __attribute__ ((format (printf, 1, 2))) |
||
81 | message (const char * format, ...) |
||
82 | { |
||
83 | va_list ap; |
||
84 | |||
85 | fprintf (stderr, "mkchkimg: "); |
||
86 | va_start (ap, format); |
||
87 | vfprintf (stderr, format, ap); |
||
88 | va_end (ap); |
||
89 | fprintf (stderr, "\n"); |
||
90 | } |
||
91 | |||
92 | struct ngr_checksum { |
||
93 | uint32_t c0; |
||
94 | uint32_t c1; |
||
95 | }; |
||
96 | |||
97 | static inline void |
||
98 | netgear_checksum_init (struct ngr_checksum * c) |
||
99 | { |
||
100 | c->c0 = c->c1 = 0; |
||
101 | } |
||
102 | |||
103 | static inline void |
||
104 | netgear_checksum_add (struct ngr_checksum * c, unsigned char * buf, size_t len) |
||
105 | { |
||
106 | size_t i; |
||
107 | |||
108 | for (i=0; i<len; i++) { |
||
109 | c->c0 += buf[i] & 0xff; |
||
110 | c->c1 += c->c0; |
||
111 | } |
||
112 | } |
||
113 | |||
114 | static inline unsigned long |
||
115 | netgear_checksum_fini (struct ngr_checksum * c) |
||
116 | { |
||
117 | uint32_t b, checksum; |
||
118 | |||
119 | b = (c->c0 & 65535) + ((c->c0 >> 16) & 65535); |
||
120 | c->c0 = ((b >> 16) + b) & 65535; |
||
121 | b = (c->c1 & 65535) + ((c->c1 >> 16) & 65535); |
||
122 | c->c1 = ((b >> 16) + b) & 65535; |
||
123 | checksum = ((c->c1 << 16) | c->c0); |
||
124 | return checksum; |
||
125 | } |
||
126 | |||
127 | static void |
||
128 | print_help (void) |
||
129 | { |
||
130 | fprintf (stderr, "Usage: mkchkimg -o output -k kernel [-f filesys] [-b board_id] [-r region]\n"); |
||
131 | } |
||
132 | |||
133 | int |
||
134 | main (int argc, char * argv[]) |
||
135 | { |
||
136 | int opt; |
||
137 | char * ptr; |
||
138 | size_t len; |
||
139 | size_t header_len; |
||
140 | struct chk_header * hdr; |
||
141 | struct ngr_checksum chk_part, chk_whole; |
||
142 | char buf[BUF_LEN]; |
||
143 | char * output_file, * kern_file, * fs_file; |
||
144 | FILE * out_fp, * kern_fp, * fs_fp; |
||
145 | char * board_id; |
||
146 | unsigned long region; |
||
147 | |||
148 | /* Default values */ |
||
149 | board_id = "U12H072T00_NETGEAR"; |
||
150 | region = 1; /* 1=WW, 2=NA */ |
||
151 | output_file = NULL; |
||
152 | kern_file = NULL; |
||
153 | fs_file = NULL; |
||
154 | fs_fp = NULL; |
||
155 | |||
156 | while ((opt = getopt (argc, argv, ":b:r:k:f:o:h")) != -1) { |
||
157 | switch (opt) { |
||
158 | case 'b': |
||
159 | /* Board Identity */ |
||
160 | if (strlen (optarg) > MAX_BOARD_ID_LEN) { |
||
161 | fatal_error (0, "Board lenght exceeds %d", |
||
162 | MAX_BOARD_ID_LEN); |
||
163 | } |
||
164 | board_id = optarg; |
||
165 | break; |
||
166 | |||
167 | case 'r': |
||
168 | /* Region */ |
||
169 | errno = 0; |
||
170 | region = strtoul (optarg, &ptr, 0); |
||
171 | if (errno || ptr==optarg || *ptr!='\0') { |
||
172 | fatal_error (0, "Cannot parse region %s", optarg); |
||
173 | } |
||
174 | if (region > 0xff) { |
||
175 | fatal_error (0, "Region cannot exceed 0xff"); |
||
176 | } |
||
177 | break; |
||
178 | |||
179 | case 'k': |
||
180 | /* Kernel */ |
||
181 | kern_file = optarg; |
||
182 | break; |
||
183 | |||
184 | case 'f': |
||
185 | /* Filing System */ |
||
186 | fs_file = optarg; |
||
187 | break; |
||
188 | |||
189 | case 'o': |
||
190 | /* Output file */ |
||
191 | output_file = optarg; |
||
192 | break; |
||
193 | |||
194 | case 'h': |
||
195 | print_help (); |
||
196 | return EXIT_SUCCESS; |
||
197 | |||
198 | case ':': |
||
199 | print_help (); |
||
200 | fatal_error (0, "Option -%c missing argument", optopt); |
||
201 | break; |
||
202 | |||
203 | case '?': |
||
204 | print_help (); |
||
205 | fatal_error (0, "Unknown argument -%c", optopt); |
||
206 | break; |
||
207 | |||
208 | default: |
||
209 | break; |
||
210 | } |
||
211 | } |
||
212 | |||
213 | /* Check we have all the options expected */ |
||
214 | if (!kern_file) { |
||
215 | print_help (); |
||
216 | fatal_error (0, "Kernel file expected"); |
||
217 | } |
||
218 | if (!output_file) { |
||
219 | print_help (); |
||
220 | fatal_error (0, "Output file required"); |
||
221 | } |
||
222 | message ("Netgear CHK writer - v0.1"); |
||
223 | |||
224 | /* Open the input file */ |
||
225 | kern_fp = fopen (kern_file, "r"); |
||
226 | if (!kern_fp) { |
||
227 | fatal_error (errno, "Cannot open %s", kern_file); |
||
228 | } |
||
229 | |||
230 | /* Open the fs file, if specified */ |
||
231 | if (fs_file) { |
||
232 | fs_fp = fopen (fs_file, "r"); |
||
233 | if (!fs_fp) { |
||
234 | fatal_error (errno, "Cannot open %s", fs_file); |
||
235 | } |
||
236 | } |
||
237 | |||
238 | /* Open the output file */ |
||
239 | out_fp = fopen (output_file, "w+"); |
||
240 | if (!out_fp) { |
||
241 | fatal_error (errno, "Cannot open %s", output_file); |
||
242 | } |
||
243 | |||
244 | /* Write zeros when the chk header will be */ |
||
245 | buf[0] = '\0'; |
||
246 | header_len = sizeof (struct chk_header) + strlen (board_id); |
||
247 | if (fwrite (buf, 1, header_len, out_fp) != header_len) { |
||
248 | fatal_error (errno, "Cannot write header"); |
||
249 | } |
||
250 | |||
251 | /* Allocate storage for header, we fill in as we go */ |
||
252 | hdr = malloc (sizeof (struct chk_header)); |
||
253 | if (!hdr) { |
||
254 | fatal_error (0, "malloc failed"); |
||
255 | } |
||
256 | bzero (hdr, sizeof (struct chk_header)); |
||
257 | |||
258 | /* Fill in known values */ |
||
259 | hdr->magic = htonl (0x2a23245e); |
||
260 | hdr->header_len = htonl(header_len); |
||
261 | hdr->reserved[0] = (unsigned char)(region & 0xff); |
||
262 | hdr->reserved[1] = 1; /* Major */ |
||
263 | hdr->reserved[2] = 1; /* Minor */ |
||
264 | hdr->reserved[3] = 99; /* Build */ |
||
265 | hdr->reserved[4] = 0; |
||
266 | hdr->reserved[5] = 0; |
||
267 | hdr->reserved[6] = 0; |
||
268 | hdr->reserved[7] = 0; |
||
269 | message (" Board Id: %s", board_id); |
||
270 | message (" Region: %s", region == 1 ? "World Wide (WW)" |
||
271 | : (region == 2 ? "North America (NA)" : "Unknown")); |
||
272 | |||
273 | /* Copy the trx file, calculating the checksum as we go */ |
||
274 | netgear_checksum_init (&chk_part); |
||
275 | netgear_checksum_init (&chk_whole); |
||
276 | while (!feof (kern_fp)) { |
||
277 | len = fread (buf, 1, BUF_LEN, kern_fp); |
||
278 | if (len < 1) { |
||
279 | break; |
||
280 | } |
||
281 | if (fwrite (buf, len, 1, out_fp) != 1) { |
||
282 | fatal_error (errno, "Write error"); |
||
283 | } |
||
284 | hdr->kernel_len += len; |
||
285 | netgear_checksum_add (&chk_part, (unsigned char *)buf, len); |
||
286 | netgear_checksum_add (&chk_whole, (unsigned char *)buf, len); |
||
287 | } |
||
288 | hdr->kernel_chksum = netgear_checksum_fini (&chk_part); |
||
289 | message (" Kernel Len: %u", hdr->kernel_len); |
||
290 | message ("Kernel Checksum: 0x%08x", hdr->kernel_chksum); |
||
291 | hdr->kernel_len = htonl (hdr->kernel_len); |
||
292 | hdr->kernel_chksum = htonl (hdr->kernel_chksum); |
||
293 | |||
294 | /* Now copy the root fs, calculating the checksum as we go */ |
||
295 | if (fs_fp) { |
||
296 | netgear_checksum_init (&chk_part); |
||
297 | while (!feof (fs_fp)) { |
||
298 | len = fread (buf, 1, BUF_LEN, fs_fp); |
||
299 | if (len < 1) { |
||
300 | break; |
||
301 | } |
||
302 | if (fwrite (buf, len, 1, out_fp) != 1) { |
||
303 | fatal_error (errno, "Write error"); |
||
304 | } |
||
305 | hdr->rootfs_len += len; |
||
306 | netgear_checksum_add (&chk_part, (unsigned char *)buf, len); |
||
307 | netgear_checksum_add (&chk_whole, (unsigned char *)buf, len); |
||
308 | } |
||
309 | hdr->rootfs_chksum = (netgear_checksum_fini (&chk_part)); |
||
310 | message (" Rootfs Len: %u", hdr->rootfs_len); |
||
311 | message ("Rootfs Checksum: 0x%08x", hdr->rootfs_chksum); |
||
312 | hdr->rootfs_len = htonl (hdr->rootfs_len); |
||
313 | hdr->rootfs_chksum = htonl (hdr->rootfs_chksum); |
||
314 | } |
||
315 | |||
316 | /* Calcautate the image checksum */ |
||
317 | hdr->image_chksum = netgear_checksum_fini (&chk_whole); |
||
318 | message (" Image Checksum: 0x%08x", hdr->image_chksum); |
||
319 | hdr->image_chksum = htonl (hdr->image_chksum); |
||
320 | |||
321 | /* Calculate the header checksum */ |
||
322 | netgear_checksum_init (&chk_part); |
||
323 | netgear_checksum_add (&chk_part, (unsigned char *)hdr, |
||
324 | sizeof (struct chk_header)); |
||
325 | netgear_checksum_add (&chk_part, (unsigned char *)board_id, |
||
326 | strlen (board_id)); |
||
327 | hdr->header_chksum = htonl (netgear_checksum_fini (&chk_part)); |
||
328 | |||
329 | /* Finally rewind the output and write headers */ |
||
330 | rewind (out_fp); |
||
331 | if (fwrite (hdr, sizeof (struct chk_header), 1, out_fp) != 1) { |
||
332 | fatal_error (errno, "Cannot write header"); |
||
333 | } |
||
334 | if (fwrite (board_id, strlen (board_id), 1, out_fp) != 1) { |
||
335 | fatal_error (errno, "Cannot write board id"); |
||
336 | } |
||
337 | |||
338 | /* Success */ |
||
339 | return EXIT_SUCCESS; |
||
340 | } |
||
341 |