1238737Simp/* 2238737Simp * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com> 3238737Simp */ 4238737Simp 5261215Simp#include <stdbool.h> 6238737Simp#include <stdint.h> 7238737Simp#include <stdio.h> 8238737Simp#include <stdlib.h> 9238737Simp#include <string.h> 10238737Simp#include <ctype.h> 11238737Simp 12261215Simp#include <libfdt.h> 13261215Simp#include <libfdt_env.h> 14238737Simp#include <fdt.h> 15238737Simp 16238737Simp#include "util.h" 17238737Simp 18318102Sgonzo#define FDT_MAGIC_SIZE 4 19318102Sgonzo#define MAX_VERSION 17 20318102Sgonzo 21238737Simp#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) 22238737Simp#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) 23238737Simp#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) 24238737Simp 25261215Simpstatic const char *tagname(uint32_t tag) 26238737Simp{ 27261215Simp static const char * const names[] = { 28318102Sgonzo#define TN(t) [t] = #t 29261215Simp TN(FDT_BEGIN_NODE), 30261215Simp TN(FDT_END_NODE), 31261215Simp TN(FDT_PROP), 32261215Simp TN(FDT_NOP), 33261215Simp TN(FDT_END), 34261215Simp#undef TN 35261215Simp }; 36261215Simp if (tag < ARRAY_SIZE(names)) 37261215Simp if (names[tag]) 38261215Simp return names[tag]; 39261215Simp return "FDT_???"; 40261215Simp} 41238737Simp 42261215Simp#define dumpf(fmt, args...) \ 43261215Simp do { if (debug) printf("// " fmt, ## args); } while (0) 44238737Simp 45261215Simpstatic void dump_blob(void *blob, bool debug) 46238737Simp{ 47261215Simp uintptr_t blob_off = (uintptr_t)blob; 48238737Simp struct fdt_header *bph = blob; 49238737Simp uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); 50238737Simp uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); 51238737Simp uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings); 52238737Simp struct fdt_reserve_entry *p_rsvmap = 53238737Simp (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap); 54238737Simp const char *p_struct = (const char *)blob + off_dt; 55238737Simp const char *p_strings = (const char *)blob + off_str; 56238737Simp uint32_t version = fdt32_to_cpu(bph->version); 57238737Simp uint32_t totalsize = fdt32_to_cpu(bph->totalsize); 58238737Simp uint32_t tag; 59238737Simp const char *p, *s, *t; 60238737Simp int depth, sz, shift; 61238737Simp int i; 62238737Simp uint64_t addr, size; 63238737Simp 64238737Simp depth = 0; 65238737Simp shift = 4; 66238737Simp 67238737Simp printf("/dts-v1/;\n"); 68238737Simp printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic)); 69238737Simp printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize); 70238737Simp printf("// off_dt_struct:\t0x%x\n", off_dt); 71238737Simp printf("// off_dt_strings:\t0x%x\n", off_str); 72238737Simp printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); 73238737Simp printf("// version:\t\t%d\n", version); 74238737Simp printf("// last_comp_version:\t%d\n", 75238737Simp fdt32_to_cpu(bph->last_comp_version)); 76238737Simp if (version >= 2) 77238737Simp printf("// boot_cpuid_phys:\t0x%x\n", 78238737Simp fdt32_to_cpu(bph->boot_cpuid_phys)); 79238737Simp 80238737Simp if (version >= 3) 81238737Simp printf("// size_dt_strings:\t0x%x\n", 82238737Simp fdt32_to_cpu(bph->size_dt_strings)); 83238737Simp if (version >= 17) 84238737Simp printf("// size_dt_struct:\t0x%x\n", 85238737Simp fdt32_to_cpu(bph->size_dt_struct)); 86238737Simp printf("\n"); 87238737Simp 88238737Simp for (i = 0; ; i++) { 89238737Simp addr = fdt64_to_cpu(p_rsvmap[i].address); 90238737Simp size = fdt64_to_cpu(p_rsvmap[i].size); 91238737Simp if (addr == 0 && size == 0) 92238737Simp break; 93238737Simp 94318102Sgonzo printf("/memreserve/ %#llx %#llx;\n", 95238737Simp (unsigned long long)addr, (unsigned long long)size); 96238737Simp } 97238737Simp 98238737Simp p = p_struct; 99238737Simp while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { 100238737Simp 101261215Simp dumpf("%04zx: tag: 0x%08x (%s)\n", 102261215Simp (uintptr_t)p - blob_off - 4, tag, tagname(tag)); 103238737Simp 104238737Simp if (tag == FDT_BEGIN_NODE) { 105238737Simp s = p; 106238737Simp p = PALIGN(p + strlen(s) + 1, 4); 107238737Simp 108238737Simp if (*s == '\0') 109238737Simp s = "/"; 110238737Simp 111238737Simp printf("%*s%s {\n", depth * shift, "", s); 112238737Simp 113238737Simp depth++; 114238737Simp continue; 115238737Simp } 116238737Simp 117238737Simp if (tag == FDT_END_NODE) { 118238737Simp depth--; 119238737Simp 120238737Simp printf("%*s};\n", depth * shift, ""); 121238737Simp continue; 122238737Simp } 123238737Simp 124238737Simp if (tag == FDT_NOP) { 125238737Simp printf("%*s// [NOP]\n", depth * shift, ""); 126238737Simp continue; 127238737Simp } 128238737Simp 129238737Simp if (tag != FDT_PROP) { 130238737Simp fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); 131238737Simp break; 132238737Simp } 133238737Simp sz = fdt32_to_cpu(GET_CELL(p)); 134238737Simp s = p_strings + fdt32_to_cpu(GET_CELL(p)); 135238737Simp if (version < 16 && sz >= 8) 136238737Simp p = PALIGN(p, 8); 137238737Simp t = p; 138238737Simp 139238737Simp p = PALIGN(p + sz, 4); 140238737Simp 141261215Simp dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s); 142261215Simp dumpf("%04zx: value\n", (uintptr_t)t - blob_off); 143238737Simp printf("%*s%s", depth * shift, "", s); 144261215Simp utilfdt_print_data(t, sz); 145238737Simp printf(";\n"); 146238737Simp } 147238737Simp} 148238737Simp 149261215Simp/* Usage related data. */ 150261215Simpstatic const char usage_synopsis[] = "fdtdump [options] <file>"; 151261215Simpstatic const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS; 152261215Simpstatic struct option const usage_long_opts[] = { 153261215Simp {"debug", no_argument, NULL, 'd'}, 154261215Simp {"scan", no_argument, NULL, 's'}, 155261215Simp USAGE_COMMON_LONG_OPTS 156261215Simp}; 157261215Simpstatic const char * const usage_opts_help[] = { 158261215Simp "Dump debug information while decoding the file", 159261215Simp "Scan for an embedded fdt in file", 160261215Simp USAGE_COMMON_OPTS_HELP 161261215Simp}; 162238737Simp 163318102Sgonzostatic bool valid_header(char *p, off_t len) 164318102Sgonzo{ 165318102Sgonzo if (len < sizeof(struct fdt_header) || 166318102Sgonzo fdt_magic(p) != FDT_MAGIC || 167318102Sgonzo fdt_version(p) > MAX_VERSION || 168318102Sgonzo fdt_last_comp_version(p) >= MAX_VERSION || 169318102Sgonzo fdt_totalsize(p) >= len || 170318102Sgonzo fdt_off_dt_struct(p) >= len || 171318102Sgonzo fdt_off_dt_strings(p) >= len) 172318102Sgonzo return 0; 173318102Sgonzo else 174318102Sgonzo return 1; 175318102Sgonzo} 176318102Sgonzo 177238737Simpint main(int argc, char *argv[]) 178238737Simp{ 179261215Simp int opt; 180261215Simp const char *file; 181238737Simp char *buf; 182261215Simp bool debug = false; 183261215Simp bool scan = false; 184261215Simp off_t len; 185238737Simp 186261215Simp while ((opt = util_getopt_long()) != EOF) { 187261215Simp switch (opt) { 188261215Simp case_USAGE_COMMON_FLAGS 189261215Simp 190261215Simp case 'd': 191261215Simp debug = true; 192261215Simp break; 193261215Simp case 's': 194261215Simp scan = true; 195261215Simp break; 196261215Simp } 197238737Simp } 198261215Simp if (optind != argc - 1) 199261215Simp usage("missing input filename"); 200261215Simp file = argv[optind]; 201238737Simp 202261215Simp buf = utilfdt_read_len(file, &len); 203261215Simp if (!buf) 204261215Simp die("could not read: %s\n", file); 205238737Simp 206261215Simp /* try and locate an embedded fdt in a bigger blob */ 207261215Simp if (scan) { 208318102Sgonzo unsigned char smagic[FDT_MAGIC_SIZE]; 209261215Simp char *p = buf; 210261215Simp char *endp = buf + len; 211261215Simp 212261215Simp fdt_set_magic(smagic, FDT_MAGIC); 213261215Simp 214261215Simp /* poor man's memmem */ 215318102Sgonzo while ((endp - p) >= FDT_MAGIC_SIZE) { 216318102Sgonzo p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE); 217261215Simp if (!p) 218261215Simp break; 219261215Simp if (fdt_magic(p) == FDT_MAGIC) { 220261215Simp /* try and validate the main struct */ 221261215Simp off_t this_len = endp - p; 222318102Sgonzo if (valid_header(p, this_len)) 223261215Simp break; 224261215Simp if (debug) 225261215Simp printf("%s: skipping fdt magic at offset %#zx\n", 226261215Simp file, p - buf); 227261215Simp } 228261215Simp ++p; 229261215Simp } 230318102Sgonzo if (!p || endp - p < sizeof(struct fdt_header)) 231261215Simp die("%s: could not locate fdt magic\n", file); 232261215Simp printf("%s: found fdt at offset %#zx\n", file, p - buf); 233261215Simp buf = p; 234318102Sgonzo } else if (!valid_header(buf, len)) 235318102Sgonzo die("%s: header is not valid\n", file); 236261215Simp 237261215Simp dump_blob(buf, debug); 238261215Simp 239238737Simp return 0; 240238737Simp} 241