[U-Boot] [PATCH 6/6] fdt: Add a Linux tool for reading values from FDT files

Joe Hershberger joe.hershberger at ni.com
Fri Aug 17 22:34:40 CEST 2012


Designed to be able to access itb files on a filesystem or an mtd
partition.

Supports print and list (like the fdt command) and also offset for
finding the offset and size of a given property in an FDT file.

This is especially helpful when reading properties from an ITB file.

Signed-off-by: Joe Hershberger <joe.hershberger at ni.com>
---
 Makefile                |   2 +-
 tools/fdtview/Makefile  |  52 ++++++
 tools/fdtview/fdtview.c | 483 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 536 insertions(+), 1 deletion(-)
 create mode 100644 tools/fdtview/Makefile
 create mode 100644 tools/fdtview/fdtview.c

diff --git a/Makefile b/Makefile
index 5ce5cc3..163fb4c 100644
--- a/Makefile
+++ b/Makefile
@@ -659,7 +659,7 @@ $(TIMESTAMP_FILE):
 		@LC_ALL=C date +'#define U_BOOT_TIME "%T"' >> $@.tmp
 		@cmp -s $@ $@.tmp && rm -f $@.tmp || mv -f $@.tmp $@
 
-easylogo env gdb:
+easylogo env fdtview gdb:
 	$(MAKE) -C tools/$@ all MTD_VERSION=${MTD_VERSION}
 gdbtools: gdb
 
