From b2543fc875f0cd30231584beb97ccf31bf8a0f88 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 29 Aug 2005 14:58:27 +1000 Subject: [PATCH] Add ftdump utility, contributed by Pantelis Antoniou. --- Makefile | 17 +++-- flat_dt.h | 3 +- ftdump.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 ftdump.c diff --git a/Makefile b/Makefile index 0ee0777..8439f56 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,21 @@ -TARGETS = dtc +TARGETS = dtc ftdump CFLAGS = -Wall -g BISON = bison -OBJS = dtc.o livetree.o flattree.o data.o treesource.o fstree.o \ - dtc-parser.tab.o lex.yy.o +DTC_OBJS = dtc.o livetree.o flattree.o data.o treesource.o fstree.o \ + dtc-parser.tab.o lex.yy.o -DEPFILES = $(OBJS:.o=.d) +OBJS = $(DTC_OBJS) libdt.o ftdump.o -all: $(DEPFILES) $(TARGETS) +DEPFILES = $(DTC_OBJS:.o=.d) -dtc: $(OBJS) +all: $(TARGETS) + +dtc: $(DTC_OBJS) + $(LINK.c) -o $@ $^ + +ftdump: ftdump.o $(LINK.c) -o $@ $^ dtc-parser.tab.c dtc-parser.tab.h dtc-parser.output: dtc-parser.y diff --git a/flat_dt.h b/flat_dt.h index 28b4d03..5b1dcb6 100644 --- a/flat_dt.h +++ b/flat_dt.h @@ -7,7 +7,8 @@ #define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */ #define OF_DT_END_NODE 0x2 /* End node */ #define OF_DT_PROP 0x3 /* Property: name off, - size, content */ + size, content */ +#define OF_DT_NOP 0x4 /* nop */ #define OF_DT_END 0x9 struct boot_param_header { diff --git a/ftdump.c b/ftdump.c new file mode 100644 index 0000000..4d4354b --- /dev/null +++ b/ftdump.c @@ -0,0 +1,188 @@ +/* + * ftdump.c - Contributed by Pantelis Antoniou + */ + +#include +#include +#include +#include +#include +#include + +#include "flat_dt.h" + +#define cpu_to_be16(x) htons(x) +#define be16_to_cpu(x) ntohs(x) + +#define cpu_to_be32(x) htonl(x) +#define be32_to_cpu(x) ntohl(x) + +#if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_be64(x) (x) +#define be64_to_cpu(x) (x) +#else +#define cpu_to_be64(x) bswap_64(x) +#define be64_to_cpu(x) bswap_64(x) +#endif + +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) +#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) +#define GET_CELL(p) (p += 4, *((uint32_t *)(p-4))) + +static int is_printable_string(const void *data, int len) +{ + const char *s = data; + const char *ss; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + ss = s; + while (*s && isprint(*s)) + s++; + + /* not zero, or not done yet */ + if (*s != '\0' || (s + 1 - ss) < len) + return 0; + + return 1; +} + +static void print_data(const void *data, int len) +{ + int i; + const uint8_t *s; + + /* no data, don't print */ + if (len == 0) + return; + + if (is_printable_string(data, len)) { + printf(" = \"%s\"", (char *)data); + } else if ((len % 4) == 0) { + printf(" = <"); + for (i = 0; i < len; i += 4) + printf("%08x%s", *((uint32_t *)data + i), + i < (len - 4) ? " " : ""); + printf(">"); + } else { + printf(" = ["); + for (i = 0, s = data; i < len; i++) + printf("%02x%s", s[i], i < len - 1 ? " " : ""); + printf("]"); + } +} + +static void dump_blob(void *blob) +{ + struct boot_param_header *bph = blob; + struct reserve_entry *p_rsvmap = + (struct reserve_entry *)(blob + + be32_to_cpu(bph->off_mem_rsvmap)); + char *p_struct = blob + be32_to_cpu(bph->off_dt_struct); + char *p_strings = blob + be32_to_cpu(bph->off_dt_strings); + uint32_t version = be32_to_cpu(bph->version); + uint32_t tag; + char *p; + char *s, *t; + int depth, sz, shift; + int i; + uint64_t addr, size; + + depth = 0; + shift = 4; + + printf("// Version 0x%x tree\n", version); + for (i = 0; ; i++) { + addr = be64_to_cpu(p_rsvmap[i].address); + size = be64_to_cpu(p_rsvmap[i].size); + if (addr == 0 && size == 0) + break; + + printf("/memreserve/ %llx %llx;\n", + (unsigned long long)addr, (unsigned long long)size); + } + + p = p_struct; + while ((tag = be32_to_cpu(GET_CELL(p))) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = p; + p = PALIGN(p + strlen(s) + 1, 4); + + if (*s == '\0') + s = "/"; + + printf("%*s%s {\n", depth * shift, "", s); + + depth++; + continue; + } + + if (tag == OF_DT_END_NODE) { + depth--; + + printf("%*s};\n", depth * shift, ""); + continue; + } + + if (tag == OF_DT_NOP) { + printf("%*s// [NOP]\n", depth * shift, ""); + continue; + } + + if (tag != OF_DT_PROP) { + fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); + break; + } + sz = GET_CELL(p); + s = p_strings + be32_to_cpu(GET_CELL(p)); + if (version < 0x10 && sz >= 8) + p = PALIGN(p, 8); + t = p; + + p = PALIGN(p + sz, 4); + + printf("%*s%s", depth * shift, "", s); + print_data(t, sz); + printf(";\n"); + } +} + + +int main(int argc, char *argv[]) +{ + FILE *fp; + char buf[16384]; /* 16k max */ + int size; + + if (argc < 2) { + fprintf(stderr, "supply input filename\n"); + return 5; + } + + fp = fopen(argv[1], "rb"); + if (fp == NULL) { + fprintf(stderr, "unable to open %s\n", argv[1]); + return 10; + } + + size = fread(buf, 1, sizeof(buf), fp); + if (size == sizeof(buf)) { /* too large */ + fprintf(stderr, "file too large\n"); + return 10; + } + + dump_blob(buf); + + fclose(fp); + + return 0; +}