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