diff --git a/tools/fdtview/Makefile b/tools/fdtview/Makefile
new file mode 100644
index 0000000..5f1488b
--- /dev/null
+++ b/tools/fdtview/Makefile
@@ -0,0 +1,52 @@
+
+include $(TOPDIR)/config.mk
+
+# Source files which exist outside the tools/fdtview directory
+EXT_SRC_FILES-y += lib/crc32.c
+EXT_SRC_FILES-y += lib/ctype.c
+EXT_SRC_FILES-y += lib/md5.c
+EXT_SRC_FILES-y += lib/sha1.c
+EXT_SRC_FILES-y += common/image.c
+
+# Source files located in the tools/fdtview directory
+SRC_FILES-y += fdtview.c
+
+# Flattened device tree objects
+LIBFDT_SRC_FILES-y += fdt.c
+LIBFDT_SRC_FILES-y += fdt_ro.c
+LIBFDT_SRC_FILES-y += fdt_rw.c
+LIBFDT_SRC_FILES-y += fdt_strerror.c
+LIBFDT_SRC_FILES-y += fdt_wip.c
+
+HOSTSRCS	+= $(addprefix $(SRCTREE)/,$(EXT_SRC_FILES-y))
+HOSTSRCS	+= $(addprefix $(SRCTREE)/tools/fdtview/,$(SRC_FILES-y))
+HOSTSRCS	+= $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_SRC_FILES-y))
+
+$(warning $(HOSTSRCS))
+#
+# Use native tools and options
+# Define __KERNEL_STRICT_NAMES to prevent typedef overlaps
+#
+HOSTCPPFLAGS   = -idirafter $(SRCTREE)/include \
+		-idirafter $(OBJTREE)/include2 \
+		-idirafter $(OBJTREE)/include \
+	        -I $(SRCTREE)/libfdt \
+		-I $(SRCTREE)/tools \
+		-DUSE_HOSTCC -D__KERNEL_STRICT_NAMES
+
+all :	$(obj)fdtview$(SFX)
+
+$(obj)fdtview$(SFX) : $(HOSTSRCS)
+	$(HOSTCC) $(HOSTCFLAGS_NOPED) $(HOSTLDFLAGS) -o $@ $(HOSTSRCS)
+	$(HOSTSTRIP) $@
+
+clean:
+	rm -rf $(obj)*.o $(obj)fdtview
+
+#########################################################################
+
+include $(TOPDIR)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/tools/fdtview/fdtview.c b/tools/fdtview/fdtview.c
new file mode 100644
index 0000000..70b3243
--- /dev/null
+++ b/tools/fdtview/fdtview.c
@@ -0,0 +1,483 @@
+
+#include "os_support.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <sha1.h>
+#include "fdt_host.h"
+#include <image.h>
+#include <linux/ctype.h>
+#include <mtd/mtd-user.h>
+
+#define MAX_LEVEL	32		/* how deeply nested we will go */
+
+static void usage(void);
+
+struct fdtview_params {
+	char *path;
+	char *propname;
+	char *imagefile;
+	char *cmdname;
+	int lflag;
+	int oflag;
+	int pflag;
+} params;
+
+/*
+ * Heuristic to guess if this is a string or concatenated strings.
+ */
+static int is_printable_string(const void *data, int len)
+{
+	const char *s = data;
+
+	/* zero length is not */
+	if (len == 0)
+		return 0;
+
+	/* must terminate with zero */
+	if (s[len - 1] != '\0' && s[len - 1] != '\n')
+		return 0;
+
+	/* printable or a null byte (concatenated strings) */
+	while (((*s == '\0') || isprint(*s) || isspace(*s)) && (len > 0)) {
+		/*
+		 * If we see a null, there are three possibilities:
+		 * 1) If len == 1, it is the end of the string, printable
+		 * 2) Next character also a null, not printable.
+		 * 3) Next character not a null, continue to check.
+		 */
+		if (s[0] == '\0') {
+			if (len == 1)
+				return 1;
+			if (s[1] == '\0')
+				return 0;
+		}
+		s++;
+		len--;
+	}
+
+	/* Not the null termination, or not done yet: not printable */
+	if (*s != '\0' || len != 0)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Print the property in the best format, a heuristic guess.  Print as
+ * a string, concatenated strings, a byte, word, double word, or (if all
+ * else fails) it is printed as a stream of bytes.
+ */
+static void print_data(const void *data, int len)
+{
+	int j;
+
+	/* no data, don't print */
+	if (len == 0)
+		return;
+
+	/*
+	 * It is a string, but it may have multiple strings (embedded '\0's).
+	 */
+	if (is_printable_string(data, len)) {
+		printf("\"");
+		j = 0;
+		while (j < len) {
+			if (j > 0)
+				printf("\", \"");
+			printf(data);
+			j    += strlen(data) + 1;
+			data += strlen(data) + 1;
+		}
+		printf("\"");
+		return;
+	}
+
+	if ((len % 4) == 0) {
+		const unsigned int *p;
+
+		printf("<");
+		for (j = 0, p = data; j < len/4; j++)
+			printf("0x%x%s",
+				fdt32_to_cpu(p[j]), j < (len/4 - 1) ? " " : "");
+		printf(">");
+	} else { /* anything else... hexdump */
+		const unsigned char *s;
+
+		printf("[");
+		for (j = 0, s = data; j < len; j++)
+			printf("%02x%s", s[j], j < len - 1 ? " " : "");
+		printf("]");
+	}
+}
+
+/*
+ * Recursively print (a portion of) the working_fdt.  The depth parameter
+ * determines how deeply nested the fdt is printed.
+ */
+static int fdt_print(unsigned char *working_fdt, const char *pathp,
+			char *prop, int depth)
+{
+	static char tabs[MAX_LEVEL+1] =
+		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
+		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+	const void *nodep;	/* property node pointer */
+	int  nodeoffset;	/* node offset from libfdt */
+	int  nextoffset;	/* next node offset from libfdt */
+	uint32_t tag;		/* tag */
+	int  len;		/* length of the property */
+	int  level = 0;		/* keep track of nesting level */
+	const struct fdt_property *fdt_prop;
+
+	nodeoffset = fdt_path_offset(working_fdt, pathp);
+	if (nodeoffset < 0) {
+		/*
+		 * Not found or something else bad happened.
+		 */
+		printf("libfdt fdt_path_offset() returned %s\n",
+			fdt_strerror(nodeoffset));
+		return 1;
+	}
+	/*
+	 * The user passed in a property as well as node path.
+	 * Print only the given property and then return.
+	 */
+	if (prop) {
+		nodep = fdt_getprop(working_fdt, nodeoffset, prop, &len);
+		if (len == 0) {
+			/* no property value */
+			printf("%s %s\n", pathp, prop);
+			return 0;
+		} else if (len > 0) {
+			printf("%s = ", prop);
+			print_data(nodep, len);
+			printf("\n");
+			return 0;
+		} else {
+			printf("libfdt fdt_getprop(): %s\n",
+				fdt_strerror(len));
+			return 1;
+		}
+	}
+
+	/*
+	 * The user passed in a node path and no property,
+	 * print the node and all subnodes.
+	 */
+	while (level >= 0) {
+		tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset);
+		switch (tag) {
+		case FDT_BEGIN_NODE:
+			pathp = fdt_get_name(working_fdt, nodeoffset, NULL);
+			if (level <= depth) {
+				if (pathp == NULL)
+					pathp = "/* NULL pointer error */";
+				if (*pathp == '\0')
+					pathp = "/";	/* root is nameless */
+				printf("%s%s {\n",
+					&tabs[MAX_LEVEL - level], pathp);
+			}
+			level++;
+			if (level >= MAX_LEVEL) {
+				printf("Nested too deep, aborting.\n");
+				return 1;
+			}
+			break;
+		case FDT_END_NODE:
+			level--;
+			if (level <= depth)
+				printf("%s};\n", &tabs[MAX_LEVEL - level]);
+			if (level == 0)
+				level = -1;		/* exit the loop */
+			break;
+		case FDT_PROP:
+			fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset,
+					sizeof(*fdt_prop));
+			pathp    = fdt_string(working_fdt,
+					fdt32_to_cpu(fdt_prop->nameoff));
+			len      = fdt32_to_cpu(fdt_prop->len);
+			nodep    = fdt_prop->data;
+			if (len < 0) {
+				printf("libfdt fdt_getprop(): %s\n",
+					fdt_strerror(len));
+				return 1;
+			} else if (len == 0) {
+				/* the property has no value */
+				if (level <= depth)
+					printf("%s%s;\n",
+						&tabs[MAX_LEVEL - level],
+						pathp);
+			} else {
+				if (level <= depth) {
+					printf("%s%s = ",
+						&tabs[MAX_LEVEL - level],
+						pathp);
+					print_data(nodep, len);
+					printf(";\n");
+				}
+			}
+			break;
+		case FDT_NOP:
+			printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]);
+			break;
+		case FDT_END:
+			return 1;
+		default:
+			if (level <= depth)
+				printf("Unknown tag 0x%08X\n", tag);
+			return 1;
+		}
+		nodeoffset = nextoffset;
+	}
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int ifd = -1;
+	struct stat sbuf;
+	unsigned char *working_fdt;
+	int retval = 0;
+	struct mtd_info_user mtd;
+	off_t file_size = 0;
+	int mmap_failed = 0;
+
+	params.cmdname = *argv;
+	params.lflag = 0;
+	params.oflag = 0;
+	params.pflag = 0;
+
+	while (--argc > 0 && **++argv == '-') {
+		while (*++*argv) {
+			switch (**argv) {
+			case 'l':
+				if (argc <= 1)
+					usage();
+				if (argc >= 3) {
+					params.path = *++argv;
+					--argc;
+				} else {
+					params.path = NULL;
+				}
+				if (argc == 3) {
+					params.propname = *++argv;
+					--argc;
+				} else {
+					params.propname = NULL;
+				}
+				params.lflag = 1;
+				goto NXTARG;
+			case 'o':
+				--argc;
+				if (--argc <= 1)
+					usage();
+				params.path = *++argv;
+				params.propname = *++argv;
+				params.oflag = 1;
+				goto NXTARG;
+			case 'p':
+				if (argc <= 1)
+					usage();
+				if (argc >= 3) {
+					params.path = *++argv;
+					--argc;
+				} else {
+					params.path = NULL;
+				}
+				if (argc == 3) {
+					params.propname = *++argv;
+					--argc;
+				} else {
+					params.propname = NULL;
+				}
+				params.pflag = 1;
+				goto NXTARG;
+			default:
+				usage();
+			}
+		}
+NXTARG:;
+	}
+
+	if (argc != 1)
+		usage();
+
+	if (!params.lflag && !params.oflag && !params.pflag)
+		usage();
+
+	params.imagefile = *argv;
+
+	ifd = open(params.imagefile, O_RDONLY|O_BINARY|O_SYNC);
+
+	if (ifd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			params.cmdname, params.imagefile,
+			strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(ifd, &sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			params.cmdname, params.imagefile,
+			strerror(errno));
+		exit(EXIT_FAILURE);
+	} else {
+		file_size = sbuf.st_size;
+	}
+
+	if ((sbuf.st_rdev & 0xFF00) == 0x1F00) {
+		fprintf(stderr, "%s: Can't access the block interface to %s\n",
+			params.cmdname, params.imagefile);
+		exit(EXIT_FAILURE);
+	}
+	if ((sbuf.st_rdev & 0xFF00) == 0x5A00) {
+		if (ioctl(ifd, MEMGETINFO, mtd) < 0) {
+			fprintf(stderr, "%s: Can't query mem info for %s: %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			exit(EXIT_FAILURE);
+		} else {
+			file_size = mtd.size;
+		}
+	}
+
+	if ((unsigned)file_size < sizeof(image_header_t)) {
+		fprintf(stderr,
+			"%s: Bad size: \"%s\" is not valid image\n",
+			params.cmdname, params.imagefile);
+		exit(EXIT_FAILURE);
+	}
+
+	working_fdt = mmap(0, file_size, PROT_READ, MAP_SHARED, ifd, 0);
+	if (working_fdt == MAP_FAILED) {
+		int readsize;
+		int totalsize;
+		mmap_failed = 1;
+
+		printf("mmap() failed.  Falling back to read.");
+		working_fdt = malloc(sizeof(image_header_t));
+		if (working_fdt == NULL) {
+			fprintf(stderr, "%s: malloc of %d"
+				" bytes (header) failed: %s\n",
+				params.cmdname, (int) file_size,
+				strerror(errno));
+			retval = 1;
+			goto error;
+		}
+		readsize = read(ifd, working_fdt, sizeof(image_header_t));
+		if (readsize < 0) {
+			fprintf(stderr, "%s: Can't read header from %s: %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			retval = readsize;
+			goto error;
+		}
+		retval = fdt_check_header((void *) working_fdt);
+		if (retval < 0) {
+			fprintf(stderr, "%s: Invalid image %s\n",
+				params.cmdname, params.imagefile);
+			goto error;
+		}
+		totalsize = fdt_totalsize(working_fdt);
+		if (totalsize < 0) {
+			fprintf(stderr, "%s: Invalid image size: %d\n",
+				params.cmdname, totalsize);
+			retval = totalsize;
+			goto error;
+		}
+		if (file_size > totalsize)
+			file_size = totalsize;
+		working_fdt = realloc(working_fdt, file_size);
+		if (working_fdt == NULL) {
+			fprintf(stderr, "%s: malloc of %d bytes failed: %s\n",
+				params.cmdname, (int) file_size,
+				strerror(errno));
+			retval = 1;
+			goto error;
+		}
+		if (read(ifd, working_fdt + readsize,
+		    file_size - readsize) < 0) {
+			fprintf(stderr, "%s: Can't read %s: %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			retval = readsize;
+			goto error;
+		}
+	}
+
+	retval = fdt_check_header((void *)working_fdt);
+	if (retval < 0) {
+		fprintf(stderr, "%s: Invalid image %s\n",
+			params.cmdname, params.imagefile);
+		goto error;
+	}
+
+	if (params.oflag) {
+		int offset;
+		offset = fdt_path_offset(working_fdt, params.path);
+		if (offset > 0) {
+			int propLength = 0;
+			const unsigned char *propData = (const uint8_t *)
+				fdt_getprop(working_fdt, offset,
+				    params.propname, &propLength);
+			if (propLength >= 0)
+				printf("%d %d\n", propData - working_fdt,
+				    propLength);
+		} else {
+			retval = offset;
+			goto error;
+		}
+	} else if (params.lflag || params.pflag) {
+		int depth = MAX_LEVEL;	/* how deep to print */
+		int  ret;		/* return value */
+		static char root[2] = "/";
+
+		/*
+		 * list is an alias for print, but limited to 1 level
+		 */
+		if (params.lflag)
+			depth = 1;
+
+		/*
+		 * Get the starting path.  The root node is an oddball,
+		 * the offset is zero and has no name.
+		 */
+		if (params.path == NULL)
+			params.path = root;
+
+		ret = fdt_print(working_fdt, params.path, params.propname,
+			 depth);
+		if (ret != 0)
+			return ret;
+	}
+
+error:
+	if (mmap_failed)
+		free(working_fdt);
+	else
+		munmap((void *)working_fdt, file_size);
+
+	close(ifd);
+
+	exit(retval);
+}
+
+
+static void usage()
+{
+	fprintf(stderr, "       %s [-l [path [propname]] | -o path propname |"
+					" -p [path [propname]]] image\n"
+			 "          -l ==> Print one level starting at <path>\n"
+			 "          -o ==> print the offset and size of a property\n"
+			 "          -p ==> Recursive print starting at <path>\n",
+		params.cmdname);
+
+	exit(EXIT_FAILURE);
+}
-- 
1.7.11.5



More information about the U-Boot mailing list