OpenWrt – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * jboot_config_read
3 *
4 * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
5 *
6 * This tool is based on mkdlinkfw.
7 * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
8 * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
9 * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2 of the License, or (at your option)
14 * any later version.
15 */
16  
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <string.h>
21 #include <unistd.h> /* for unlink() */
22 #include <libgen.h>
23 #include <getopt.h> /* for getopt() */
24 #include <stdarg.h>
25 #include <stdbool.h>
26 #include <endian.h>
27 #include <errno.h>
28 #include <sys/stat.h>
29  
30  
31  
32 #define ERR(fmt, ...) do { \
33 fflush(0); \
34 fprintf(stderr, "[%s] *** error: " fmt "\n", \
35 progname, ## __VA_ARGS__); \
36 } while (0)
37  
38 #define ERRS(fmt, ...) do { \
39 int save = errno; \
40 fflush(0); \
41 fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
42 progname, ## __VA_ARGS__, strerror(save)); \
43 } while (0)
44  
45 #define VERBOSE(fmt, ...) do { \
46 if (verbose) { \
47 fprintf(stdout, "[%s] " fmt "\n", progname, ## __VA_ARGS__); \
48 } \
49 } while (0)
50  
51 #define STAG_SIZE 16
52 #define STAG_MAGIC 0x2B24
53 #define STAG_ID 0x02
54  
55 #define CSXF_SIZE 16
56 #define CSXF_MAGIC 0x5343
57  
58 #define MAX_DATA_HEADER 128
59 #define DATA_HEADER_UNKNOWN 0x8000
60 #define DATA_HEADER_EEPROM 0xF5
61 #define DATA_HEADER_CONFIG 0x42
62 #define DATA_HEADER_SIZE 6
63  
64 #define DATA_HEADER_ID_MAC 0x30
65 #define DATA_HEADER_ID_CAL 0x0
66  
67 /* ARM update header 2.0
68 * used only in factory images to erase and flash selected area
69 */
70 struct stag_header { /* used only of sch2 wrapped kernel data */
71 uint8_t cmark; /* in factory 0xFF ,in sysuograde must be the same as id */
72 uint8_t id; /* 0x04 */
73 uint16_t magic; /* magic 0x2B24 */
74 uint32_t time_stamp; /* timestamp calculated in jboot way */
75 uint32_t image_length; /* lentgh of kernel + sch2 header */
76 uint16_t image_checksum; /* negated jboot_checksum of sch2 + kernel */
77 uint16_t tag_checksum; /* negated jboot_checksum of stag header data */
78 };
79  
80 struct csxf_header {
81 uint16_t magic; /* 0x5343, 'CS' in little endian */
82 uint16_t checksum; /* checksum, include header & body */
83 uint32_t body_length; /* length of body */
84 uint8_t body_encoding; /* encoding method of body */
85 uint8_t reserved[3];
86 uint32_t raw_length; /* length of body before encoded */
87 };
88  
89 struct data_header {
90 uint8_t id;
91 uint8_t type; /* 0x42xx for config 0xF5xx for eeprom */
92 uint16_t unknown;
93 uint16_t length; /* length of body */
94 uint8_t data[]; /* encoding method of body */
95 };
96  
97 /* globals */
98  
99 char *ofname;
100 char *ifname;
101 char *progname;
102  
103 uint8_t *buffer;
104 uint32_t config_size;
105  
106 uint32_t start_offset;
107 uint8_t mac_duplicate;
108 uint8_t mac_print;
109 uint8_t print_data;
110 uint8_t verbose;
111  
112 static void usage(int status)
113 {
114 fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
115 fprintf(stderr,
116 "\n"
117 "Options:\n"
118 " -i <file> config partition file <file>\n"
119 " -m print mac address\n"
120 " -e <file> save eeprom calibration data image to the file <file>\n"
121 " -o <offset> set start offset to <ofset>\n"
122 " -p print config data\n"
123 " -v verbose\n"
124 " -h show this screen\n");
125  
126 exit(status);
127 }
128  
129 static void print_data_header(struct data_header *printed_header)
130 {
131 printf("id: 0x%02X "
132 "type: 0x%02X "
133 "unknown: 0x%04X "
134 "length: 0x%04X\n"
135 "data: ",
136 printed_header->id,
137 printed_header->type,
138 printed_header->unknown, printed_header->length);
139  
140 for (uint16_t i = 0; i < printed_header->length; i++)
141 printf("%02X ", printed_header->data[i]);
142  
143 printf("\n");
144  
145 }
146  
147 static uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size)
148 {
149 uint32_t counter = start_val;
150 uint16_t *ptr = data;
151  
152 while (size > 1) {
153 counter += *ptr;
154 ++ptr;
155 while (counter >> 16)
156 counter = (uint16_t) counter + (counter >> 16);
157 size -= 2;
158 }
159 if (size > 0) {
160 counter += *(uint8_t *) ptr;
161 counter -= 0xFF;
162 }
163 while (counter >> 16)
164 counter = (uint16_t) counter + (counter >> 16);
165 return counter;
166 }
167  
168 static int find_header(uint8_t *buf, uint32_t buf_size,
169 struct data_header **data_table)
170 {
171 uint8_t *tmp_buf = buf + start_offset;
172 uint8_t tmp_hdr[4] = { STAG_ID, STAG_ID, (STAG_MAGIC & 0xFF), (STAG_MAGIC >> 8) };
173 struct csxf_header *tmp_csxf_header;
174 uint16_t tmp_checksum = 0;
175 uint16_t data_header_counter = 0;
176 int ret = EXIT_FAILURE;
177  
178 VERBOSE("Looking for STAG header!");
179  
180 while ((uint32_t) tmp_buf - (uint32_t) buf <= buf_size) {
181 if (!memcmp(tmp_buf, tmp_hdr, 4)) {
182 if (((struct stag_header *)tmp_buf)->tag_checksum ==
183 (uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf,
184 STAG_SIZE - 2)) {
185 VERBOSE("Found proper STAG header at: 0x%X.",
186 tmp_buf - buf);
187 break;
188 }
189 }
190 tmp_buf++;
191 }
192  
193 tmp_csxf_header = (struct csxf_header *)(tmp_buf + STAG_SIZE);
194 if (tmp_csxf_header->magic != CSXF_MAGIC) {
195 ERR("CSXF magic incorrect! 0x%X != 0x%X",
196 tmp_csxf_header->magic, CSXF_MAGIC);
197 goto out;
198 }
199 VERBOSE("CSXF magic ok.");
200 tmp_checksum = tmp_csxf_header->checksum;
201 tmp_csxf_header->checksum = 0;
202  
203 tmp_csxf_header->checksum =
204 (uint16_t) ~jboot_checksum(0, (uint16_t *) (tmp_buf + STAG_SIZE),
205 tmp_csxf_header->raw_length +
206 CSXF_SIZE);
207  
208 if (tmp_checksum != tmp_csxf_header->checksum) {
209 ERR("CSXF checksum incorrect! Stored: 0x%X Calculated: 0x%X",
210 tmp_checksum, tmp_csxf_header->checksum);
211 goto out;
212 }
213 VERBOSE("CSXF image checksum ok.");
214  
215 tmp_buf = tmp_buf + STAG_SIZE + CSXF_SIZE;
216  
217 while ((uint32_t) tmp_buf - (uint32_t) buf <= buf_size) {
218  
219 struct data_header *tmp_data_header =
220 (struct data_header *)tmp_buf;
221  
222 if (tmp_data_header->unknown != DATA_HEADER_UNKNOWN) {
223 tmp_buf++;
224 continue;
225 }
226 if (tmp_data_header->type != DATA_HEADER_EEPROM
227 && tmp_data_header->type != DATA_HEADER_CONFIG) {
228 tmp_buf++;
229 continue;
230 }
231  
232 data_table[data_header_counter] = tmp_data_header;
233 tmp_buf +=
234 DATA_HEADER_SIZE + data_table[data_header_counter]->length;
235 data_header_counter++;
236  
237 }
238  
239 ret = data_header_counter;
240  
241 out:
242 return ret;
243 }
244  
245 static int read_file(char *file_name)
246 {
247 int ret = EXIT_FAILURE;
248 uint32_t file_size = 0;
249 FILE *fp;
250  
251 fp = fopen(file_name, "r");
252  
253 if (!fp) {
254 ERR("Failed to open config input file %s", file_name);
255 goto out;
256 }
257  
258 fseek(fp, 0L, SEEK_END);
259 file_size = ftell(fp);
260 fseek(fp, 0L, SEEK_SET);
261  
262 buffer = malloc(file_size);
263 VERBOSE("Allocated %d bytes.", file_size);
264  
265 if (fread(buffer, 1, file_size, fp) != file_size) {
266 ERR("Failed to read config input file %s", file_name);
267 goto out_free_buf;
268 }
269  
270 VERBOSE("Read %d bytes of config input file %s", file_size, file_name);
271 config_size = file_size;
272 ret = EXIT_SUCCESS;
273 goto out;
274  
275 out_free_buf:
276 free(buffer);
277 fclose(fp);
278 out:
279 return ret;
280 }
281  
282 static int write_file(const char *ofname, const uint8_t *data, int len)
283 {
284 FILE *f;
285 int ret = EXIT_FAILURE;
286  
287 f = fopen(ofname, "w");
288 if (f == NULL) {
289 ERRS("could not open \"%s\" for writing", ofname);
290 goto out;
291 }
292  
293 errno = 0;
294 fwrite(data, len, 1, f);
295 if (errno) {
296 ERRS("unable to write output file");
297 goto out_flush;
298 }
299  
300 VERBOSE("firmware file \"%s\" completed", ofname);
301  
302 ret = EXIT_SUCCESS;
303  
304 out_flush:
305 fflush(f);
306 fclose(f);
307 if (ret != EXIT_SUCCESS)
308 unlink(ofname);
309 out:
310 return ret;
311 }
312  
313 static void print_mac(struct data_header **data_table, int cnt)
314 {
315  
316 for (int i = 0; i < cnt; i++) {
317 if (data_table[i]->type == DATA_HEADER_CONFIG
318 && data_table[i]->id == DATA_HEADER_ID_MAC) {
319 int j;
320 for (j = 0; j < 5; j++)
321 printf("%02x:", data_table[i]->data[j]);
322 printf("%02x\n", data_table[i]->data[j]);
323 }
324  
325 }
326  
327 }
328  
329 static int write_eeprom(struct data_header **data_table, int cnt)
330 {
331 int ret = EXIT_FAILURE;
332  
333 for (int i = 0; i < cnt; i++) {
334 if (data_table[i]->type == DATA_HEADER_EEPROM
335 && data_table[i]->id == DATA_HEADER_ID_CAL) {
336 ret =
337 write_file(ofname, data_table[i]->data,
338 data_table[i]->length);
339 break;
340 }
341  
342 }
343  
344 return ret;
345 }
346  
347 int main(int argc, char *argv[])
348 {
349 int ret = EXIT_FAILURE;
350 int configs_counter = 0;
351 struct data_header *configs_table[MAX_DATA_HEADER];
352 buffer = NULL;
353 config_size = 0;
354  
355 progname = basename(argv[0]);
356 start_offset = 0;
357 mac_print = 0;
358 print_data = 0;
359 verbose = 0;
360 ofname = NULL;
361 ifname = NULL;
362  
363 while (1) {
364 int c;
365  
366 c = getopt(argc, argv, "de:hi:mo:pv");
367 if (c == -1)
368 break;
369  
370 switch (c) {
371 case 'm':
372 mac_print = 1;
373 break;
374 case 'i':
375 ifname = optarg;
376 break;
377 case 'e':
378 ofname = optarg;
379 break;
380 case 'o':
381 sscanf(optarg, "0x%x", &start_offset);
382 break;
383 case 'p':
384 print_data = 1;
385 break;
386 case 'v':
387 verbose = 1;
388 VERBOSE("Enable verbose!");
389 break;
390 default:
391 usage(EXIT_FAILURE);
392 break;
393 }
394 }
395  
396 if (!ifname)
397 usage(EXIT_FAILURE);
398  
399 ret = read_file(ifname);
400  
401 if (ret || config_size <= 0)
402 goto out;
403  
404 configs_counter = find_header(buffer, config_size, configs_table);
405  
406 if (configs_counter <= 0)
407 goto out_free_buf;
408  
409 if (print_data || verbose) {
410 for (int i = 0; i < configs_counter; i++)
411 print_data_header(configs_table[i]);
412 }
413  
414 if (mac_print)
415 print_mac(configs_table, configs_counter);
416  
417 ret = EXIT_SUCCESS;
418  
419 if (ofname)
420 ret = write_eeprom(configs_table, configs_counter);
421  
422 out_free_buf:
423 free(buffer);
424 out:
425 return ret;
426  
427 }