blob: 77d7aef1428a2655aee2638127af0ec2cf3875df [file] [log] [blame]
David Ng3556e582012-07-27 23:52:11 +00001/*
2 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define _GNU_SOURCE
31#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <dirent.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <getopt.h>
40#include <errno.h>
41#include <unistd.h>
42
43#define QCDT_MAGIC "QCDT" /* Master DTB magic */
44#define QCDT_VERSION 1 /* QCDT version */
45#define QCDT_VERSION_NEW 2 /* QCDT version */
46
47#define QCDT_DT_TAG "qcom,msm-id = <"
48#define QCDT_BOARD_TAG "qcom,board-id = <"
49
50#define PAGE_SIZE_DEF 2048
51#define PAGE_SIZE_MAX (1024*1024)
52
53#define log_err(x...) printf(x)
54#define log_info(x...) printf(x)
55#define log_dbg(x...) { if (verbose) printf(x); }
56
57#define COPY_BLK 1024 /* File copy block size */
58
59#define RC_SUCCESS 0
60#define RC_ERROR -1
61
62struct chipInfo_t {
63 uint32_t chipset;
64 uint32_t platform;
65 uint32_t subtype;
66 uint32_t revNum;
67 uint32_t dtb_size;
68 char *dtb_file;
69 struct chipInfo_t *prev;
70 struct chipInfo_t *next;
71 struct chipInfo_t *master;
72 int wroteDtb;
73 uint32_t master_offset;
74 struct chipInfo_t *t_next;
75};
76
77struct chipInfo_t *chip_list;
78
79struct chipId_t {
80 uint32_t chipset;
81 uint32_t revNum;
82 struct chipId_t *next;
83 struct chipId_t *t_next;
84};
85
86struct chipSt_t {
87 uint32_t platform;
88 uint32_t subtype;
89 struct chipSt_t *next;
90 struct chipSt_t *t_next;
91};
92
93char *input_dir;
94char *output_file;
95char *dtc_path;
h8rift09db8b22014-04-07 22:10:33 -040096char *dt_tag = QCDT_DT_TAG;
David Ng3556e582012-07-27 23:52:11 +000097int verbose;
98int page_size = PAGE_SIZE_DEF;
99int force_v2;
100
101
102void print_help()
103{
104 log_info("dtbTool version %d (kinda :) )\n", QCDT_VERSION);
105 log_info("dtbTool [options] -o <output file> <input DTB path>\n");
106 log_info(" options:\n");
107 log_info(" --output-file/-o output file\n");
108 log_info(" --dtc-path/-p path to dtc\n");
109 log_info(" --page-size/-s page size in bytes\n");
h8rift09db8b22014-04-07 22:10:33 -0400110 log_info(" --dt-tag/-d alternate QCDT_DT_TAG\n");
David Ng3556e582012-07-27 23:52:11 +0000111 log_info(" --verbose/-v verbose\n");
112 log_info(" --force-v2/-2 use dtb v2 format\n");
113 log_info(" --help/-h this help screen\n");
114}
115
116int parse_commandline(int argc, char *const argv[])
117{
118 int c;
119
120 struct option long_options[] = {
121 {"output-file", 1, 0, 'o'},
122 {"dtc-path", 1, 0, 'p'},
123 {"page-size", 1, 0, 's'},
h8rift09db8b22014-04-07 22:10:33 -0400124 {"dt-tag", 1, 0, 'd'},
David Ng3556e582012-07-27 23:52:11 +0000125 {"verbose", 0, 0, 'v'},
126 {"help", 0, 0, 'h'},
127 {"force-v2", 0, 0, '2'},
128 {0, 0, 0, 0}
129 };
130
h8rift09db8b22014-04-07 22:10:33 -0400131 while ((c = getopt_long(argc, argv, "-o:p:s:d:vh2", long_options, NULL))
David Ng3556e582012-07-27 23:52:11 +0000132 != -1) {
133 switch (c) {
134 case 1:
135 if (!input_dir)
136 input_dir = optarg;
137 break;
138 case 'o':
139 output_file = optarg;
140 break;
141 case 'p':
142 dtc_path = optarg;
143 break;
144 case 's':
145 page_size = atoi(optarg);
146 if ((page_size <= 0) || (page_size > (PAGE_SIZE_MAX))) {
147 log_err("Invalid page size (> 0 and <=1MB\n");
148 return RC_ERROR;
149 }
150 break;
h8rift09db8b22014-04-07 22:10:33 -0400151 case 'd':
152 dt_tag = optarg;
153 break;
David Ng3556e582012-07-27 23:52:11 +0000154 case 'v':
155 verbose = 1;
156 break;
157 case '2':
158 force_v2 = 1;
159 break;
160 case 'h':
161 default:
162 return RC_ERROR;
163 }
164 }
165
166 if (!output_file) {
167 log_err("Output file must be specified\n");
168 return RC_ERROR;
169 }
170
171 if (!input_dir)
172 input_dir = "./";
173
174 if (!dtc_path)
175 dtc_path = "";
176
177 return RC_SUCCESS;
178}
179
180/* Unique entry sorted list add (by chipset->platform->rev) */
181int chip_add(struct chipInfo_t *c)
182{
183 struct chipInfo_t *x = chip_list;
184
185 if (!chip_list) {
186 chip_list = c;
187 c->next = NULL;
188 c->prev = NULL;
189 return RC_SUCCESS;
190 }
191
192 while (1) {
193 if ((c->chipset < x->chipset) ||
194 ((c->chipset == x->chipset) &&
195 ((c->platform < x->platform) ||
196 ((c->platform == x->platform) &&
197 ((c->subtype < x->subtype) ||
198 ((c->subtype == x->subtype) &&
199 (c->revNum < x->revNum))))))) {
200 if (!x->prev) {
201 c->next = x;
202 c->prev = NULL;
203 x->prev = c;
204 chip_list = c;
205 break;
206 } else {
207 c->next = x;
208 c->prev = x->prev;
209 x->prev->next = c;
210 x->prev = c;
211 break;
212 }
213 }
214 if ((c->chipset == x->chipset) &&
215 (c->platform == x->platform) &&
216 (c->subtype == x->subtype) &&
217 (c->revNum == x->revNum)) {
218 return RC_ERROR; /* duplicate */
219 }
220 if (!x->next) {
221 c->prev = x;
222 c->next = NULL;
223 x->next = c;
224 break;
225 }
226 x = x->next;
227 }
228 return RC_SUCCESS;
229}
230
231void chip_deleteall()
232{
233 struct chipInfo_t *c = chip_list, *t;
234
235 while (c) {
236 t = c;
237 c = c->next;
238 if (t->dtb_file)
239 free(t->dtb_file);
240 free(t);
241 }
242}
243
244/*
245 For v1 Extract 'qcom,msm-id' parameter triplet from DTB
246 qcom,msm-id = <x y z>;
247
248 For v2 Extract 'qcom,msm-id', 'qcom,board-id' parameter double from DTB
249 qcom,msm-id = <x z> i.e chipset, revision number;
250 qcom,board-id = <y y'> i.e platform and sub-type;
251 */
252
253struct chipInfo_t *getChipInfo(const char *filename, int *num, uint32_t msmversion)
254{
255
256 const char str1[] = "dtc -I dtb -O dts \"";
257 const char str2[] = "\" 2>&1";
258 char *buf, *pos;
259 char *line = NULL;
260 size_t line_size;
261 FILE *pfile;
262 int llen;
263 struct chipInfo_t *chip = NULL, *tmp;
264 uint32_t data[3] = {0, 0, 0};
265 uint32_t data_st[2] = {0, 0};
266 char *tok, *sptr = NULL;
267 int i, entryValid, entryEnded;
268 int count = 0, count1 = 0, count2 =0;
269 int entryValidST, entryEndedST, entryValidDT, entryEndedDT;
270 struct chipId_t *chipId = NULL, *cId = NULL, *tmp_id = NULL;
271 struct chipSt_t *chipSt = NULL, *cSt = NULL, *tmp_st = NULL;
272
273 line_size = 1024;
274 line = (char *)malloc(line_size);
275 if (!line) {
276 log_err("Out of memory\n");
277 return NULL;
278 }
279
280 llen = sizeof(char) * (strlen(dtc_path) +
281 strlen(str1) +
282 strlen(str2) +
283 strlen(filename) + 1);
284 buf = (char *)malloc(llen);
285 if (!buf) {
286 log_err("Out of memory\n");
287 free(line);
288 return NULL;
289 }
290
291 strncpy(buf, dtc_path, llen);
292 strncat(buf, str1, llen);
293 strncat(buf, filename, llen);
294 strncat(buf, str2, llen);
295
296 pfile = popen(buf, "r");
297 free(buf);
298
299 if (pfile == NULL) {
300 log_err("... skip, fail to decompile dtb\n");
301 } else {
302 /* Find "qcom,msm-id" */
303 while ((llen = getline(&line, &line_size, pfile)) != -1) {
304 if (msmversion == 1) {
h8rift09db8b22014-04-07 22:10:33 -0400305 if ((pos = strstr(line, dt_tag)) != NULL) {
306 pos += strlen(dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000307
Ethan Chenebe5c222014-03-09 10:08:22 -0700308 entryEnded = 0;
309 while (1) {
310 entryValid = 1;
311 for (i = 0; i < 3; i++) {
312 tok = strtok_r(pos, " \t", &sptr);
313 pos = NULL;
314 if (tok != NULL) {
315 if (*tok == '>') {
316 entryEnded = 1;
317 entryValid = 0;
318 break;
319 }
320 data[i] = strtoul(tok, NULL, 0);
321 } else {
322 data[i] = 0;
David Ng3556e582012-07-27 23:52:11 +0000323 entryValid = 0;
Ethan Chenebe5c222014-03-09 10:08:22 -0700324 entryEnded = 1;
325 }
326 }
327 if (entryEnded) {
328 free(line);
329 pclose(pfile);
330 *num = count;
331 return chip;
332 }
333 if (entryValid) {
334 tmp = (struct chipInfo_t *)
335 malloc(sizeof(struct chipInfo_t));
336 if (!tmp) {
337 log_err("Out of memory\n");
David Ng3556e582012-07-27 23:52:11 +0000338 break;
339 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700340 if (!chip) {
341 chip = tmp;
342 chip->t_next = NULL;
343 } else {
344 tmp->t_next = chip->t_next;
345 chip->t_next = tmp;
346 }
347 tmp->chipset = data[0];
348 tmp->platform = data[1];
David Ng3556e582012-07-27 23:52:11 +0000349 tmp->subtype = 0;
Ethan Chenebe5c222014-03-09 10:08:22 -0700350 tmp->revNum = data[2];
351 tmp->dtb_size = 0;
352 tmp->dtb_file = NULL;
353 tmp->master = chip;
354 tmp->wroteDtb = 0;
355 tmp->master_offset = 0;
356 count++;
357 }
David Ng3556e582012-07-27 23:52:11 +0000358 }
David Ng3556e582012-07-27 23:52:11 +0000359
h8rift09db8b22014-04-07 22:10:33 -0400360 log_err("... skip, incorrect '%s' format\n", dt_tag);
Ethan Chenebe5c222014-03-09 10:08:22 -0700361 break;
362 }
David Ng3556e582012-07-27 23:52:11 +0000363 } else if (msmversion == 2) {
h8rift09db8b22014-04-07 22:10:33 -0400364 if ((pos = strstr(line, dt_tag)) != NULL) {
365 pos += strlen(dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000366
367 entryEndedDT = 0;
368 for (;entryEndedDT < 1;) {
369 entryValidDT = 1;
370 for (i = 0; i < 2; i++) {
371 tok = strtok_r(pos, " \t", &sptr);
372 pos = NULL;
373 if (tok != NULL) {
374 if (*tok == '>') {
375 entryEndedDT = 1;
376 entryValidDT = 0;
377 break;
378 }
379 data_st[i] = strtoul(tok, NULL, 0);
380 } else {
381 data_st[i] = 0;
382 entryValidDT = 0;
383 entryEndedDT = 1;
384 }
385 }
386
387 if (entryValidDT) {
388 tmp_id = (struct chipId_t *)
389 malloc(sizeof(struct chipId_t));
390 if (!tmp_id) {
391 log_err("Out of memory\n");
392 break;
393 }
394 if (!chipId) {
395 chipId = tmp_id;
396 cId = tmp_id;
397 chipId->t_next = NULL;
398 } else {
399 tmp_id->t_next = chipId->t_next;
400 chipId->t_next = tmp_id;
401 }
402 tmp_id->chipset = data_st[0];
403 tmp_id->revNum= data_st[1];
404 count1++;
405 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700406 }
David Ng3556e582012-07-27 23:52:11 +0000407 }
408
409 if ((pos = strstr(line,QCDT_BOARD_TAG)) != NULL) {
410 pos += strlen(QCDT_BOARD_TAG);
411 entryEndedST = 0;
412 for (;entryEndedST < 1;) {
413 entryValidST = 1;
414 for (i = 0; i < 2; i++) {
415 tok = strtok_r(pos, " \t", &sptr);
416 pos = NULL;
417 if (tok != NULL) {
418 if (*tok == '>') {
419 entryEndedST = 1;
420 entryValidST = 0;
421 break;
422 }
423 data_st[i] = strtoul(tok, NULL, 0);
424 } else {
425 data_st[i] = 0;
426 entryValidST = 0;
427 entryEndedST = 1;
428 }
429 }
430 if (entryValidST) {
431 tmp_st = (struct chipSt_t *)
432 malloc(sizeof(struct chipSt_t));
433 if (!tmp_st) {
434 log_err("Out of memory\n");
435 break;
436 }
437
438 if (!chipSt) {
439 chipSt = tmp_st;
440 cSt = tmp_st;
441 chipSt->t_next = NULL;
442 } else {
443 tmp_st->t_next = chipSt->t_next;
444 chipSt->t_next = tmp_st;
445 }
446
447 tmp_st->platform = data_st[0];
448 tmp_st->subtype= data_st[1];
449 count2++;
450 }
451 }
452 }
453 }
454 }
455 }
456
Ethan Chenebe5c222014-03-09 10:08:22 -0700457 if (line)
458 free(line);
David Ng3556e582012-07-27 23:52:11 +0000459
460 if (force_v2 || msmversion == 2) {
461
462 if (count1 == 0) {
h8rift09db8b22014-04-07 22:10:33 -0400463 log_err("... skip, incorrect '%s' format\n", dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000464 return NULL;
465 }
466 if (count2 == 0) {
467 log_err("... skip, incorrect '%s' format\n", QCDT_BOARD_TAG);
468 return NULL;
469 }
470
471 tmp_st = cSt;
472 while (cId != NULL) {
473 while (cSt != NULL) {
474 tmp = (struct chipInfo_t *)
475 malloc(sizeof(struct chipInfo_t));
476 if (!tmp) {
477 log_err("Out of memory\n");
478 break;
479 }
480 if (!chip) {
481 chip = tmp;
482 chip->t_next = NULL;
483 } else {
484 tmp->t_next = chip->t_next;
485 chip->t_next = tmp;
486 }
487
488 tmp->chipset = cId->chipset;
489 tmp->platform = cSt->platform;
490 tmp->revNum = cId->revNum;
491 tmp->subtype = cSt->subtype;
492 tmp->dtb_size = 0;
493 tmp->dtb_file = NULL;
494 tmp->master = chip;
495 tmp->wroteDtb = 0;
496 tmp->master_offset = 0;
497
498 cSt = cSt->t_next;
499
500 }
501 cSt = tmp_st;
502 cId = cId->t_next;
503 }
504
505 if (entryEndedST == 1 && entryEndedDT == 1) {
506 pclose(pfile);
507 *num = count1;
508 free(chipSt);
509 free(chipId);
510 return chip;
511 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700512
David Ng3556e582012-07-27 23:52:11 +0000513 } else {
514 pclose(pfile);
515 }
516
517 return NULL;
518}
519
520/* Get the version-id based on dtb files */
521int GetVersionInfo(const char *filename)
522{
523 const char str1[] = "dtc -I dtb -O dts \"";
524 const char str2[] = "\" 2>&1";
525 char *buf, *pos;
526 char *line = NULL;
527 size_t line_size;
528 FILE *pfile;
529 int llen;
530 int v = 1;
531
532 line_size = 1024;
533 line = (char *)malloc(line_size);
534 if (!line) {
535 log_err("Out of memory\n");
536 return 0;
537 }
538
539 llen = sizeof(char) * (strlen(dtc_path) +
540 strlen(str1) +
541 strlen(str2) +
542 strlen(filename) + 1);
543 buf = (char *)malloc(llen);
544 if (!buf) {
545 log_err("Out of memory\n");
546 free(line);
547 return 0;
548 }
549
550 strncpy(buf, dtc_path, llen);
551 strncat(buf, str1, llen);
552 strncat(buf, filename, llen);
553 strncat(buf, str2, llen);
554
555 pfile = popen(buf, "r");
556 free(buf);
557
558 if (pfile == NULL) {
559 log_err("... skip, fail to decompile dtb\n");
560 } else {
561 /* Find the type of version */
562 while ((llen = getline(&line, &line_size, pfile)) != -1) {
563 if ((pos = strstr(line,QCDT_BOARD_TAG)) != NULL) {
564 v = 2;
565 break;
566 }
567 }
568 }
569 if (v == 1)
570 log_info(" Old Version:%d\n", v);
571 free(line);
572
573 return v;
574}
575
576/* Extract 'qcom,msm-id' 'qcom,board-id' parameter from DTB
577 v1 format:
578 qcom,msm-id = <x y z> [, <x2 y2 z2> ...];
579 v2 format:
580 qcom,msm-id = <x z> [, <x2 z2> ...;
581 qcom,board-id = <y y'> [, <y2 y2'> ...;
582 Fields:
583 x = chipset
584 y = platform
585 y' = subtype
586 z = soc rev
587 */
588int main(int argc, char **argv)
589{
590 char buf[COPY_BLK];
591 struct chipInfo_t *chip, *t_chip;
592 struct dirent *dp;
593 FILE *pInputFile;
594 char *filename;
595 int padding;
596 uint8_t *filler = NULL;
597 int numBytesRead = 0;
598 int totBytesRead = 0;
599 int out_fd;
600 int flen;
601 int rc = RC_SUCCESS;
602 int dtb_count = 0, dtb_offset = 0;
603 size_t wrote = 0, expected = 0;
604 struct stat st;
605 uint32_t version = QCDT_VERSION;
606 int num;
607 uint32_t dtb_size;
608 int msmversion = 0;
609
610 log_info("DTB combiner:\n");
611
612 if (parse_commandline(argc, argv) != RC_SUCCESS) {
613 print_help();
614 return RC_ERROR;
615 }
616
617 log_info(" Input directory: '%s'\n", input_dir);
618 log_info(" Output file: '%s'\n", output_file);
619
620 DIR *dir = opendir(input_dir);
621 if (!dir) {
622 log_err("Failed to open input directory '%s'\n", input_dir);
623 return RC_ERROR;
624 }
625
626 filler = (uint8_t *)malloc(page_size);
627 if (!filler) {
628 log_err("Out of memory\n");
629 closedir(dir);
630 return RC_ERROR;
631 }
632 memset(filler, 0, page_size);
633
634 /* Open the .dtb files in the specified path, decompile and
635 extract "qcom,msm-id" parameter
636 */
637 while ((dp = readdir(dir)) != NULL) {
Robin Humble6fc97b72014-05-03 16:29:44 +1000638 if ((dp->d_type != DT_REG)) {
639 continue;
640 }
David Ng3556e582012-07-27 23:52:11 +0000641
Robin Humble6fc97b72014-05-03 16:29:44 +1000642 flen = strlen(dp->d_name);
643 if ((flen <= 4) ||
644 (strncmp(&dp->d_name[flen-4], ".dtb", 4) != 0)) {
645 continue;
646 }
647 log_info("Found file: %s ... ", dp->d_name);
David Ng3556e582012-07-27 23:52:11 +0000648
Robin Humble6fc97b72014-05-03 16:29:44 +1000649 flen = strlen(input_dir) + strlen(dp->d_name) + 1;
650 filename = (char *)malloc(flen);
651 if (!filename) {
652 log_err("Out of memory\n");
653 rc = RC_ERROR;
654 break;
655 }
656 strncpy(filename, input_dir, flen);
657 strncat(filename, dp->d_name, flen);
David Ng3556e582012-07-27 23:52:11 +0000658
Robin Humble6fc97b72014-05-03 16:29:44 +1000659 /* To identify the version number */
660 msmversion = force_v2 ? GetVersionInfo(filename) : 1;
David Ng3556e582012-07-27 23:52:11 +0000661
Robin Humble6fc97b72014-05-03 16:29:44 +1000662 num = 1;
663 chip = getChipInfo(filename, &num, msmversion);
David Ng3556e582012-07-27 23:52:11 +0000664
Robin Humble6fc97b72014-05-03 16:29:44 +1000665 if (msmversion == 1) {
666 if (!chip) {
667 log_err("skip, failed to scan for '%s' tag\n",
668 dt_tag);
669 free(filename);
670 continue;
David Ng3556e582012-07-27 23:52:11 +0000671 }
672 }
Robin Humble6fc97b72014-05-03 16:29:44 +1000673 if (msmversion == 2) {
674 if (!chip) {
675 log_err("skip, failed to scan for '%s' or '%s' tag\n",
676 dt_tag, QCDT_BOARD_TAG);
677 free(filename);
678 continue;
679 }
680 }
681
682 if ((stat(filename, &st) != 0) ||
683 (st.st_size == 0)) {
684 log_err("skip, failed to get DTB size\n");
685 free(filename);
686 continue;
687 }
688
689 log_info("chipset: %u, rev: %u, platform: %u, subtype: %u\n",
690 chip->chipset, chip->revNum, chip->platform, chip->subtype);
691
692 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
693 log_info(" additional chipset: %u, rev: %u, platform: %u, subtype: %u\n",
694 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
695 }
696
697 rc = chip_add(chip);
698 if (rc != RC_SUCCESS) {
699 log_err("... duplicate info, skipped\n");
700 free(filename);
701 continue;
702 }
703
704 dtb_count++;
705
706 chip->dtb_size = st.st_size +
707 (page_size - (st.st_size % page_size));
708 chip->dtb_file = filename;
709
710 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
711 rc = chip_add(t_chip);
712 if (rc != RC_SUCCESS) {
713 log_err("... duplicate info, skipped (chipset %u, rev: %u, platform: %u, subtype %u:\n",
714 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
715 continue;
716 }
717 dtb_count++;
718 }
David Ng3556e582012-07-27 23:52:11 +0000719 }
720 closedir(dir);
721 log_info("=> Found %d unique DTB(s)\n", dtb_count);
722
723 if (!dtb_count)
724 goto cleanup;
725
726
727 /* Generate the master DTB file:
728
729 Simplify write error handling by just checking for actual vs
730 expected bytes written at the end.
731 */
732
733 log_info("\nGenerating master DTB... ");
734
735 out_fd = open(output_file, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
736 if (!out_fd < 0) {
737 log_err("Cannot create '%s'\n", output_file);
738 rc = RC_ERROR;
739 goto cleanup;
740 }
741
742 if (force_v2) {
743 version = QCDT_VERSION_NEW;
744 }
745
746 /* Write header info */
747 wrote += write(out_fd, QCDT_MAGIC, sizeof(uint8_t) * 4); /* magic */
748 wrote += write(out_fd, &version, sizeof(uint32_t)); /* version */
749 wrote += write(out_fd, (uint32_t *)&dtb_count, sizeof(uint32_t));
750 /* #DTB */
751
752 /* Calculate offset of first DTB block */
753 dtb_offset = 12 + /* header */
754 ((force_v2 ? 24 : 20) * dtb_count) + /* DTB table entries */
755 4; /* end of table indicator */
756 /* Round up to page size */
757 padding = page_size - (dtb_offset % page_size);
758 dtb_offset += padding;
759 expected = dtb_offset;
760
761 /* Write index table:
762 chipset
763 platform
764 subtype
765 soc rev
766 dtb offset
767 dtb size
768 */
769 for (chip = chip_list; chip; chip = chip->next) {
770 wrote += write(out_fd, &chip->chipset, sizeof(uint32_t));
771 wrote += write(out_fd, &chip->platform, sizeof(uint32_t));
772 if (force_v2)
773 wrote += write(out_fd, &chip->subtype, sizeof(uint32_t));
774 wrote += write(out_fd, &chip->revNum, sizeof(uint32_t));
775 if (chip->master->master_offset != 0) {
776 wrote += write(out_fd, &chip->master->master_offset, sizeof(uint32_t));
777 } else {
778 wrote += write(out_fd, &expected, sizeof(uint32_t));
779 chip->master->master_offset = expected;
780 expected += chip->master->dtb_size;
781 }
782 wrote += write(out_fd, &chip->master->dtb_size, sizeof(uint32_t));
783 }
784
785 rc = RC_SUCCESS;
786 wrote += write(out_fd, &rc, sizeof(uint32_t)); /* end of table indicator */
787 if (padding > 0)
788 wrote += write(out_fd, filler, padding);
789
790 /* Write DTB's */
791 for (chip = chip_list; chip; chip = chip->next) {
792 if (chip->master->wroteDtb) {
793 continue;
794 }
795
796 chip->master->wroteDtb = 1;
797 filename = chip->master->dtb_file;
798 dtb_size = chip->master->dtb_size;
799
800 log_dbg("\n (writing '%s' - %u bytes) ", filename, dtb_size);
801 pInputFile = fopen(filename, "r");
802 if (pInputFile != NULL) {
803 totBytesRead = 0;
804 while ((numBytesRead = fread(buf, 1, COPY_BLK, pInputFile)) > 0) {
805 wrote += write(out_fd, buf, numBytesRead);
806 totBytesRead += numBytesRead;
807 }
808 fclose(pInputFile);
809 padding = page_size - (totBytesRead % page_size);
810 if ((uint32_t)(totBytesRead + padding) != dtb_size) {
811 log_err("DTB size mismatch, please re-run: expected %d vs actual %d (%s)\n",
812 dtb_size, totBytesRead + padding,
813 filename);
814 rc = RC_ERROR;
815 break;
816 }
817 if (padding > 0)
818 wrote += write(out_fd, filler, padding);
819 } else {
820 log_err("failed to open DTB '%s'\n", filename);
821 rc = RC_ERROR;
822 break;
823 }
824 }
825 close(out_fd);
826
827 if (expected != wrote) {
828 log_err("error writing output file, please rerun: size mismatch %d vs %d\n",
829 expected, wrote);
830 rc = RC_ERROR;
831 } else
832 log_dbg("Total wrote %u bytes\n", wrote);
833
834 if (rc != RC_SUCCESS)
835 unlink(output_file);
836 else
837 log_info("completed\n");
838
839cleanup:
840 free(filler);
841 chip_deleteall();
842 return rc;
843}