1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19
20 #include "libfdt.h"
21 #include "libufdt_sysdeps.h"
22
23 #include "util.h"
24
find_dtb_header_pos(const char * buf,size_t buf_size)25 static int find_dtb_header_pos(const char *buf, size_t buf_size) {
26 if (buf == NULL || buf_size == 0) {
27 return -1;
28 }
29
30 int pos = buf_size;
31 while (1) {
32 pos--;
33 if (pos < 0) {
34 break;
35 }
36 uint32_t tag = fdt32_to_cpu(*(fdt32_t *)(buf + pos));
37 if (tag == FDT_MAGIC) {
38 // Hit!
39 break;
40 }
41 }
42
43 return pos;
44 }
45
find_and_write_dtb(const char * filename,const char * buf,size_t buf_size)46 static int find_and_write_dtb(const char *filename, const char *buf,
47 size_t buf_size) {
48 int tag_pos = find_dtb_header_pos(buf, buf_size);
49 if (tag_pos < 0) {
50 return -1;
51 }
52
53 buf_size -= tag_pos;
54
55 // Allocate and copy into new buffer to fix memory alignment
56 char *fdt_ptr = malloc(buf_size);
57 if (!fdt_ptr) {
58 fprintf(stderr, "malloc(%u) failed.\n", buf_size - tag_pos);
59 goto error;
60 }
61
62 memcpy(fdt_ptr, buf + tag_pos, buf_size);
63
64 // Check FDT header
65 if (fdt_check_full(fdt_ptr, buf_size) != 0) {
66 fprintf(stderr, "Bad DTB.\n");
67 goto error;
68 }
69
70 // Check FDT size and actual size
71 size_t fdt_size = fdt_totalsize(fdt_ptr);
72 if (buf_size < fdt_size) {
73 fprintf(stderr,
74 "Wrong size: fdt truncated: buffer size = %zu < FDT size = %zu\n",
75 buf_size, fdt_size);
76 goto error;
77 }
78
79 // Print the DT basic information
80 int root_node_off = fdt_path_offset(fdt_ptr, "/");
81 if (root_node_off < 0) {
82 fprintf(stderr, "Can not get the root node.\n");
83 goto error;
84 }
85 printf("Output %s\n", filename);
86 const char *model =
87 (const char *)fdt_getprop(fdt_ptr, root_node_off, "model", NULL);
88 printf(" model=%s\n", model ? model : "(unknown)");
89 const char *compatible =
90 (const char *)fdt_getprop(fdt_ptr, root_node_off, "compatible", NULL);
91 printf(" compatible=%s\n", compatible ? compatible : "(unknown)");
92
93 // Output DTB file
94 if (write_fdt_to_file(filename, fdt_ptr) != 0) {
95 fprintf(stderr, "Write file error: %s\n", filename);
96 goto error;
97 }
98
99 free(fdt_ptr);
100
101 return tag_pos;
102
103 error:
104 if (fdt_ptr) free(fdt_ptr);
105 return -1;
106 }
107
extract_dtbs(const char * in_filename,const char * out_dtb_filename,const char * out_image_filename)108 static int extract_dtbs(const char *in_filename, const char *out_dtb_filename,
109 const char *out_image_filename) {
110 int ret = 1;
111 char *buf = NULL;
112
113 size_t buf_size;
114 buf = load_file(in_filename, &buf_size);
115 if (!buf || fdt_check_full(buf, buf_size)) {
116 fprintf(stderr, "Can not load file: %s\n", in_filename);
117 goto end;
118 }
119
120 char filename[128];
121 int index = 0;
122 while (buf_size > 0) {
123 int tag_pos;
124 if (index > 0) {
125 snprintf(filename, sizeof(filename), "%s.%d", out_dtb_filename, index);
126 tag_pos = find_and_write_dtb(filename, buf, buf_size);
127 } else {
128 tag_pos = find_and_write_dtb(out_dtb_filename, buf, buf_size);
129 }
130 if (tag_pos < 0) {
131 break;
132 }
133
134 buf_size = tag_pos;
135 index++;
136 }
137
138 if (index == 0) {
139 fprintf(stderr, "Can not find any DTB.\n");
140 goto end;
141 }
142
143 // Output the rest buffer as image file
144 if (out_image_filename != NULL) {
145 printf("Output %s\n", out_image_filename);
146 if (write_buf_to_file(out_image_filename, buf, buf_size) != 0) {
147 fprintf(stderr, "Write file error: %s\n", out_image_filename);
148 goto end;
149 }
150 }
151
152 ret = 0;
153
154 end:
155 if (buf) dto_free(buf);
156
157 return ret;
158 }
159
main(int argc,char ** argv)160 int main(int argc, char **argv) {
161 if (argc < 3) {
162 fprintf(stderr, "Usage: %s <image.gz-dtb_file> <out_dtb_name> (<out_image_name>)\n\n", argv[0]);
163 fprintf(stderr, " Note: If there are more than one DTB, it outputs DTB files named\n" \
164 " out_dtb_name, out_dtb_name.1, out_dtb_name.2, etc.\n");
165 return 1;
166 }
167
168 const char *in_file = argv[1];
169 const char *out_dtb_file = argv[2];
170 const char *out_image_file = (argc > 3) ? argv[3] : NULL;
171 int ret = extract_dtbs(in_file, out_dtb_file, out_image_file);
172
173 return ret;
174 }
175