1 /*
2 * Copyright (C) 2017 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 <getopt.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21
22 #include "libacpi.h"
23 #include "libfdt.h"
24
25 #include "dt_table.h"
26
27
28 struct dump_params {
29 const char *img_filename;
30 const char *out_filename;
31 const char *out_dtb_filename;
32 };
33
34 static const char short_options[] = "o:b:";
35 static struct option options[] = {{"output", required_argument, NULL, 'o'},
36 {"dtb", required_argument, NULL, 'b'},
37 {0, 0, NULL, 0}};
38
read_fdt_from_image(FILE * img_fp,uint32_t dt_offset,uint32_t dt_size)39 static void *read_fdt_from_image(FILE *img_fp,
40 uint32_t dt_offset, uint32_t dt_size) {
41 void *fdt = NULL;
42
43 fdt = malloc(dt_size);
44
45 fseek(img_fp, dt_offset, SEEK_SET);
46 if (fread(fdt, dt_size, 1, img_fp) == 0) {
47 fprintf(stderr, "Read FDT data error.\n");
48
49 free(fdt);
50 return NULL;
51 }
52
53 return fdt;
54 }
55
write_fdt_to_file(const char * filename,const void * fdt,uint32_t (* get_fdt_size)(const void *))56 static int write_fdt_to_file(const char *filename, const void *fdt,
57 uint32_t (*get_fdt_size)(const void *)) {
58 int ret = -1;
59 FILE *out_fp = NULL;
60
61 out_fp = fopen(filename, "wb");
62 if (!out_fp) {
63 fprintf(stderr, "Can not create file: %s\n", filename);
64 goto end;
65 }
66
67 uint32_t fdt_size = get_fdt_size(fdt);
68 if (fwrite(fdt, fdt_size, 1, out_fp) < 1) {
69 fprintf(stderr, "Write FDT data error.\n");
70 goto end;
71 }
72
73 ret = 0;
74
75 end:
76 if (out_fp) fclose(out_fp);
77
78 return ret;
79 }
80
free_fdt(void * fdt)81 static void free_fdt(void *fdt) {
82 if (fdt == NULL) {
83 /* do nothing */
84 return;
85 }
86
87 free(fdt);
88 }
89
90
output_prop_int(FILE * out_fp,const char * name,uint32_t value)91 static void output_prop_int(FILE *out_fp, const char *name, uint32_t value) {
92 fprintf(out_fp, "%+20s = %d\n", name, fdt32_to_cpu(value));
93 }
94
output_prop_int_cpu(FILE * out_fp,const char * name,uint32_t value)95 static void output_prop_int_cpu(FILE *out_fp, const char *name, uint32_t value) {
96 fprintf(out_fp, "%+20s = %d\n", name, value);
97 }
98
output_prop_hex(FILE * out_fp,const char * name,uint32_t value)99 static void output_prop_hex(FILE *out_fp, const char *name, uint32_t value) {
100 fprintf(out_fp, "%+20s = %08x\n", name, fdt32_to_cpu(value));
101 }
102
output_prop_str(FILE * out_fp,const char * name,const char * value)103 static void output_prop_str(FILE *out_fp, const char *name, const char *value) {
104 fprintf(out_fp, "%+20s = %s\n", name, value);
105 }
106
output_table_header(FILE * out_fp,const struct dt_table_header * header)107 static void output_table_header(FILE *out_fp, const struct dt_table_header *header) {
108 fprintf(out_fp, "dt_table_header:\n");
109 output_prop_hex(out_fp, "magic", header->magic);
110 output_prop_int(out_fp, "total_size", header->total_size);
111 output_prop_int(out_fp, "header_size", header->header_size);
112 output_prop_int(out_fp, "dt_entry_size", header->dt_entry_size);
113 output_prop_int(out_fp, "dt_entry_count", header->dt_entry_count);
114 output_prop_int(out_fp, "dt_entries_offset", header->dt_entries_offset);
115 output_prop_int(out_fp, "page_size", header->page_size);
116 output_prop_int(out_fp, "version", header->version);
117 }
118
output_table_entry(FILE * out_fp,int index,const struct dt_table_entry * entry)119 static void output_table_entry(FILE *out_fp, int index, const struct dt_table_entry *entry) {
120 fprintf(out_fp, "dt_table_entry[%d]:\n", index);
121 output_prop_int(out_fp, "dt_size", entry->dt_size);
122 output_prop_int(out_fp, "dt_offset", entry->dt_offset);
123 output_prop_hex(out_fp, "id", entry->id);
124 output_prop_hex(out_fp, "rev", entry->rev);
125 output_prop_hex(out_fp, "custom[0]", entry->custom[0]);
126 output_prop_hex(out_fp, "custom[1]", entry->custom[1]);
127 output_prop_hex(out_fp, "custom[2]", entry->custom[2]);
128 output_prop_hex(out_fp, "custom[3]", entry->custom[3]);
129 }
130
output_fdt_info(FILE * out_fp,void * fdt,uint32_t (* get_fdt_size)(const void *))131 static int output_fdt_info(FILE *out_fp, void *fdt,
132 uint32_t (*get_fdt_size)(const void *)) {
133 uint32_t fdt_size = get_fdt_size(fdt);
134
135 output_prop_int_cpu(out_fp, "(FDT)size", fdt_size);
136
137 int root_node_off = fdt_path_offset(fdt, "/");
138 if (root_node_off < 0) {
139 fprintf(stderr, "Can not get the root node.\n");
140 return -1;
141 }
142
143 const char *compatible =
144 (const char *)fdt_getprop(fdt, root_node_off, "compatible", NULL);
145 output_prop_str(out_fp, "(FDT)compatible", compatible ? compatible : "(unknown)");
146
147 return 0;
148 }
149
get_acpi_file_size(const void * acpi)150 static inline uint32_t get_acpi_file_size(const void *acpi) {
151 return acpi_length(acpi);
152 }
153
get_fdt_file_size(const void * fdt)154 static inline uint32_t get_fdt_file_size(const void *fdt) {
155 return fdt_totalsize(fdt);
156 }
157
dump_image_from_fp(FILE * out_fp,FILE * img_fp,const struct dump_params * params)158 static int dump_image_from_fp(FILE *out_fp, FILE *img_fp,
159 const struct dump_params *params) {
160 struct dt_table_header header;
161 if (fread(&header, sizeof(header), 1, img_fp) != 1) {
162 fprintf(stderr, "Read error.\n");
163 return -1;
164 }
165 /* TODO: check header */
166 output_table_header(out_fp, &header);
167
168 uint32_t (*get_fdt_size)(const void *);
169 uint32_t entry_magic = fdt32_to_cpu(header.magic);
170 if (entry_magic == ACPI_TABLE_MAGIC)
171 get_fdt_size = get_acpi_file_size;
172 else
173 get_fdt_size = get_fdt_file_size;
174
175 uint32_t entry_size = fdt32_to_cpu(header.dt_entry_size);
176 uint32_t entry_offset = fdt32_to_cpu(header.dt_entries_offset);
177 uint32_t entry_count = fdt32_to_cpu(header.dt_entry_count);
178 uint32_t i;
179 for (i = 0; i < entry_count; i++) {
180 struct dt_table_entry entry;
181 fseek(img_fp, entry_offset, SEEK_SET);
182 if (fread(&entry, sizeof(entry), 1, img_fp) != 1) {
183 fprintf(stderr, "Read dt_table_entry error.\n");
184 return -1;
185 }
186 output_table_entry(out_fp, i, &entry);
187
188 uint32_t dt_size = fdt32_to_cpu(entry.dt_size);
189 uint32_t dt_offset = fdt32_to_cpu(entry.dt_offset);
190 if (dt_size > 0 && dt_offset > 0) {
191 void *fdt = read_fdt_from_image(img_fp, dt_offset, dt_size);
192 output_fdt_info(out_fp, fdt, get_fdt_size);
193
194 if (params->out_dtb_filename != NULL) {
195 char filename[256];
196 snprintf(filename, sizeof(filename), "%s.%d",
197 params->out_dtb_filename, i);
198 write_fdt_to_file(filename, fdt, get_fdt_size);
199 }
200
201 free_fdt(fdt);
202 }
203
204 entry_offset += entry_size;
205 }
206
207 return 0;
208 }
209
process_command_dump(const struct dump_params * params)210 static int process_command_dump(const struct dump_params *params) {
211 int ret = -1;
212 FILE *out_fp = NULL;
213 FILE *img_fp = NULL;
214
215 img_fp = fopen(params->img_filename, "rb");
216 if (img_fp == NULL) {
217 fprintf(stderr, "Can not open image file: %s\n", params->img_filename);
218 goto end;
219 }
220
221 if (params->out_filename != NULL) {
222 out_fp = fopen(params->out_filename, "w");
223 if (out_fp == NULL) {
224 fprintf(stderr, "Can not create file: %s\n", params->out_filename);
225 goto end;
226 }
227 }
228
229 ret = dump_image_from_fp(out_fp ? out_fp : stdout, img_fp, params);
230
231 end:
232 if (img_fp) fclose(img_fp);
233 if (out_fp) fclose(out_fp);
234
235 return ret;
236 }
237
handle_usage_dump(FILE * out_fp,const char * prog_name)238 void handle_usage_dump(FILE *out_fp, const char *prog_name) {
239 fprintf(out_fp, " %s dump <image_file> (<option>...)\n\n", prog_name);
240 fprintf(out_fp,
241 " options:\n"
242 " -o, --output <filename> Output file name.\n"
243 " Default is output to stdout.\n"
244 " -b, --dtb <filename> Dump dtb/dtbo files from image.\n"
245 " Will output to <filename>.0, <filename>.1, etc.\n");
246 }
247
handle_command_dump(int argc,char * argv[],int arg_start)248 int handle_command_dump(int argc, char *argv[], int arg_start) {
249 if (argc - arg_start < 1) {
250 handle_usage_dump(stderr, argv[0]);
251 return 1;
252 }
253
254 struct dump_params params;
255 memset(¶ms, 0, sizeof(params));
256 params.img_filename = argv[arg_start];
257
258 optind = arg_start + 1;
259 while (1) {
260 int c = getopt_long(argc, argv, short_options, options, NULL);
261 if (c == -1) {
262 break;
263 }
264 switch (c) {
265 case 'o':
266 params.out_filename = optarg;
267 break;
268 case 'b':
269 params.out_dtb_filename = optarg;
270 break;
271 default:
272 /* Unknown option, return error */
273 return 1;
274 }
275 }
276
277 return process_command_dump(¶ms);
278 }
279