1238737Simp/* 2238737Simp * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com> 3238737Simp */ 4238737Simp 5266130Sian#include <stdbool.h> 6238737Simp#include <stdint.h> 7238737Simp#include <stdio.h> 8238737Simp#include <stdlib.h> 9238737Simp#include <string.h> 10238737Simp#include <ctype.h> 11238737Simp 12266130Sian#include <libfdt.h> 13266130Sian#include <libfdt_env.h> 14238737Simp#include <fdt.h> 15238737Simp 16238737Simp#include "util.h" 17238737Simp 18238737Simp#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) 19238737Simp#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) 20238737Simp#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) 21238737Simp 22266130Sianstatic const char *tagname(uint32_t tag) 23238737Simp{ 24266130Sian static const char * const names[] = { 25266130Sian#define TN(t) [t] #t 26266130Sian TN(FDT_BEGIN_NODE), 27266130Sian TN(FDT_END_NODE), 28266130Sian TN(FDT_PROP), 29266130Sian TN(FDT_NOP), 30266130Sian TN(FDT_END), 31266130Sian#undef TN 32266130Sian }; 33266130Sian if (tag < ARRAY_SIZE(names)) 34266130Sian if (names[tag]) 35266130Sian return names[tag]; 36266130Sian return "FDT_???"; 37266130Sian} 38238737Simp 39266130Sian#define dumpf(fmt, args...) \ 40266130Sian do { if (debug) printf("// " fmt, ## args); } while (0) 41238737Simp 42266130Sianstatic void dump_blob(void *blob, bool debug) 43238737Simp{ 44266130Sian uintptr_t blob_off = (uintptr_t)blob; 45238737Simp struct fdt_header *bph = blob; 46238737Simp uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); 47238737Simp uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); 48238737Simp uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings); 49238737Simp struct fdt_reserve_entry *p_rsvmap = 50238737Simp (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap); 51238737Simp const char *p_struct = (const char *)blob + off_dt; 52238737Simp const char *p_strings = (const char *)blob + off_str; 53238737Simp uint32_t version = fdt32_to_cpu(bph->version); 54238737Simp uint32_t totalsize = fdt32_to_cpu(bph->totalsize); 55238737Simp uint32_t tag; 56238737Simp const char *p, *s, *t; 57238737Simp int depth, sz, shift; 58238737Simp int i; 59238737Simp uint64_t addr, size; 60238737Simp 61238737Simp depth = 0; 62238737Simp shift = 4; 63238737Simp 64238737Simp printf("/dts-v1/;\n"); 65238737Simp printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic)); 66238737Simp printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize); 67238737Simp printf("// off_dt_struct:\t0x%x\n", off_dt); 68238737Simp printf("// off_dt_strings:\t0x%x\n", off_str); 69238737Simp printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); 70238737Simp printf("// version:\t\t%d\n", version); 71238737Simp printf("// last_comp_version:\t%d\n", 72238737Simp fdt32_to_cpu(bph->last_comp_version)); 73238737Simp if (version >= 2) 74238737Simp printf("// boot_cpuid_phys:\t0x%x\n", 75238737Simp fdt32_to_cpu(bph->boot_cpuid_phys)); 76238737Simp 77238737Simp if (version >= 3) 78238737Simp printf("// size_dt_strings:\t0x%x\n", 79238737Simp fdt32_to_cpu(bph->size_dt_strings)); 80238737Simp if (version >= 17) 81238737Simp printf("// size_dt_struct:\t0x%x\n", 82238737Simp fdt32_to_cpu(bph->size_dt_struct)); 83238737Simp printf("\n"); 84238737Simp 85238737Simp for (i = 0; ; i++) { 86238737Simp addr = fdt64_to_cpu(p_rsvmap[i].address); 87238737Simp size = fdt64_to_cpu(p_rsvmap[i].size); 88238737Simp if (addr == 0 && size == 0) 89238737Simp break; 90238737Simp 91238737Simp printf("/memreserve/ %llx %llx;\n", 92238737Simp (unsigned long long)addr, (unsigned long long)size); 93238737Simp } 94238737Simp 95238737Simp p = p_struct; 96238737Simp while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { 97238737Simp 98266130Sian dumpf("%04zx: tag: 0x%08x (%s)\n", 99266130Sian (uintptr_t)p - blob_off - 4, tag, tagname(tag)); 100238737Simp 101238737Simp if (tag == FDT_BEGIN_NODE) { 102238737Simp s = p; 103238737Simp p = PALIGN(p + strlen(s) + 1, 4); 104238737Simp 105238737Simp if (*s == '\0') 106238737Simp s = "/"; 107238737Simp 108238737Simp printf("%*s%s {\n", depth * shift, "", s); 109238737Simp 110238737Simp depth++; 111238737Simp continue; 112238737Simp } 113238737Simp 114238737Simp if (tag == FDT_END_NODE) { 115238737Simp depth--; 116238737Simp 117238737Simp printf("%*s};\n", depth * shift, ""); 118238737Simp continue; 119238737Simp } 120238737Simp 121238737Simp if (tag == FDT_NOP) { 122238737Simp printf("%*s// [NOP]\n", depth * shift, ""); 123238737Simp continue; 124238737Simp } 125238737Simp 126238737Simp if (tag != FDT_PROP) { 127238737Simp fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); 128238737Simp break; 129238737Simp } 130238737Simp sz = fdt32_to_cpu(GET_CELL(p)); 131238737Simp s = p_strings + fdt32_to_cpu(GET_CELL(p)); 132238737Simp if (version < 16 && sz >= 8) 133238737Simp p = PALIGN(p, 8); 134238737Simp t = p; 135238737Simp 136238737Simp p = PALIGN(p + sz, 4); 137238737Simp 138266130Sian dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s); 139266130Sian dumpf("%04zx: value\n", (uintptr_t)t - blob_off); 140238737Simp printf("%*s%s", depth * shift, "", s); 141266130Sian utilfdt_print_data(t, sz); 142238737Simp printf(";\n"); 143238737Simp } 144238737Simp} 145238737Simp 146266130Sian/* Usage related data. */ 147266130Sianstatic const char usage_synopsis[] = "fdtdump [options] <file>"; 148266130Sianstatic const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS; 149266130Sianstatic struct option const usage_long_opts[] = { 150266130Sian {"debug", no_argument, NULL, 'd'}, 151266130Sian {"scan", no_argument, NULL, 's'}, 152266130Sian USAGE_COMMON_LONG_OPTS 153266130Sian}; 154266130Sianstatic const char * const usage_opts_help[] = { 155266130Sian "Dump debug information while decoding the file", 156266130Sian "Scan for an embedded fdt in file", 157266130Sian USAGE_COMMON_OPTS_HELP 158266130Sian}; 159238737Simp 160238737Simpint main(int argc, char *argv[]) 161238737Simp{ 162266130Sian int opt; 163266130Sian const char *file; 164238737Simp char *buf; 165266130Sian bool debug = false; 166266130Sian bool scan = false; 167266130Sian off_t len; 168238737Simp 169266130Sian while ((opt = util_getopt_long()) != EOF) { 170266130Sian switch (opt) { 171266130Sian case_USAGE_COMMON_FLAGS 172266130Sian 173266130Sian case 'd': 174266130Sian debug = true; 175266130Sian break; 176266130Sian case 's': 177266130Sian scan = true; 178266130Sian break; 179266130Sian } 180238737Simp } 181266130Sian if (optind != argc - 1) 182266130Sian usage("missing input filename"); 183266130Sian file = argv[optind]; 184238737Simp 185266130Sian buf = utilfdt_read_len(file, &len); 186266130Sian if (!buf) 187266130Sian die("could not read: %s\n", file); 188238737Simp 189266130Sian /* try and locate an embedded fdt in a bigger blob */ 190266130Sian if (scan) { 191266130Sian unsigned char smagic[4]; 192266130Sian char *p = buf; 193266130Sian char *endp = buf + len; 194266130Sian 195266130Sian fdt_set_magic(smagic, FDT_MAGIC); 196266130Sian 197266130Sian /* poor man's memmem */ 198266130Sian while (true) { 199266130Sian p = memchr(p, smagic[0], endp - p - 4); 200266130Sian if (!p) 201266130Sian break; 202266130Sian if (fdt_magic(p) == FDT_MAGIC) { 203266130Sian /* try and validate the main struct */ 204266130Sian off_t this_len = endp - p; 205266130Sian fdt32_t max_version = 17; 206266130Sian if (fdt_version(p) <= max_version && 207266130Sian fdt_last_comp_version(p) < max_version && 208266130Sian fdt_totalsize(p) < this_len && 209266130Sian fdt_off_dt_struct(p) < this_len && 210266130Sian fdt_off_dt_strings(p) < this_len) 211266130Sian break; 212266130Sian if (debug) 213266130Sian printf("%s: skipping fdt magic at offset %#zx\n", 214266130Sian file, p - buf); 215266130Sian } 216266130Sian ++p; 217266130Sian } 218266130Sian if (!p) 219266130Sian die("%s: could not locate fdt magic\n", file); 220266130Sian printf("%s: found fdt at offset %#zx\n", file, p - buf); 221266130Sian buf = p; 222266130Sian } 223266130Sian 224266130Sian dump_blob(buf, debug); 225266130Sian 226238737Simp return 0; 227238737Simp} 228