blob: 0dbee4d5bec0f084a1dbfebc4613d45e6e9f5867 [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) {
David Ng3556e582012-07-27 23:52:11 +0000638
Robin Humble6fc97b72014-05-03 16:29:44 +1000639 flen = strlen(input_dir) + strlen(dp->d_name) + 1;
640 filename = (char *)malloc(flen);
641 if (!filename) {
642 log_err("Out of memory\n");
643 rc = RC_ERROR;
644 break;
645 }
646 strncpy(filename, input_dir, flen);
647 strncat(filename, dp->d_name, flen);
David Ng3556e582012-07-27 23:52:11 +0000648
Robin Humble9077ed02014-05-03 16:34:22 +1000649 if (stat(filename, &st) != 0 || !S_ISREG(st.st_mode)) {
650 free(filename);
651 continue;
652 }
653
654 flen = strlen(dp->d_name);
655 if ((flen <= 4) || (strncmp(&dp->d_name[flen-4], ".dtb", 4) != 0)) {
656 free(filename);
657 continue;
658 }
659
660 log_info("Found file: %s ... ", dp->d_name);
661
Robin Humble6fc97b72014-05-03 16:29:44 +1000662 /* To identify the version number */
663 msmversion = force_v2 ? GetVersionInfo(filename) : 1;
David Ng3556e582012-07-27 23:52:11 +0000664
Robin Humble6fc97b72014-05-03 16:29:44 +1000665 num = 1;
666 chip = getChipInfo(filename, &num, msmversion);
David Ng3556e582012-07-27 23:52:11 +0000667
Robin Humble6fc97b72014-05-03 16:29:44 +1000668 if (msmversion == 1) {
669 if (!chip) {
670 log_err("skip, failed to scan for '%s' tag\n",
671 dt_tag);
672 free(filename);
673 continue;
David Ng3556e582012-07-27 23:52:11 +0000674 }
675 }
Robin Humble6fc97b72014-05-03 16:29:44 +1000676 if (msmversion == 2) {
677 if (!chip) {
678 log_err("skip, failed to scan for '%s' or '%s' tag\n",
679 dt_tag, QCDT_BOARD_TAG);
680 free(filename);
681 continue;
682 }
683 }
684
Robin Humble9077ed02014-05-03 16:34:22 +1000685 if (st.st_size == 0) {
Robin Humble6fc97b72014-05-03 16:29:44 +1000686 log_err("skip, failed to get DTB size\n");
687 free(filename);
688 continue;
689 }
690
691 log_info("chipset: %u, rev: %u, platform: %u, subtype: %u\n",
692 chip->chipset, chip->revNum, chip->platform, chip->subtype);
693
694 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
695 log_info(" additional chipset: %u, rev: %u, platform: %u, subtype: %u\n",
696 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
697 }
698
699 rc = chip_add(chip);
700 if (rc != RC_SUCCESS) {
701 log_err("... duplicate info, skipped\n");
702 free(filename);
703 continue;
704 }
705
706 dtb_count++;
707
708 chip->dtb_size = st.st_size +
709 (page_size - (st.st_size % page_size));
710 chip->dtb_file = filename;
711
712 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
713 rc = chip_add(t_chip);
714 if (rc != RC_SUCCESS) {
715 log_err("... duplicate info, skipped (chipset %u, rev: %u, platform: %u, subtype %u:\n",
716 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
717 continue;
718 }
719 dtb_count++;
720 }
David Ng3556e582012-07-27 23:52:11 +0000721 }
722 closedir(dir);
723 log_info("=> Found %d unique DTB(s)\n", dtb_count);
724
725 if (!dtb_count)
726 goto cleanup;
727
728
729 /* Generate the master DTB file:
730
731 Simplify write error handling by just checking for actual vs
732 expected bytes written at the end.
733 */
734
735 log_info("\nGenerating master DTB... ");
736
737 out_fd = open(output_file, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
738 if (!out_fd < 0) {
739 log_err("Cannot create '%s'\n", output_file);
740 rc = RC_ERROR;
741 goto cleanup;
742 }
743
744 if (force_v2) {
745 version = QCDT_VERSION_NEW;
746 }
747
748 /* Write header info */
749 wrote += write(out_fd, QCDT_MAGIC, sizeof(uint8_t) * 4); /* magic */
750 wrote += write(out_fd, &version, sizeof(uint32_t)); /* version */
751 wrote += write(out_fd, (uint32_t *)&dtb_count, sizeof(uint32_t));
752 /* #DTB */
753
754 /* Calculate offset of first DTB block */
755 dtb_offset = 12 + /* header */
756 ((force_v2 ? 24 : 20) * dtb_count) + /* DTB table entries */
757 4; /* end of table indicator */
758 /* Round up to page size */
759 padding = page_size - (dtb_offset % page_size);
760 dtb_offset += padding;
761 expected = dtb_offset;
762
763 /* Write index table:
764 chipset
765 platform
766 subtype
767 soc rev
768 dtb offset
769 dtb size
770 */
771 for (chip = chip_list; chip; chip = chip->next) {
772 wrote += write(out_fd, &chip->chipset, sizeof(uint32_t));
773 wrote += write(out_fd, &chip->platform, sizeof(uint32_t));
774 if (force_v2)
775 wrote += write(out_fd, &chip->subtype, sizeof(uint32_t));
776 wrote += write(out_fd, &chip->revNum, sizeof(uint32_t));
777 if (chip->master->master_offset != 0) {
778 wrote += write(out_fd, &chip->master->master_offset, sizeof(uint32_t));
779 } else {
780 wrote += write(out_fd, &expected, sizeof(uint32_t));
781 chip->master->master_offset = expected;
782 expected += chip->master->dtb_size;
783 }
784 wrote += write(out_fd, &chip->master->dtb_size, sizeof(uint32_t));
785 }
786
787 rc = RC_SUCCESS;
788 wrote += write(out_fd, &rc, sizeof(uint32_t)); /* end of table indicator */
789 if (padding > 0)
790 wrote += write(out_fd, filler, padding);
791
792 /* Write DTB's */
793 for (chip = chip_list; chip; chip = chip->next) {
794 if (chip->master->wroteDtb) {
795 continue;
796 }
797
798 chip->master->wroteDtb = 1;
799 filename = chip->master->dtb_file;
800 dtb_size = chip->master->dtb_size;
801
802 log_dbg("\n (writing '%s' - %u bytes) ", filename, dtb_size);
803 pInputFile = fopen(filename, "r");
804 if (pInputFile != NULL) {
805 totBytesRead = 0;
806 while ((numBytesRead = fread(buf, 1, COPY_BLK, pInputFile)) > 0) {
807 wrote += write(out_fd, buf, numBytesRead);
808 totBytesRead += numBytesRead;
809 }
810 fclose(pInputFile);
811 padding = page_size - (totBytesRead % page_size);
812 if ((uint32_t)(totBytesRead + padding) != dtb_size) {
813 log_err("DTB size mismatch, please re-run: expected %d vs actual %d (%s)\n",
814 dtb_size, totBytesRead + padding,
815 filename);
816 rc = RC_ERROR;
817 break;
818 }
819 if (padding > 0)
820 wrote += write(out_fd, filler, padding);
821 } else {
822 log_err("failed to open DTB '%s'\n", filename);
823 rc = RC_ERROR;
824 break;
825 }
826 }
827 close(out_fd);
828
829 if (expected != wrote) {
savoca04489bf2015-10-08 11:52:35 -0700830 log_err("error writing output file, please rerun: size mismatch %zu vs %zu\n",
David Ng3556e582012-07-27 23:52:11 +0000831 expected, wrote);
832 rc = RC_ERROR;
833 } else
savoca04489bf2015-10-08 11:52:35 -0700834 log_dbg("Total wrote %zu bytes\n", wrote);
David Ng3556e582012-07-27 23:52:11 +0000835
836 if (rc != RC_SUCCESS)
837 unlink(output_file);
838 else
839 log_info("completed\n");
840
841cleanup:
842 free(filler);
843 chip_deleteall();
844 return rc;
845}