Home | History | Annotate | Download | only in src
      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(&params, 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(&params);
    262 }
    263