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 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 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 82 static void free_fdt(void *fdt) { 83 if (fdt == NULL) { 84 /* do nothing */ 85 return; 86 } 87 88 free(fdt); 89 } 90 91 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 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 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 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 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_int(out_fp, "version", header->version); 118 } 119 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 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 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 if (fread(&entry, sizeof(entry), 1, img_fp) != 1) { 167 fprintf(stderr, "Read dt_table_entry error.\n"); 168 return -1; 169 } 170 output_table_entry(out_fp, i, &entry); 171 172 uint32_t dt_size = fdt32_to_cpu(entry.dt_size); 173 uint32_t dt_offset = fdt32_to_cpu(entry.dt_offset); 174 if (dt_size > 0 && dt_offset > 0) { 175 void *fdt = read_fdt_from_image(img_fp, dt_offset, dt_size); 176 output_fdt_info(out_fp, fdt); 177 178 if (params->out_dtb_filename != NULL) { 179 char filename[256]; 180 snprintf(filename, sizeof(filename), "%s.%d", 181 params->out_dtb_filename, i); 182 write_fdt_to_file(filename, fdt); 183 } 184 185 free_fdt(fdt); 186 } 187 188 entry_offset += entry_size; 189 } 190 191 return 0; 192 } 193 194 static int process_command_dump(const struct dump_params *params) { 195 int ret = -1; 196 FILE *out_fp = NULL; 197 FILE *img_fp = NULL; 198 199 img_fp = fopen(params->img_filename, "rb"); 200 if (img_fp == NULL) { 201 fprintf(stderr, "Can not open image file: %s\n", params->img_filename); 202 goto end; 203 } 204 205 if (params->out_filename != NULL) { 206 out_fp = fopen(params->out_filename, "w"); 207 if (out_fp == NULL) { 208 fprintf(stderr, "Can not create file: %s\n", params->out_filename); 209 goto end; 210 } 211 } 212 213 ret = dump_image_from_fp(out_fp ? out_fp : stdout, img_fp, params); 214 215 end: 216 if (img_fp) fclose(img_fp); 217 if (out_fp) fclose(out_fp); 218 219 return ret; 220 } 221 222 void handle_usage_dump(FILE *out_fp, const char *prog_name) { 223 fprintf(out_fp, " %s dump <image_file> (<option>...)\n\n", prog_name); 224 fprintf(out_fp, 225 " options:\n" 226 " -o, --output <filename> Output file name.\n" 227 " Default is output to stdout.\n" 228 " -b, --dtb <filename> Dump dtb/dtbo files from image.\n" 229 " Will output to <filename>.0, <filename>.1, etc.\n"); 230 } 231 232 int handle_command_dump(int argc, char *argv[], int arg_start) { 233 if (argc - arg_start < 1) { 234 handle_usage_dump(stderr, argv[0]); 235 return 1; 236 } 237 238 struct dump_params params; 239 memset(¶ms, 0, sizeof(params)); 240 params.img_filename = argv[arg_start]; 241 242 optind = arg_start + 1; 243 while (1) { 244 int c = getopt_long(argc, argv, short_options, options, NULL); 245 if (c == -1) { 246 break; 247 } 248 switch (c) { 249 case 'o': 250 params.out_filename = optarg; 251 break; 252 case 'b': 253 params.out_dtb_filename = optarg; 254 break; 255 default: 256 /* Unknown option, return error */ 257 return 1; 258 } 259 } 260 261 return process_command_dump(¶ms); 262 } 263