xref: /openbmc/u-boot/tools/fdtgrep.c (revision dd0ee9ea857c4e4d927ae41791c1626fd57c301d)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
21043d0a0SSimon Glass /*
31043d0a0SSimon Glass  * Copyright (c) 2013, Google Inc.
41043d0a0SSimon Glass  * Written by Simon Glass <sjg@chromium.org>
51043d0a0SSimon Glass  *
61043d0a0SSimon Glass  * Perform a grep of an FDT either displaying the source subset or producing
71043d0a0SSimon Glass  * a new .dtb subset which can be used as required.
81043d0a0SSimon Glass  */
91043d0a0SSimon Glass 
101043d0a0SSimon Glass #include <assert.h>
111043d0a0SSimon Glass #include <ctype.h>
12d2bf1152SMasahiro Yamada #include <errno.h>
131043d0a0SSimon Glass #include <getopt.h>
14d2bf1152SMasahiro Yamada #include <fcntl.h>
15d2bf1152SMasahiro Yamada #include <stdbool.h>
161043d0a0SSimon Glass #include <stdio.h>
171043d0a0SSimon Glass #include <stdlib.h>
181043d0a0SSimon Glass #include <string.h>
191043d0a0SSimon Glass #include <unistd.h>
201043d0a0SSimon Glass 
21ae9ace70SMasahiro Yamada #include "fdt_host.h"
22b95a5190SJan Kundrát #include "libfdt_internal.h"
231043d0a0SSimon Glass 
241043d0a0SSimon Glass /* Define DEBUG to get some debugging output on stderr */
251043d0a0SSimon Glass #ifdef DEBUG
261043d0a0SSimon Glass #define debug(a, b...) fprintf(stderr, a, ## b)
271043d0a0SSimon Glass #else
281043d0a0SSimon Glass #define debug(a, b...)
291043d0a0SSimon Glass #endif
301043d0a0SSimon Glass 
311043d0a0SSimon Glass /* A linked list of values we are grepping for */
321043d0a0SSimon Glass struct value_node {
331043d0a0SSimon Glass 	int type;		/* Types this value matches (FDT_IS... mask) */
341043d0a0SSimon Glass 	int include;		/* 1 to include matches, 0 to exclude */
351043d0a0SSimon Glass 	const char *string;	/* String to match */
361043d0a0SSimon Glass 	struct value_node *next;	/* Pointer to next node, or NULL */
371043d0a0SSimon Glass };
381043d0a0SSimon Glass 
391043d0a0SSimon Glass /* Output formats we support */
401043d0a0SSimon Glass enum output_t {
411043d0a0SSimon Glass 	OUT_DTS,		/* Device tree source */
421043d0a0SSimon Glass 	OUT_DTB,		/* Valid device tree binary */
431043d0a0SSimon Glass 	OUT_BIN,		/* Fragment of .dtb, for hashing */
441043d0a0SSimon Glass };
451043d0a0SSimon Glass 
461043d0a0SSimon Glass /* Holds information which controls our output and options */
471043d0a0SSimon Glass struct display_info {
481043d0a0SSimon Glass 	enum output_t output;	/* Output format */
491043d0a0SSimon Glass 	int add_aliases;	/* Add aliases node to output */
501043d0a0SSimon Glass 	int all;		/* Display all properties/nodes */
511043d0a0SSimon Glass 	int colour;		/* Display output in ANSI colour */
521043d0a0SSimon Glass 	int region_list;	/* Output a region list */
531043d0a0SSimon Glass 	int flags;		/* Flags (FDT_REG_...) */
541043d0a0SSimon Glass 	int list_strings;	/* List strings in string table */
551043d0a0SSimon Glass 	int show_offset;	/* Show offset */
561043d0a0SSimon Glass 	int show_addr;		/* Show address */
571043d0a0SSimon Glass 	int header;		/* Output an FDT header */
581043d0a0SSimon Glass 	int diff;		/* Show +/- diff markers */
591043d0a0SSimon Glass 	int include_root;	/* Include the root node and all properties */
601043d0a0SSimon Glass 	int remove_strings;	/* Remove unused strings */
611043d0a0SSimon Glass 	int show_dts_version;	/* Put '/dts-v1/;' on the first line */
621043d0a0SSimon Glass 	int types_inc;		/* Mask of types that we include (FDT_IS...) */
631043d0a0SSimon Glass 	int types_exc;		/* Mask of types that we exclude (FDT_IS...) */
641043d0a0SSimon Glass 	int invert;		/* Invert polarity of match */
651043d0a0SSimon Glass 	struct value_node *value_head;	/* List of values to match */
661043d0a0SSimon Glass 	const char *output_fname;	/* Output filename */
671043d0a0SSimon Glass 	FILE *fout;		/* File to write dts/dtb output */
681043d0a0SSimon Glass };
691043d0a0SSimon Glass 
report_error(const char * where,int err)701043d0a0SSimon Glass static void report_error(const char *where, int err)
711043d0a0SSimon Glass {
721043d0a0SSimon Glass 	fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
731043d0a0SSimon Glass }
741043d0a0SSimon Glass 
751043d0a0SSimon Glass /* Supported ANSI colours */
761043d0a0SSimon Glass enum {
771043d0a0SSimon Glass 	COL_BLACK,
781043d0a0SSimon Glass 	COL_RED,
791043d0a0SSimon Glass 	COL_GREEN,
801043d0a0SSimon Glass 	COL_YELLOW,
811043d0a0SSimon Glass 	COL_BLUE,
821043d0a0SSimon Glass 	COL_MAGENTA,
831043d0a0SSimon Glass 	COL_CYAN,
841043d0a0SSimon Glass 	COL_WHITE,
851043d0a0SSimon Glass 
861043d0a0SSimon Glass 	COL_NONE = -1,
871043d0a0SSimon Glass };
881043d0a0SSimon Glass 
891043d0a0SSimon Glass /**
901043d0a0SSimon Glass  * print_ansi_colour() - Print out the ANSI sequence for a colour
911043d0a0SSimon Glass  *
921043d0a0SSimon Glass  * @fout:	Output file
931043d0a0SSimon Glass  * @col:	Colour to output (COL_...), or COL_NONE to reset colour
941043d0a0SSimon Glass  */
print_ansi_colour(FILE * fout,int col)951043d0a0SSimon Glass static void print_ansi_colour(FILE *fout, int col)
961043d0a0SSimon Glass {
971043d0a0SSimon Glass 	if (col == COL_NONE)
981043d0a0SSimon Glass 		fprintf(fout, "\033[0m");
991043d0a0SSimon Glass 	else
1001043d0a0SSimon Glass 		fprintf(fout, "\033[1;%dm", col + 30);
1011043d0a0SSimon Glass }
1021043d0a0SSimon Glass 
1031043d0a0SSimon Glass 
1041043d0a0SSimon Glass /**
1051043d0a0SSimon Glass  * value_add() - Add a new value to our list of things to grep for
1061043d0a0SSimon Glass  *
1071043d0a0SSimon Glass  * @disp:	Display structure, holding info about our options
1081043d0a0SSimon Glass  * @headp:	Pointer to header pointer of list
1091043d0a0SSimon Glass  * @type:	Type of this value (FDT_IS_...)
1101043d0a0SSimon Glass  * @include:	1 if we want to include matches, 0 to exclude
1111043d0a0SSimon Glass  * @str:	String value to match
1121043d0a0SSimon Glass  */
value_add(struct display_info * disp,struct value_node ** headp,int type,int include,const char * str)1131043d0a0SSimon Glass static int value_add(struct display_info *disp, struct value_node **headp,
1141043d0a0SSimon Glass 		     int type, int include, const char *str)
1151043d0a0SSimon Glass {
1161043d0a0SSimon Glass 	struct value_node *node;
1171043d0a0SSimon Glass 
1181043d0a0SSimon Glass 	/*
1191043d0a0SSimon Glass 	 * Keep track of which types we are excluding/including. We don't
1201043d0a0SSimon Glass 	 * allow both including and excluding things, because it doesn't make
1211043d0a0SSimon Glass 	 * sense. 'Including' means that everything not mentioned is
1221043d0a0SSimon Glass 	 * excluded. 'Excluding' means that everything not mentioned is
1231043d0a0SSimon Glass 	 * included. So using the two together would be meaningless.
1241043d0a0SSimon Glass 	 */
1251043d0a0SSimon Glass 	if (include)
1261043d0a0SSimon Glass 		disp->types_inc |= type;
1271043d0a0SSimon Glass 	else
1281043d0a0SSimon Glass 		disp->types_exc |= type;
1291043d0a0SSimon Glass 	if (disp->types_inc & disp->types_exc & type) {
1301043d0a0SSimon Glass 		fprintf(stderr,
1311043d0a0SSimon Glass 			"Cannot use both include and exclude for '%s'\n", str);
1321043d0a0SSimon Glass 		return -1;
1331043d0a0SSimon Glass 	}
1341043d0a0SSimon Glass 
1351043d0a0SSimon Glass 	str = strdup(str);
136*dd0ee9eaSSimon Glass 	if (!str)
137*dd0ee9eaSSimon Glass 		goto err_mem;
1381043d0a0SSimon Glass 	node = malloc(sizeof(*node));
139*dd0ee9eaSSimon Glass 	if (!node)
140*dd0ee9eaSSimon Glass 		goto err_mem;
1411043d0a0SSimon Glass 	node->next = *headp;
1421043d0a0SSimon Glass 	node->type = type;
1431043d0a0SSimon Glass 	node->include = include;
1441043d0a0SSimon Glass 	node->string = str;
1451043d0a0SSimon Glass 	*headp = node;
1461043d0a0SSimon Glass 
1471043d0a0SSimon Glass 	return 0;
148*dd0ee9eaSSimon Glass err_mem:
149*dd0ee9eaSSimon Glass 	fprintf(stderr, "Out of memory\n");
150*dd0ee9eaSSimon Glass 	return -1;
1511043d0a0SSimon Glass }
1521043d0a0SSimon Glass 
util_is_printable_string(const void * data,int len)1531043d0a0SSimon Glass static bool util_is_printable_string(const void *data, int len)
1541043d0a0SSimon Glass {
1551043d0a0SSimon Glass 	const char *s = data;
1561043d0a0SSimon Glass 	const char *ss, *se;
1571043d0a0SSimon Glass 
1581043d0a0SSimon Glass 	/* zero length is not */
1591043d0a0SSimon Glass 	if (len == 0)
1601043d0a0SSimon Glass 		return 0;
1611043d0a0SSimon Glass 
1621043d0a0SSimon Glass 	/* must terminate with zero */
1631043d0a0SSimon Glass 	if (s[len - 1] != '\0')
1641043d0a0SSimon Glass 		return 0;
1651043d0a0SSimon Glass 
1661043d0a0SSimon Glass 	se = s + len;
1671043d0a0SSimon Glass 
1681043d0a0SSimon Glass 	while (s < se) {
1691043d0a0SSimon Glass 		ss = s;
1701043d0a0SSimon Glass 		while (s < se && *s && isprint((unsigned char)*s))
1711043d0a0SSimon Glass 			s++;
1721043d0a0SSimon Glass 
1731043d0a0SSimon Glass 		/* not zero, or not done yet */
1741043d0a0SSimon Glass 		if (*s != '\0' || s == ss)
1751043d0a0SSimon Glass 			return 0;
1761043d0a0SSimon Glass 
1771043d0a0SSimon Glass 		s++;
1781043d0a0SSimon Glass 	}
1791043d0a0SSimon Glass 
1801043d0a0SSimon Glass 	return 1;
1811043d0a0SSimon Glass }
1821043d0a0SSimon Glass 
utilfdt_print_data(const char * data,int len)1831043d0a0SSimon Glass static void utilfdt_print_data(const char *data, int len)
1841043d0a0SSimon Glass {
1851043d0a0SSimon Glass 	int i;
1861043d0a0SSimon Glass 	const char *p = data;
1871043d0a0SSimon Glass 	const char *s;
1881043d0a0SSimon Glass 
1891043d0a0SSimon Glass 	/* no data, don't print */
1901043d0a0SSimon Glass 	if (len == 0)
1911043d0a0SSimon Glass 		return;
1921043d0a0SSimon Glass 
1931043d0a0SSimon Glass 	if (util_is_printable_string(data, len)) {
1941043d0a0SSimon Glass 		printf(" = ");
1951043d0a0SSimon Glass 
1961043d0a0SSimon Glass 		s = data;
1971043d0a0SSimon Glass 		do {
1981043d0a0SSimon Glass 			printf("\"%s\"", s);
1991043d0a0SSimon Glass 			s += strlen(s) + 1;
2001043d0a0SSimon Glass 			if (s < data + len)
2011043d0a0SSimon Glass 				printf(", ");
2021043d0a0SSimon Glass 		} while (s < data + len);
2031043d0a0SSimon Glass 
2041043d0a0SSimon Glass 	} else if ((len % 4) == 0) {
2051043d0a0SSimon Glass 		const uint32_t *cell = (const uint32_t *)data;
2061043d0a0SSimon Glass 
2071043d0a0SSimon Glass 		printf(" = <");
2081043d0a0SSimon Glass 		for (i = 0, len /= 4; i < len; i++)
2091043d0a0SSimon Glass 			printf("0x%08x%s", fdt32_to_cpu(cell[i]),
2101043d0a0SSimon Glass 			       i < (len - 1) ? " " : "");
2111043d0a0SSimon Glass 		printf(">");
2121043d0a0SSimon Glass 	} else {
2131043d0a0SSimon Glass 		printf(" = [");
2141043d0a0SSimon Glass 		for (i = 0; i < len; i++)
2151043d0a0SSimon Glass 			printf("%02x%s", *p++, i < len - 1 ? " " : "");
2161043d0a0SSimon Glass 		printf("]");
2171043d0a0SSimon Glass 	}
2181043d0a0SSimon Glass }
2191043d0a0SSimon Glass 
2201043d0a0SSimon Glass /**
2211043d0a0SSimon Glass  * display_fdt_by_regions() - Display regions of an FDT source
2221043d0a0SSimon Glass  *
2231043d0a0SSimon Glass  * This dumps an FDT as source, but only certain regions of it. This is the
2241043d0a0SSimon Glass  * final stage of the grep - we have a list of regions we want to display,
2251043d0a0SSimon Glass  * and this function displays them.
2261043d0a0SSimon Glass  *
2271043d0a0SSimon Glass  * @disp:	Display structure, holding info about our options
2281043d0a0SSimon Glass  * @blob:	FDT blob to display
2291043d0a0SSimon Glass  * @region:	List of regions to display
2301043d0a0SSimon Glass  * @count:	Number of regions
2311043d0a0SSimon Glass  */
display_fdt_by_regions(struct display_info * disp,const void * blob,struct fdt_region region[],int count)2321043d0a0SSimon Glass static int display_fdt_by_regions(struct display_info *disp, const void *blob,
2331043d0a0SSimon Glass 		struct fdt_region region[], int count)
2341043d0a0SSimon Glass {
2351043d0a0SSimon Glass 	struct fdt_region *reg = region, *reg_end = region + count;
2361043d0a0SSimon Glass 	uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
2371043d0a0SSimon Glass 	int base = fdt_off_dt_struct(blob);
2381043d0a0SSimon Glass 	int version = fdt_version(blob);
2391043d0a0SSimon Glass 	int offset, nextoffset;
2401043d0a0SSimon Glass 	int tag, depth, shift;
2411043d0a0SSimon Glass 	FILE *f = disp->fout;
2421043d0a0SSimon Glass 	uint64_t addr, size;
2431043d0a0SSimon Glass 	int in_region;
2441043d0a0SSimon Glass 	int file_ofs;
2451043d0a0SSimon Glass 	int i;
2461043d0a0SSimon Glass 
2471043d0a0SSimon Glass 	if (disp->show_dts_version)
2481043d0a0SSimon Glass 		fprintf(f, "/dts-v1/;\n");
2491043d0a0SSimon Glass 
2501043d0a0SSimon Glass 	if (disp->header) {
2511043d0a0SSimon Glass 		fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
2521043d0a0SSimon Glass 		fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
2531043d0a0SSimon Glass 			fdt_totalsize(blob));
2541043d0a0SSimon Glass 		fprintf(f, "// off_dt_struct:\t0x%x\n",
2551043d0a0SSimon Glass 			fdt_off_dt_struct(blob));
2561043d0a0SSimon Glass 		fprintf(f, "// off_dt_strings:\t0x%x\n",
2571043d0a0SSimon Glass 			fdt_off_dt_strings(blob));
2581043d0a0SSimon Glass 		fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
2591043d0a0SSimon Glass 		fprintf(f, "// version:\t\t%d\n", version);
2601043d0a0SSimon Glass 		fprintf(f, "// last_comp_version:\t%d\n",
2611043d0a0SSimon Glass 			fdt_last_comp_version(blob));
2621043d0a0SSimon Glass 		if (version >= 2) {
2631043d0a0SSimon Glass 			fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
2641043d0a0SSimon Glass 				fdt_boot_cpuid_phys(blob));
2651043d0a0SSimon Glass 		}
2661043d0a0SSimon Glass 		if (version >= 3) {
2671043d0a0SSimon Glass 			fprintf(f, "// size_dt_strings:\t0x%x\n",
2681043d0a0SSimon Glass 				fdt_size_dt_strings(blob));
2691043d0a0SSimon Glass 		}
2701043d0a0SSimon Glass 		if (version >= 17) {
2711043d0a0SSimon Glass 			fprintf(f, "// size_dt_struct:\t0x%x\n",
2721043d0a0SSimon Glass 				fdt_size_dt_struct(blob));
2731043d0a0SSimon Glass 		}
2741043d0a0SSimon Glass 		fprintf(f, "\n");
2751043d0a0SSimon Glass 	}
2761043d0a0SSimon Glass 
2771043d0a0SSimon Glass 	if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
2781043d0a0SSimon Glass 		const struct fdt_reserve_entry *p_rsvmap;
2791043d0a0SSimon Glass 
2801043d0a0SSimon Glass 		p_rsvmap = (const struct fdt_reserve_entry *)
2811043d0a0SSimon Glass 				((const char *)blob + off_mem_rsvmap);
2821043d0a0SSimon Glass 		for (i = 0; ; i++) {
2831043d0a0SSimon Glass 			addr = fdt64_to_cpu(p_rsvmap[i].address);
2841043d0a0SSimon Glass 			size = fdt64_to_cpu(p_rsvmap[i].size);
2851043d0a0SSimon Glass 			if (addr == 0 && size == 0)
2861043d0a0SSimon Glass 				break;
2871043d0a0SSimon Glass 
2881043d0a0SSimon Glass 			fprintf(f, "/memreserve/ %llx %llx;\n",
2891043d0a0SSimon Glass 				(unsigned long long)addr,
2901043d0a0SSimon Glass 				(unsigned long long)size);
2911043d0a0SSimon Glass 		}
2921043d0a0SSimon Glass 	}
2931043d0a0SSimon Glass 
2941043d0a0SSimon Glass 	depth = 0;
2951043d0a0SSimon Glass 	nextoffset = 0;
2961043d0a0SSimon Glass 	shift = 4;	/* 4 spaces per indent */
2971043d0a0SSimon Glass 	do {
2981043d0a0SSimon Glass 		const struct fdt_property *prop;
2991043d0a0SSimon Glass 		const char *name;
3001043d0a0SSimon Glass 		int show;
3011043d0a0SSimon Glass 		int len;
3021043d0a0SSimon Glass 
3031043d0a0SSimon Glass 		offset = nextoffset;
3041043d0a0SSimon Glass 
3051043d0a0SSimon Glass 		/*
3061043d0a0SSimon Glass 		 * Work out the file offset of this offset, and decide
3071043d0a0SSimon Glass 		 * whether it is in the region list or not
3081043d0a0SSimon Glass 		 */
3091043d0a0SSimon Glass 		file_ofs = base + offset;
3101043d0a0SSimon Glass 		if (reg < reg_end && file_ofs >= reg->offset + reg->size)
3111043d0a0SSimon Glass 			reg++;
3121043d0a0SSimon Glass 		in_region = reg < reg_end && file_ofs >= reg->offset &&
3131043d0a0SSimon Glass 				file_ofs < reg->offset + reg->size;
3141043d0a0SSimon Glass 		tag = fdt_next_tag(blob, offset, &nextoffset);
3151043d0a0SSimon Glass 
3161043d0a0SSimon Glass 		if (tag == FDT_END)
3171043d0a0SSimon Glass 			break;
3181043d0a0SSimon Glass 		show = in_region || disp->all;
3191043d0a0SSimon Glass 		if (show && disp->diff)
3201043d0a0SSimon Glass 			fprintf(f, "%c", in_region ? '+' : '-');
3211043d0a0SSimon Glass 
3221043d0a0SSimon Glass 		if (!show) {
3231043d0a0SSimon Glass 			/* Do this here to avoid 'if (show)' in every 'case' */
3241043d0a0SSimon Glass 			if (tag == FDT_BEGIN_NODE)
3251043d0a0SSimon Glass 				depth++;
3261043d0a0SSimon Glass 			else if (tag == FDT_END_NODE)
3271043d0a0SSimon Glass 				depth--;
3281043d0a0SSimon Glass 			continue;
3291043d0a0SSimon Glass 		}
3301043d0a0SSimon Glass 		if (tag != FDT_END) {
3311043d0a0SSimon Glass 			if (disp->show_addr)
3321043d0a0SSimon Glass 				fprintf(f, "%4x: ", file_ofs);
3331043d0a0SSimon Glass 			if (disp->show_offset)
3341043d0a0SSimon Glass 				fprintf(f, "%4x: ", file_ofs - base);
3351043d0a0SSimon Glass 		}
3361043d0a0SSimon Glass 
3371043d0a0SSimon Glass 		/* Green means included, red means excluded */
3381043d0a0SSimon Glass 		if (disp->colour)
3391043d0a0SSimon Glass 			print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
3401043d0a0SSimon Glass 
3411043d0a0SSimon Glass 		switch (tag) {
3421043d0a0SSimon Glass 		case FDT_PROP:
3431043d0a0SSimon Glass 			prop = fdt_get_property_by_offset(blob, offset, NULL);
3441043d0a0SSimon Glass 			name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
3451043d0a0SSimon Glass 			fprintf(f, "%*s%s", depth * shift, "", name);
3461043d0a0SSimon Glass 			utilfdt_print_data(prop->data,
3471043d0a0SSimon Glass 					   fdt32_to_cpu(prop->len));
3481043d0a0SSimon Glass 			fprintf(f, ";");
3491043d0a0SSimon Glass 			break;
3501043d0a0SSimon Glass 
3511043d0a0SSimon Glass 		case FDT_NOP:
3521043d0a0SSimon Glass 			fprintf(f, "%*s// [NOP]", depth * shift, "");
3531043d0a0SSimon Glass 			break;
3541043d0a0SSimon Glass 
3551043d0a0SSimon Glass 		case FDT_BEGIN_NODE:
3561043d0a0SSimon Glass 			name = fdt_get_name(blob, offset, &len);
3571043d0a0SSimon Glass 			fprintf(f, "%*s%s {", depth++ * shift, "",
3581043d0a0SSimon Glass 				*name ? name : "/");
3591043d0a0SSimon Glass 			break;
3601043d0a0SSimon Glass 
3611043d0a0SSimon Glass 		case FDT_END_NODE:
3621043d0a0SSimon Glass 			fprintf(f, "%*s};", --depth * shift, "");
3631043d0a0SSimon Glass 			break;
3641043d0a0SSimon Glass 		}
3651043d0a0SSimon Glass 
3661043d0a0SSimon Glass 		/* Reset colour back to normal before end of line */
3671043d0a0SSimon Glass 		if (disp->colour)
3681043d0a0SSimon Glass 			print_ansi_colour(f, COL_NONE);
3691043d0a0SSimon Glass 		fprintf(f, "\n");
3701043d0a0SSimon Glass 	} while (1);
3711043d0a0SSimon Glass 
3721043d0a0SSimon Glass 	/* Print a list of strings if requested */
3731043d0a0SSimon Glass 	if (disp->list_strings) {
3741043d0a0SSimon Glass 		const char *str;
3751043d0a0SSimon Glass 		int str_base = fdt_off_dt_strings(blob);
3761043d0a0SSimon Glass 
3771043d0a0SSimon Glass 		for (offset = 0; offset < fdt_size_dt_strings(blob);
3781043d0a0SSimon Glass 				offset += strlen(str) + 1) {
3791043d0a0SSimon Glass 			str = fdt_string(blob, offset);
3801043d0a0SSimon Glass 			int len = strlen(str) + 1;
3811043d0a0SSimon Glass 			int show;
3821043d0a0SSimon Glass 
3831043d0a0SSimon Glass 			/* Only print strings that are in the region */
3841043d0a0SSimon Glass 			file_ofs = str_base + offset;
3851043d0a0SSimon Glass 			in_region = reg < reg_end &&
3861043d0a0SSimon Glass 					file_ofs >= reg->offset &&
3871043d0a0SSimon Glass 					file_ofs + len < reg->offset +
3881043d0a0SSimon Glass 						reg->size;
3891043d0a0SSimon Glass 			show = in_region || disp->all;
3901043d0a0SSimon Glass 			if (show && disp->diff)
3911043d0a0SSimon Glass 				printf("%c", in_region ? '+' : '-');
3921043d0a0SSimon Glass 			if (disp->show_addr)
3931043d0a0SSimon Glass 				printf("%4x: ", file_ofs);
3941043d0a0SSimon Glass 			if (disp->show_offset)
3951043d0a0SSimon Glass 				printf("%4x: ", offset);
3961043d0a0SSimon Glass 			printf("%s\n", str);
3971043d0a0SSimon Glass 		}
3981043d0a0SSimon Glass 	}
3991043d0a0SSimon Glass 
4001043d0a0SSimon Glass 	return 0;
4011043d0a0SSimon Glass }
4021043d0a0SSimon Glass 
4031043d0a0SSimon Glass /**
4041043d0a0SSimon Glass  * dump_fdt_regions() - Dump regions of an FDT as binary data
4051043d0a0SSimon Glass  *
4061043d0a0SSimon Glass  * This dumps an FDT as binary, but only certain regions of it. This is the
4071043d0a0SSimon Glass  * final stage of the grep - we have a list of regions we want to dump,
4081043d0a0SSimon Glass  * and this function dumps them.
4091043d0a0SSimon Glass  *
4101043d0a0SSimon Glass  * The output of this function may or may not be a valid FDT. To ensure it
4111043d0a0SSimon Glass  * is, these disp->flags must be set:
4121043d0a0SSimon Glass  *
413fc0b5948SRobert P. J. Day  *   FDT_REG_SUPERNODES: ensures that subnodes are preceded by their
4141043d0a0SSimon Glass  *		parents. Without this option, fragments of subnode data may be
4151043d0a0SSimon Glass  *		output without the supernodes above them. This is useful for
4161043d0a0SSimon Glass  *		hashing but cannot produce a valid FDT.
4171043d0a0SSimon Glass  *   FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
4181043d0a0SSimon Glass  *		Without this none of the properties will have names
4191043d0a0SSimon Glass  *   FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
4201043d0a0SSimon Glass  *		without this.
4211043d0a0SSimon Glass  *
4221043d0a0SSimon Glass  * @disp:	Display structure, holding info about our options
4231043d0a0SSimon Glass  * @blob:	FDT blob to display
4241043d0a0SSimon Glass  * @region:	List of regions to display
4251043d0a0SSimon Glass  * @count:	Number of regions
4261043d0a0SSimon Glass  * @out:	Output destination
4271043d0a0SSimon Glass  */
dump_fdt_regions(struct display_info * disp,const void * blob,struct fdt_region region[],int count,char * out)4281043d0a0SSimon Glass static int dump_fdt_regions(struct display_info *disp, const void *blob,
4291043d0a0SSimon Glass 		struct fdt_region region[], int count, char *out)
4301043d0a0SSimon Glass {
4311043d0a0SSimon Glass 	struct fdt_header *fdt;
4321043d0a0SSimon Glass 	int size, struct_start;
4331043d0a0SSimon Glass 	int ptr;
4341043d0a0SSimon Glass 	int i;
4351043d0a0SSimon Glass 
4361043d0a0SSimon Glass 	/* Set up a basic header (even if we don't actually write it) */
4371043d0a0SSimon Glass 	fdt = (struct fdt_header *)out;
4381043d0a0SSimon Glass 	memset(fdt, '\0', sizeof(*fdt));
4391043d0a0SSimon Glass 	fdt_set_magic(fdt, FDT_MAGIC);
4401043d0a0SSimon Glass 	struct_start = FDT_ALIGN(sizeof(struct fdt_header),
4411043d0a0SSimon Glass 					sizeof(struct fdt_reserve_entry));
4421043d0a0SSimon Glass 	fdt_set_off_mem_rsvmap(fdt, struct_start);
4431043d0a0SSimon Glass 	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
4441043d0a0SSimon Glass 	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
4451043d0a0SSimon Glass 
4461043d0a0SSimon Glass 	/*
4471043d0a0SSimon Glass 	 * Calculate the total size of the regions we are writing out. The
4481043d0a0SSimon Glass 	 * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
4491043d0a0SSimon Glass 	 * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
4501043d0a0SSimon Glass 	 * is set.
4511043d0a0SSimon Glass 	 */
4521043d0a0SSimon Glass 	for (i = size = 0; i < count; i++)
4531043d0a0SSimon Glass 		size += region[i].size;
4541043d0a0SSimon Glass 
4551043d0a0SSimon Glass 	/* Bring in the mem_rsvmap section from the old file if requested */
4561043d0a0SSimon Glass 	if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
4571043d0a0SSimon Glass 		struct_start += region[0].size;
4581043d0a0SSimon Glass 		size -= region[0].size;
4591043d0a0SSimon Glass 	}
4601043d0a0SSimon Glass 	fdt_set_off_dt_struct(fdt, struct_start);
4611043d0a0SSimon Glass 
4621043d0a0SSimon Glass 	/* Update the header to have the correct offsets/sizes */
4631043d0a0SSimon Glass 	if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
4641043d0a0SSimon Glass 		int str_size;
4651043d0a0SSimon Glass 
4661043d0a0SSimon Glass 		str_size = region[count - 1].size;
4671043d0a0SSimon Glass 		fdt_set_size_dt_struct(fdt, size - str_size);
4681043d0a0SSimon Glass 		fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
4691043d0a0SSimon Glass 		fdt_set_size_dt_strings(fdt, str_size);
4701043d0a0SSimon Glass 		fdt_set_totalsize(fdt, struct_start + size);
4711043d0a0SSimon Glass 	}
4721043d0a0SSimon Glass 
4731043d0a0SSimon Glass 	/* Write the header if required */
4741043d0a0SSimon Glass 	ptr = 0;
4751043d0a0SSimon Glass 	if (disp->header) {
4761043d0a0SSimon Glass 		ptr = sizeof(*fdt);
4771043d0a0SSimon Glass 		while (ptr < fdt_off_mem_rsvmap(fdt))
4781043d0a0SSimon Glass 			out[ptr++] = '\0';
4791043d0a0SSimon Glass 	}
4801043d0a0SSimon Glass 
4811043d0a0SSimon Glass 	/* Output all the nodes including any mem_rsvmap/string table */
4821043d0a0SSimon Glass 	for (i = 0; i < count; i++) {
4831043d0a0SSimon Glass 		struct fdt_region *reg = &region[i];
4841043d0a0SSimon Glass 
4851043d0a0SSimon Glass 		memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
4861043d0a0SSimon Glass 		ptr += reg->size;
4871043d0a0SSimon Glass 	}
4881043d0a0SSimon Glass 
4891043d0a0SSimon Glass 	return ptr;
4901043d0a0SSimon Glass }
4911043d0a0SSimon Glass 
4921043d0a0SSimon Glass /**
4931043d0a0SSimon Glass  * show_region_list() - Print out a list of regions
4941043d0a0SSimon Glass  *
4951043d0a0SSimon Glass  * The list includes the region offset (absolute offset from start of FDT
4961043d0a0SSimon Glass  * blob in bytes) and size
4971043d0a0SSimon Glass  *
4981043d0a0SSimon Glass  * @reg:	List of regions to print
4991043d0a0SSimon Glass  * @count:	Number of regions
5001043d0a0SSimon Glass  */
show_region_list(struct fdt_region * reg,int count)5011043d0a0SSimon Glass static void show_region_list(struct fdt_region *reg, int count)
5021043d0a0SSimon Glass {
5031043d0a0SSimon Glass 	int i;
5041043d0a0SSimon Glass 
5051043d0a0SSimon Glass 	printf("Regions: %d\n", count);
5061043d0a0SSimon Glass 	for (i = 0; i < count; i++, reg++) {
5071043d0a0SSimon Glass 		printf("%d:  %-10x  %-10x\n", i, reg->offset,
5081043d0a0SSimon Glass 		       reg->offset + reg->size);
5091043d0a0SSimon Glass 	}
5101043d0a0SSimon Glass }
5111043d0a0SSimon Glass 
check_type_include(void * priv,int type,const char * data,int size)5121043d0a0SSimon Glass static int check_type_include(void *priv, int type, const char *data, int size)
5131043d0a0SSimon Glass {
5141043d0a0SSimon Glass 	struct display_info *disp = priv;
5151043d0a0SSimon Glass 	struct value_node *val;
5161043d0a0SSimon Glass 	int match, none_match = FDT_IS_ANY;
5171043d0a0SSimon Glass 
5181043d0a0SSimon Glass 	/* If none of our conditions mention this type, we know nothing */
5191043d0a0SSimon Glass 	debug("type=%x, data=%s\n", type, data ? data : "(null)");
5201043d0a0SSimon Glass 	if (!((disp->types_inc | disp->types_exc) & type)) {
5211043d0a0SSimon Glass 		debug("   - not in any condition\n");
5221043d0a0SSimon Glass 		return -1;
5231043d0a0SSimon Glass 	}
5241043d0a0SSimon Glass 
5251043d0a0SSimon Glass 	/*
5261043d0a0SSimon Glass 	 * Go through the list of conditions. For inclusive conditions, we
5271043d0a0SSimon Glass 	 * return 1 at the first match. For exclusive conditions, we must
5281043d0a0SSimon Glass 	 * check that there are no matches.
5291043d0a0SSimon Glass 	 */
53096725153SSimon Glass 	if (data) {
5311043d0a0SSimon Glass 		for (val = disp->value_head; val; val = val->next) {
5321043d0a0SSimon Glass 			if (!(type & val->type))
5331043d0a0SSimon Glass 				continue;
53496725153SSimon Glass 			match = fdt_stringlist_contains(data, size,
53596725153SSimon Glass 							val->string);
5361043d0a0SSimon Glass 			debug("      - val->type=%x, str='%s', match=%d\n",
5371043d0a0SSimon Glass 			      val->type, val->string, match);
5381043d0a0SSimon Glass 			if (match && val->include) {
5391043d0a0SSimon Glass 				debug("   - match inc %s\n", val->string);
5401043d0a0SSimon Glass 				return 1;
5411043d0a0SSimon Glass 			}
5421043d0a0SSimon Glass 			if (match)
5431043d0a0SSimon Glass 				none_match &= ~val->type;
5441043d0a0SSimon Glass 		}
54596725153SSimon Glass 	}
5461043d0a0SSimon Glass 
5471043d0a0SSimon Glass 	/*
5481043d0a0SSimon Glass 	 * If this is an exclusive condition, and nothing matches, then we
5491043d0a0SSimon Glass 	 * should return 1.
5501043d0a0SSimon Glass 	 */
5511043d0a0SSimon Glass 	if ((type & disp->types_exc) && (none_match & type)) {
5521043d0a0SSimon Glass 		debug("   - match exc\n");
5531043d0a0SSimon Glass 		/*
5541043d0a0SSimon Glass 		 * Allow FDT_IS_COMPAT to make the final decision in the
5551043d0a0SSimon Glass 		 * case where there is no specific type
5561043d0a0SSimon Glass 		 */
5571043d0a0SSimon Glass 		if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
5581043d0a0SSimon Glass 			debug("   - supressed exc node\n");
5591043d0a0SSimon Glass 			return -1;
5601043d0a0SSimon Glass 		}
5611043d0a0SSimon Glass 		return 1;
5621043d0a0SSimon Glass 	}
5631043d0a0SSimon Glass 
5641043d0a0SSimon Glass 	/*
5651043d0a0SSimon Glass 	 * Allow FDT_IS_COMPAT to make the final decision in the
5661043d0a0SSimon Glass 	 * case where there is no specific type (inclusive)
5671043d0a0SSimon Glass 	 */
5681043d0a0SSimon Glass 	if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
5691043d0a0SSimon Glass 		return -1;
5701043d0a0SSimon Glass 
5711043d0a0SSimon Glass 	debug("   - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
5721043d0a0SSimon Glass 	      disp->types_inc, disp->types_exc, none_match);
5731043d0a0SSimon Glass 
5741043d0a0SSimon Glass 	return 0;
5751043d0a0SSimon Glass }
5761043d0a0SSimon Glass 
5771043d0a0SSimon Glass /**
5781043d0a0SSimon Glass  * h_include() - Include handler function for fdt_find_regions()
5791043d0a0SSimon Glass  *
5801043d0a0SSimon Glass  * This function decides whether to include or exclude a node, property or
5811043d0a0SSimon Glass  * compatible string. The function is defined by fdt_find_regions().
5821043d0a0SSimon Glass  *
5831043d0a0SSimon Glass  * The algorithm is documented in the code - disp->invert is 0 for normal
5841043d0a0SSimon Glass  * operation, and 1 to invert the sense of all matches.
5851043d0a0SSimon Glass  *
5861043d0a0SSimon Glass  * See
5871043d0a0SSimon Glass  */
h_include(void * priv,const void * fdt,int offset,int type,const char * data,int size)5881043d0a0SSimon Glass static int h_include(void *priv, const void *fdt, int offset, int type,
5891043d0a0SSimon Glass 		     const char *data, int size)
5901043d0a0SSimon Glass {
5911043d0a0SSimon Glass 	struct display_info *disp = priv;
5921043d0a0SSimon Glass 	int inc, len;
5931043d0a0SSimon Glass 
5941043d0a0SSimon Glass 	inc = check_type_include(priv, type, data, size);
5951043d0a0SSimon Glass 	if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
5961043d0a0SSimon Glass 		return 1;
5971043d0a0SSimon Glass 
5981043d0a0SSimon Glass 	/*
5991043d0a0SSimon Glass 	 * If the node name does not tell us anything, check the
6001043d0a0SSimon Glass 	 * compatible string
6011043d0a0SSimon Glass 	 */
6021043d0a0SSimon Glass 	if (inc == -1 && type == FDT_IS_NODE) {
6031043d0a0SSimon Glass 		debug("   - checking compatible2\n");
6041043d0a0SSimon Glass 		data = fdt_getprop(fdt, offset, "compatible", &len);
6051043d0a0SSimon Glass 		inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
6061043d0a0SSimon Glass 	}
6071043d0a0SSimon Glass 
6081043d0a0SSimon Glass 	/* If we still have no idea, check for properties in the node */
6091043d0a0SSimon Glass 	if (inc != 1 && type == FDT_IS_NODE &&
6101043d0a0SSimon Glass 	    (disp->types_inc & FDT_NODE_HAS_PROP)) {
6111043d0a0SSimon Glass 		debug("   - checking node '%s'\n",
6121043d0a0SSimon Glass 		      fdt_get_name(fdt, offset, NULL));
6131043d0a0SSimon Glass 		for (offset = fdt_first_property_offset(fdt, offset);
6141043d0a0SSimon Glass 		     offset > 0 && inc != 1;
6151043d0a0SSimon Glass 		     offset = fdt_next_property_offset(fdt, offset)) {
6161043d0a0SSimon Glass 			const struct fdt_property *prop;
6171043d0a0SSimon Glass 			const char *str;
6181043d0a0SSimon Glass 
6191043d0a0SSimon Glass 			prop = fdt_get_property_by_offset(fdt, offset, NULL);
6201043d0a0SSimon Glass 			if (!prop)
6211043d0a0SSimon Glass 				continue;
6221043d0a0SSimon Glass 			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
6231043d0a0SSimon Glass 			inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
6241043d0a0SSimon Glass 						 strlen(str));
6251043d0a0SSimon Glass 		}
6261043d0a0SSimon Glass 		if (inc == -1)
6271043d0a0SSimon Glass 			inc = 0;
6281043d0a0SSimon Glass 	}
6291043d0a0SSimon Glass 
6301043d0a0SSimon Glass 	switch (inc) {
6311043d0a0SSimon Glass 	case 1:
6321043d0a0SSimon Glass 		inc = !disp->invert;
6331043d0a0SSimon Glass 		break;
6341043d0a0SSimon Glass 	case 0:
6351043d0a0SSimon Glass 		inc = disp->invert;
6361043d0a0SSimon Glass 		break;
6371043d0a0SSimon Glass 	}
6381043d0a0SSimon Glass 	debug("   - returning %d\n", inc);
6391043d0a0SSimon Glass 
6401043d0a0SSimon Glass 	return inc;
6411043d0a0SSimon Glass }
6421043d0a0SSimon Glass 
h_cmp_region(const void * v1,const void * v2)6431043d0a0SSimon Glass static int h_cmp_region(const void *v1, const void *v2)
6441043d0a0SSimon Glass {
6451043d0a0SSimon Glass 	const struct fdt_region *region1 = v1, *region2 = v2;
6461043d0a0SSimon Glass 
6471043d0a0SSimon Glass 	return region1->offset - region2->offset;
6481043d0a0SSimon Glass }
6491043d0a0SSimon Glass 
fdtgrep_find_regions(const void * fdt,int (* include_func)(void * priv,const void * fdt,int offset,int type,const char * data,int size),struct display_info * disp,struct fdt_region * region,int max_regions,char * path,int path_len,int flags)6501043d0a0SSimon Glass static int fdtgrep_find_regions(const void *fdt,
6511043d0a0SSimon Glass 		int (*include_func)(void *priv, const void *fdt, int offset,
6521043d0a0SSimon Glass 				 int type, const char *data, int size),
6531043d0a0SSimon Glass 		struct display_info *disp, struct fdt_region *region,
6541043d0a0SSimon Glass 		int max_regions, char *path, int path_len, int flags)
6551043d0a0SSimon Glass {
6561043d0a0SSimon Glass 	struct fdt_region_state state;
6571043d0a0SSimon Glass 	int count;
6581043d0a0SSimon Glass 	int ret;
6591043d0a0SSimon Glass 
6601043d0a0SSimon Glass 	count = 0;
6611043d0a0SSimon Glass 	ret = fdt_first_region(fdt, include_func, disp,
6621043d0a0SSimon Glass 			&region[count++], path, path_len,
6631043d0a0SSimon Glass 			disp->flags, &state);
6641043d0a0SSimon Glass 	while (ret == 0) {
6651043d0a0SSimon Glass 		ret = fdt_next_region(fdt, include_func, disp,
6661043d0a0SSimon Glass 				count < max_regions ? &region[count] : NULL,
6671043d0a0SSimon Glass 				path, path_len, disp->flags, &state);
6681043d0a0SSimon Glass 		if (!ret)
6691043d0a0SSimon Glass 			count++;
6701043d0a0SSimon Glass 	}
6719404fc85SSimon Glass 	if (ret && ret != -FDT_ERR_NOTFOUND)
6729404fc85SSimon Glass 		return ret;
6731043d0a0SSimon Glass 
6741043d0a0SSimon Glass 	/* Find all the aliases and add those regions back in */
6751043d0a0SSimon Glass 	if (disp->add_aliases && count < max_regions) {
6761043d0a0SSimon Glass 		int new_count;
6771043d0a0SSimon Glass 
6781043d0a0SSimon Glass 		new_count = fdt_add_alias_regions(fdt, region, count,
6791043d0a0SSimon Glass 						  max_regions, &state);
6809404fc85SSimon Glass 		if (new_count == -FDT_ERR_NOTFOUND) {
6819404fc85SSimon Glass 			/* No alias node found */
6829404fc85SSimon Glass 		} else if (new_count < 0) {
6839404fc85SSimon Glass 			return new_count;
6849404fc85SSimon Glass 		} else if (new_count <= max_regions) {
6851043d0a0SSimon Glass 			/*
686f403914dSSimon Glass 			* The alias regions will now be at the end of the list.
687f403914dSSimon Glass 			* Sort the regions by offset to get things into the
688f403914dSSimon Glass 			* right order
6891043d0a0SSimon Glass 			*/
6901043d0a0SSimon Glass 			count = new_count;
691f403914dSSimon Glass 			qsort(region, count, sizeof(struct fdt_region),
692f403914dSSimon Glass 			      h_cmp_region);
693f403914dSSimon Glass 		}
6941043d0a0SSimon Glass 	}
6951043d0a0SSimon Glass 
6961043d0a0SSimon Glass 	return count;
6971043d0a0SSimon Glass }
6981043d0a0SSimon Glass 
utilfdt_read_err_len(const char * filename,char ** buffp,off_t * len)6991043d0a0SSimon Glass int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
7001043d0a0SSimon Glass {
7011043d0a0SSimon Glass 	int fd = 0;	/* assume stdin */
7021043d0a0SSimon Glass 	char *buf = NULL;
7031043d0a0SSimon Glass 	off_t bufsize = 1024, offset = 0;
7041043d0a0SSimon Glass 	int ret = 0;
7051043d0a0SSimon Glass 
7061043d0a0SSimon Glass 	*buffp = NULL;
7071043d0a0SSimon Glass 	if (strcmp(filename, "-") != 0) {
7081043d0a0SSimon Glass 		fd = open(filename, O_RDONLY);
7091043d0a0SSimon Glass 		if (fd < 0)
7101043d0a0SSimon Glass 			return errno;
7111043d0a0SSimon Glass 	}
7121043d0a0SSimon Glass 
7131043d0a0SSimon Glass 	/* Loop until we have read everything */
7141043d0a0SSimon Glass 	buf = malloc(bufsize);
7151043d0a0SSimon Glass 	if (!buf)
7161043d0a0SSimon Glass 		return -ENOMEM;
7171043d0a0SSimon Glass 	do {
7181043d0a0SSimon Glass 		/* Expand the buffer to hold the next chunk */
7191043d0a0SSimon Glass 		if (offset == bufsize) {
7201043d0a0SSimon Glass 			bufsize *= 2;
7211043d0a0SSimon Glass 			buf = realloc(buf, bufsize);
7221043d0a0SSimon Glass 			if (!buf)
7231043d0a0SSimon Glass 				return -ENOMEM;
7241043d0a0SSimon Glass 		}
7251043d0a0SSimon Glass 
7261043d0a0SSimon Glass 		ret = read(fd, &buf[offset], bufsize - offset);
7271043d0a0SSimon Glass 		if (ret < 0) {
7281043d0a0SSimon Glass 			ret = errno;
7291043d0a0SSimon Glass 			break;
7301043d0a0SSimon Glass 		}
7311043d0a0SSimon Glass 		offset += ret;
7321043d0a0SSimon Glass 	} while (ret != 0);
7331043d0a0SSimon Glass 
7341043d0a0SSimon Glass 	/* Clean up, including closing stdin; return errno on error */
7351043d0a0SSimon Glass 	close(fd);
7361043d0a0SSimon Glass 	if (ret)
7371043d0a0SSimon Glass 		free(buf);
7381043d0a0SSimon Glass 	else
7391043d0a0SSimon Glass 		*buffp = buf;
7401043d0a0SSimon Glass 	*len = bufsize;
7411043d0a0SSimon Glass 	return ret;
7421043d0a0SSimon Glass }
7431043d0a0SSimon Glass 
utilfdt_read_err(const char * filename,char ** buffp)7441043d0a0SSimon Glass int utilfdt_read_err(const char *filename, char **buffp)
7451043d0a0SSimon Glass {
7461043d0a0SSimon Glass 	off_t len;
7471043d0a0SSimon Glass 	return utilfdt_read_err_len(filename, buffp, &len);
7481043d0a0SSimon Glass }
7491043d0a0SSimon Glass 
utilfdt_read_len(const char * filename,off_t * len)7501043d0a0SSimon Glass char *utilfdt_read_len(const char *filename, off_t *len)
7511043d0a0SSimon Glass {
7521043d0a0SSimon Glass 	char *buff;
7531043d0a0SSimon Glass 	int ret = utilfdt_read_err_len(filename, &buff, len);
7541043d0a0SSimon Glass 
7551043d0a0SSimon Glass 	if (ret) {
7561043d0a0SSimon Glass 		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
7571043d0a0SSimon Glass 			strerror(ret));
7581043d0a0SSimon Glass 		return NULL;
7591043d0a0SSimon Glass 	}
7601043d0a0SSimon Glass 	/* Successful read */
7611043d0a0SSimon Glass 	return buff;
7621043d0a0SSimon Glass }
7631043d0a0SSimon Glass 
utilfdt_read(const char * filename)7641043d0a0SSimon Glass char *utilfdt_read(const char *filename)
7651043d0a0SSimon Glass {
7661043d0a0SSimon Glass 	off_t len;
7671043d0a0SSimon Glass 	return utilfdt_read_len(filename, &len);
7681043d0a0SSimon Glass }
7691043d0a0SSimon Glass 
7701043d0a0SSimon Glass /**
7711043d0a0SSimon Glass  * Run the main fdtgrep operation, given a filename and valid arguments
7721043d0a0SSimon Glass  *
7731043d0a0SSimon Glass  * @param disp		Display information / options
7741043d0a0SSimon Glass  * @param filename	Filename of blob file
7751043d0a0SSimon Glass  * @param return 0 if ok, -ve on error
7761043d0a0SSimon Glass  */
do_fdtgrep(struct display_info * disp,const char * filename)7771043d0a0SSimon Glass static int do_fdtgrep(struct display_info *disp, const char *filename)
7781043d0a0SSimon Glass {
779e178db1dSSimon Glass 	struct fdt_region *region = NULL;
7801043d0a0SSimon Glass 	int max_regions;
7811043d0a0SSimon Glass 	int count = 100;
7821043d0a0SSimon Glass 	char path[1024];
7831043d0a0SSimon Glass 	char *blob;
7841043d0a0SSimon Glass 	int i, ret;
7851043d0a0SSimon Glass 
7861043d0a0SSimon Glass 	blob = utilfdt_read(filename);
7871043d0a0SSimon Glass 	if (!blob)
7881043d0a0SSimon Glass 		return -1;
7891043d0a0SSimon Glass 	ret = fdt_check_header(blob);
7901043d0a0SSimon Glass 	if (ret) {
7911043d0a0SSimon Glass 		fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
7921043d0a0SSimon Glass 		return ret;
7931043d0a0SSimon Glass 	}
7941043d0a0SSimon Glass 
7951043d0a0SSimon Glass 	/* Allow old files, but they are untested */
7961043d0a0SSimon Glass 	if (fdt_version(blob) < 17 && disp->value_head) {
7971043d0a0SSimon Glass 		fprintf(stderr,
7981043d0a0SSimon Glass 			"Warning: fdtgrep does not fully support version %d files\n",
7991043d0a0SSimon Glass 			fdt_version(blob));
8001043d0a0SSimon Glass 	}
8011043d0a0SSimon Glass 
8021043d0a0SSimon Glass 	/*
8031043d0a0SSimon Glass 	 * We do two passes, since we don't know how many regions we need.
8041043d0a0SSimon Glass 	 * The first pass will count the regions, but if it is too many,
8051043d0a0SSimon Glass 	 * we do another pass to actually record them.
8061043d0a0SSimon Glass 	 */
807e178db1dSSimon Glass 	for (i = 0; i < 2; i++) {
8081043d0a0SSimon Glass 		region = malloc(count * sizeof(struct fdt_region));
8091043d0a0SSimon Glass 		if (!region) {
8101043d0a0SSimon Glass 			fprintf(stderr, "Out of memory for %d regions\n",
8111043d0a0SSimon Glass 				count);
8121043d0a0SSimon Glass 			return -1;
8131043d0a0SSimon Glass 		}
8141043d0a0SSimon Glass 		max_regions = count;
8151043d0a0SSimon Glass 		count = fdtgrep_find_regions(blob,
8161043d0a0SSimon Glass 				h_include, disp,
8171043d0a0SSimon Glass 				region, max_regions, path, sizeof(path),
8181043d0a0SSimon Glass 				disp->flags);
8191043d0a0SSimon Glass 		if (count < 0) {
8201043d0a0SSimon Glass 			report_error("fdt_find_regions", count);
821e178db1dSSimon Glass 			free(region);
8221043d0a0SSimon Glass 			return -1;
8231043d0a0SSimon Glass 		}
8241043d0a0SSimon Glass 		if (count <= max_regions)
8251043d0a0SSimon Glass 			break;
8261043d0a0SSimon Glass 		free(region);
827e178db1dSSimon Glass 		fprintf(stderr, "Internal error with fdtgrep_find_region)(\n");
828e178db1dSSimon Glass 		return -1;
8291043d0a0SSimon Glass 	}
8301043d0a0SSimon Glass 
8311043d0a0SSimon Glass 	/* Optionally print a list of regions */
8321043d0a0SSimon Glass 	if (disp->region_list)
8331043d0a0SSimon Glass 		show_region_list(region, count);
8341043d0a0SSimon Glass 
8351043d0a0SSimon Glass 	/* Output either source .dts or binary .dtb */
8361043d0a0SSimon Glass 	if (disp->output == OUT_DTS) {
8371043d0a0SSimon Glass 		ret = display_fdt_by_regions(disp, blob, region, count);
8381043d0a0SSimon Glass 	} else {
8391043d0a0SSimon Glass 		void *fdt;
8401043d0a0SSimon Glass 		/* Allow reserved memory section to expand slightly */
8411043d0a0SSimon Glass 		int size = fdt_totalsize(blob) + 16;
8421043d0a0SSimon Glass 
8431043d0a0SSimon Glass 		fdt = malloc(size);
8441043d0a0SSimon Glass 		if (!fdt) {
8451043d0a0SSimon Glass 			fprintf(stderr, "Out_of_memory\n");
8461043d0a0SSimon Glass 			ret = -1;
8471043d0a0SSimon Glass 			goto err;
8481043d0a0SSimon Glass 		}
8491043d0a0SSimon Glass 		size = dump_fdt_regions(disp, blob, region, count, fdt);
8501043d0a0SSimon Glass 		if (disp->remove_strings) {
8511043d0a0SSimon Glass 			void *out;
8521043d0a0SSimon Glass 
8531043d0a0SSimon Glass 			out = malloc(size);
8541043d0a0SSimon Glass 			if (!out) {
8551043d0a0SSimon Glass 				fprintf(stderr, "Out_of_memory\n");
8561043d0a0SSimon Glass 				ret = -1;
8571043d0a0SSimon Glass 				goto err;
8581043d0a0SSimon Glass 			}
8591043d0a0SSimon Glass 			ret = fdt_remove_unused_strings(fdt, out);
8601043d0a0SSimon Glass 			if (ret < 0) {
8611043d0a0SSimon Glass 				fprintf(stderr,
8621043d0a0SSimon Glass 					"Failed to remove unused strings: err=%d\n",
8631043d0a0SSimon Glass 					ret);
8641043d0a0SSimon Glass 				goto err;
8651043d0a0SSimon Glass 			}
8661043d0a0SSimon Glass 			free(fdt);
8671043d0a0SSimon Glass 			fdt = out;
8681043d0a0SSimon Glass 			ret = fdt_pack(fdt);
8691043d0a0SSimon Glass 			if (ret < 0) {
8701043d0a0SSimon Glass 				fprintf(stderr, "Failed to pack: err=%d\n",
8711043d0a0SSimon Glass 					ret);
8721043d0a0SSimon Glass 				goto err;
8731043d0a0SSimon Glass 			}
8741043d0a0SSimon Glass 			size = fdt_totalsize(fdt);
8751043d0a0SSimon Glass 		}
8761043d0a0SSimon Glass 
8771043d0a0SSimon Glass 		if (size != fwrite(fdt, 1, size, disp->fout)) {
8781043d0a0SSimon Glass 			fprintf(stderr, "Write failure, %d bytes\n", size);
8791043d0a0SSimon Glass 			free(fdt);
8801043d0a0SSimon Glass 			ret = 1;
8811043d0a0SSimon Glass 			goto err;
8821043d0a0SSimon Glass 		}
8831043d0a0SSimon Glass 		free(fdt);
8841043d0a0SSimon Glass 	}
8851043d0a0SSimon Glass err:
8861043d0a0SSimon Glass 	free(blob);
8871043d0a0SSimon Glass 	free(region);
8881043d0a0SSimon Glass 
8891043d0a0SSimon Glass 	return ret;
8901043d0a0SSimon Glass }
8911043d0a0SSimon Glass 
8921043d0a0SSimon Glass static const char usage_synopsis[] =
8931043d0a0SSimon Glass 	"fdtgrep - extract portions from device tree\n"
8941043d0a0SSimon Glass 	"\n"
8951043d0a0SSimon Glass 	"Usage:\n"
8961043d0a0SSimon Glass 	"	fdtgrep <options> <dt file>|-\n\n"
8971043d0a0SSimon Glass 	"Output formats are:\n"
8981043d0a0SSimon Glass 	"\tdts - device tree soure text\n"
8991043d0a0SSimon Glass 	"\tdtb - device tree blob (sets -Hmt automatically)\n"
9001043d0a0SSimon Glass 	"\tbin - device tree fragment (may not be a valid .dtb)";
9011043d0a0SSimon Glass 
9021043d0a0SSimon Glass /* Helper for usage_short_opts string constant */
9031043d0a0SSimon Glass #define USAGE_COMMON_SHORT_OPTS "hV"
9041043d0a0SSimon Glass 
9051043d0a0SSimon Glass /* Helper for aligning long_opts array */
9061043d0a0SSimon Glass #define a_argument required_argument
9071043d0a0SSimon Glass 
9081043d0a0SSimon Glass /* Helper for usage_long_opts option array */
9091043d0a0SSimon Glass #define USAGE_COMMON_LONG_OPTS \
9101043d0a0SSimon Glass 	{"help",      no_argument, NULL, 'h'}, \
9111043d0a0SSimon Glass 	{"version",   no_argument, NULL, 'V'}, \
9121043d0a0SSimon Glass 	{NULL,        no_argument, NULL, 0x0}
9131043d0a0SSimon Glass 
9141043d0a0SSimon Glass /* Helper for usage_opts_help array */
9151043d0a0SSimon Glass #define USAGE_COMMON_OPTS_HELP \
9161043d0a0SSimon Glass 	"Print this help and exit", \
9171043d0a0SSimon Glass 	"Print version and exit", \
9181043d0a0SSimon Glass 	NULL
9191043d0a0SSimon Glass 
9201043d0a0SSimon Glass /* Helper for getopt case statements */
9211043d0a0SSimon Glass #define case_USAGE_COMMON_FLAGS \
9221043d0a0SSimon Glass 	case 'h': usage(NULL); \
9231043d0a0SSimon Glass 	case 'V': util_version(); \
9241043d0a0SSimon Glass 	case '?': usage("unknown option");
9251043d0a0SSimon Glass 
9261043d0a0SSimon Glass static const char usage_short_opts[] =
9271043d0a0SSimon Glass 		"haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
9281043d0a0SSimon Glass 		USAGE_COMMON_SHORT_OPTS;
9291043d0a0SSimon Glass static struct option const usage_long_opts[] = {
9301043d0a0SSimon Glass 	{"show-address",	no_argument, NULL, 'a'},
9311043d0a0SSimon Glass 	{"colour",		no_argument, NULL, 'A'},
9321043d0a0SSimon Glass 	{"include-node-with-prop", a_argument, NULL, 'b'},
9331043d0a0SSimon Glass 	{"include-compat",	a_argument, NULL, 'c'},
9341043d0a0SSimon Glass 	{"exclude-compat",	a_argument, NULL, 'C'},
9351043d0a0SSimon Glass 	{"diff",		no_argument, NULL, 'd'},
9361043d0a0SSimon Glass 	{"enter-node",		no_argument, NULL, 'e'},
9371043d0a0SSimon Glass 	{"show-offset",		no_argument, NULL, 'f'},
9381043d0a0SSimon Glass 	{"include-match",	a_argument, NULL, 'g'},
9391043d0a0SSimon Glass 	{"exclude-match",	a_argument, NULL, 'G'},
9401043d0a0SSimon Glass 	{"show-header",		no_argument, NULL, 'H'},
9411043d0a0SSimon Glass 	{"show-version",	no_argument, NULL, 'I'},
9421043d0a0SSimon Glass 	{"list-regions",	no_argument, NULL, 'l'},
9431043d0a0SSimon Glass 	{"list-strings",	no_argument, NULL, 'L'},
9441043d0a0SSimon Glass 	{"include-mem",		no_argument, NULL, 'm'},
9451043d0a0SSimon Glass 	{"include-node",	a_argument, NULL, 'n'},
9461043d0a0SSimon Glass 	{"exclude-node",	a_argument, NULL, 'N'},
9471043d0a0SSimon Glass 	{"include-prop",	a_argument, NULL, 'p'},
9481043d0a0SSimon Glass 	{"exclude-prop",	a_argument, NULL, 'P'},
9491043d0a0SSimon Glass 	{"remove-strings",	no_argument, NULL, 'r'},
9501043d0a0SSimon Glass 	{"include-root",	no_argument, NULL, 'R'},
9511043d0a0SSimon Glass 	{"show-subnodes",	no_argument, NULL, 's'},
9521043d0a0SSimon Glass 	{"skip-supernodes",	no_argument, NULL, 'S'},
9531043d0a0SSimon Glass 	{"show-stringtab",	no_argument, NULL, 't'},
9541043d0a0SSimon Glass 	{"show-aliases",	no_argument, NULL, 'T'},
9551043d0a0SSimon Glass 	{"out",			a_argument, NULL, 'o'},
9561043d0a0SSimon Glass 	{"out-format",		a_argument, NULL, 'O'},
9571043d0a0SSimon Glass 	{"invert-match",	no_argument, NULL, 'v'},
9581043d0a0SSimon Glass 	USAGE_COMMON_LONG_OPTS,
9591043d0a0SSimon Glass };
9601043d0a0SSimon Glass static const char * const usage_opts_help[] = {
9611043d0a0SSimon Glass 	"Display address",
9621043d0a0SSimon Glass 	"Show all nodes/tags, colour those that match",
9631043d0a0SSimon Glass 	"Include contains containing property",
9641043d0a0SSimon Glass 	"Compatible nodes to include in grep",
9651043d0a0SSimon Glass 	"Compatible nodes to exclude in grep",
9661043d0a0SSimon Glass 	"Diff: Mark matching nodes with +, others with -",
9671043d0a0SSimon Glass 	"Enter direct subnode names of matching nodes",
9681043d0a0SSimon Glass 	"Display offset",
9691043d0a0SSimon Glass 	"Node/property/compatible string to include in grep",
9701043d0a0SSimon Glass 	"Node/property/compatible string to exclude in grep",
9711043d0a0SSimon Glass 	"Output a header",
9721043d0a0SSimon Glass 	"Put \"/dts-v1/;\" on first line of dts output",
9731043d0a0SSimon Glass 	"Output a region list",
9741043d0a0SSimon Glass 	"List strings in string table",
9751043d0a0SSimon Glass 	"Include mem_rsvmap section in binary output",
9761043d0a0SSimon Glass 	"Node to include in grep",
9771043d0a0SSimon Glass 	"Node to exclude in grep",
9781043d0a0SSimon Glass 	"Property to include in grep",
9791043d0a0SSimon Glass 	"Property to exclude in grep",
9801043d0a0SSimon Glass 	"Remove unused strings from string table",
9811043d0a0SSimon Glass 	"Include root node and all properties",
9821043d0a0SSimon Glass 	"Show all subnodes matching nodes",
9831043d0a0SSimon Glass 	"Don't include supernodes of matching nodes",
9841043d0a0SSimon Glass 	"Include string table in binary output",
9851043d0a0SSimon Glass 	"Include matching aliases in output",
9861043d0a0SSimon Glass 	"-o <output file>",
9871043d0a0SSimon Glass 	"-O <output format>",
9881043d0a0SSimon Glass 	"Invert the sense of matching (select non-matching lines)",
9891043d0a0SSimon Glass 	USAGE_COMMON_OPTS_HELP
9901043d0a0SSimon Glass };
9911043d0a0SSimon Glass 
9921043d0a0SSimon Glass /**
9931043d0a0SSimon Glass  * Call getopt_long() with standard options
9941043d0a0SSimon Glass  *
9951043d0a0SSimon Glass  * Since all util code runs getopt in the same way, provide a helper.
9961043d0a0SSimon Glass  */
9971043d0a0SSimon Glass #define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
9981043d0a0SSimon Glass 				       usage_long_opts, NULL)
9991043d0a0SSimon Glass 
util_usage(const char * errmsg,const char * synopsis,const char * short_opts,struct option const long_opts[],const char * const opts_help[])10001043d0a0SSimon Glass void util_usage(const char *errmsg, const char *synopsis,
10011043d0a0SSimon Glass 		const char *short_opts, struct option const long_opts[],
10021043d0a0SSimon Glass 		const char * const opts_help[])
10031043d0a0SSimon Glass {
10041043d0a0SSimon Glass 	FILE *fp = errmsg ? stderr : stdout;
10051043d0a0SSimon Glass 	const char a_arg[] = "<arg>";
10061043d0a0SSimon Glass 	size_t a_arg_len = strlen(a_arg) + 1;
10071043d0a0SSimon Glass 	size_t i;
10081043d0a0SSimon Glass 	int optlen;
10091043d0a0SSimon Glass 
10101043d0a0SSimon Glass 	fprintf(fp,
10111043d0a0SSimon Glass 		"Usage: %s\n"
10121043d0a0SSimon Glass 		"\n"
10131043d0a0SSimon Glass 		"Options: -[%s]\n", synopsis, short_opts);
10141043d0a0SSimon Glass 
10151043d0a0SSimon Glass 	/* prescan the --long opt length to auto-align */
10161043d0a0SSimon Glass 	optlen = 0;
10171043d0a0SSimon Glass 	for (i = 0; long_opts[i].name; ++i) {
10181043d0a0SSimon Glass 		/* +1 is for space between --opt and help text */
10191043d0a0SSimon Glass 		int l = strlen(long_opts[i].name) + 1;
10201043d0a0SSimon Glass 		if (long_opts[i].has_arg == a_argument)
10211043d0a0SSimon Glass 			l += a_arg_len;
10221043d0a0SSimon Glass 		if (optlen < l)
10231043d0a0SSimon Glass 			optlen = l;
10241043d0a0SSimon Glass 	}
10251043d0a0SSimon Glass 
10261043d0a0SSimon Glass 	for (i = 0; long_opts[i].name; ++i) {
10271043d0a0SSimon Glass 		/* helps when adding new applets or options */
10281043d0a0SSimon Glass 		assert(opts_help[i] != NULL);
10291043d0a0SSimon Glass 
10301043d0a0SSimon Glass 		/* first output the short flag if it has one */
10311043d0a0SSimon Glass 		if (long_opts[i].val > '~')
10321043d0a0SSimon Glass 			fprintf(fp, "      ");
10331043d0a0SSimon Glass 		else
10341043d0a0SSimon Glass 			fprintf(fp, "  -%c, ", long_opts[i].val);
10351043d0a0SSimon Glass 
10361043d0a0SSimon Glass 		/* then the long flag */
10371043d0a0SSimon Glass 		if (long_opts[i].has_arg == no_argument) {
10381043d0a0SSimon Glass 			fprintf(fp, "--%-*s", optlen, long_opts[i].name);
10391043d0a0SSimon Glass 		} else {
10401043d0a0SSimon Glass 			fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
10411043d0a0SSimon Glass 				(int)(optlen - strlen(long_opts[i].name) -
10421043d0a0SSimon Glass 				a_arg_len), "");
10431043d0a0SSimon Glass 		}
10441043d0a0SSimon Glass 
10451043d0a0SSimon Glass 		/* finally the help text */
10461043d0a0SSimon Glass 		fprintf(fp, "%s\n", opts_help[i]);
10471043d0a0SSimon Glass 	}
10481043d0a0SSimon Glass 
10491043d0a0SSimon Glass 	if (errmsg) {
10501043d0a0SSimon Glass 		fprintf(fp, "\nError: %s\n", errmsg);
10511043d0a0SSimon Glass 		exit(EXIT_FAILURE);
10521043d0a0SSimon Glass 	} else {
10531043d0a0SSimon Glass 		exit(EXIT_SUCCESS);
10541043d0a0SSimon Glass 	}
10551043d0a0SSimon Glass }
10561043d0a0SSimon Glass 
10571043d0a0SSimon Glass /**
10581043d0a0SSimon Glass  * Show usage and exit
10591043d0a0SSimon Glass  *
10601043d0a0SSimon Glass  * If you name all your usage variables with usage_xxx, then you can call this
10611043d0a0SSimon Glass  * help macro rather than expanding all arguments yourself.
10621043d0a0SSimon Glass  *
10631043d0a0SSimon Glass  * @param errmsg	If non-NULL, an error message to display
10641043d0a0SSimon Glass  */
10651043d0a0SSimon Glass #define usage(errmsg) \
10661043d0a0SSimon Glass 	util_usage(errmsg, usage_synopsis, usage_short_opts, \
10671043d0a0SSimon Glass 		   usage_long_opts, usage_opts_help)
10681043d0a0SSimon Glass 
util_version(void)10691043d0a0SSimon Glass void util_version(void)
10701043d0a0SSimon Glass {
10711043d0a0SSimon Glass 	printf("Version: %s\n", "(U-Boot)");
10721043d0a0SSimon Glass 	exit(0);
10731043d0a0SSimon Glass }
10741043d0a0SSimon Glass 
scan_args(struct display_info * disp,int argc,char * argv[])10751043d0a0SSimon Glass static void scan_args(struct display_info *disp, int argc, char *argv[])
10761043d0a0SSimon Glass {
10771043d0a0SSimon Glass 	int opt;
10781043d0a0SSimon Glass 
10791043d0a0SSimon Glass 	while ((opt = util_getopt_long()) != EOF) {
10801043d0a0SSimon Glass 		int type = 0;
10811043d0a0SSimon Glass 		int inc = 1;
10821043d0a0SSimon Glass 
10831043d0a0SSimon Glass 		switch (opt) {
10841043d0a0SSimon Glass 		case_USAGE_COMMON_FLAGS
10851043d0a0SSimon Glass 		case 'a':
10861043d0a0SSimon Glass 			disp->show_addr = 1;
10871043d0a0SSimon Glass 			break;
10881043d0a0SSimon Glass 		case 'A':
10891043d0a0SSimon Glass 			disp->all = 1;
10901043d0a0SSimon Glass 			break;
10911043d0a0SSimon Glass 		case 'b':
10921043d0a0SSimon Glass 			type = FDT_NODE_HAS_PROP;
10931043d0a0SSimon Glass 			break;
10941043d0a0SSimon Glass 		case 'C':
10951043d0a0SSimon Glass 			inc = 0;
10961043d0a0SSimon Glass 			/* no break */
10971043d0a0SSimon Glass 		case 'c':
10981043d0a0SSimon Glass 			type = FDT_IS_COMPAT;
10991043d0a0SSimon Glass 			break;
11001043d0a0SSimon Glass 		case 'd':
11011043d0a0SSimon Glass 			disp->diff = 1;
11021043d0a0SSimon Glass 			break;
11031043d0a0SSimon Glass 		case 'e':
11041043d0a0SSimon Glass 			disp->flags |= FDT_REG_DIRECT_SUBNODES;
11051043d0a0SSimon Glass 			break;
11061043d0a0SSimon Glass 		case 'f':
11071043d0a0SSimon Glass 			disp->show_offset = 1;
11081043d0a0SSimon Glass 			break;
11091043d0a0SSimon Glass 		case 'G':
11101043d0a0SSimon Glass 			inc = 0;
11111043d0a0SSimon Glass 			/* no break */
11121043d0a0SSimon Glass 		case 'g':
11131043d0a0SSimon Glass 			type = FDT_ANY_GLOBAL;
11141043d0a0SSimon Glass 			break;
11151043d0a0SSimon Glass 		case 'H':
11161043d0a0SSimon Glass 			disp->header = 1;
11171043d0a0SSimon Glass 			break;
11181043d0a0SSimon Glass 		case 'l':
11191043d0a0SSimon Glass 			disp->region_list = 1;
11201043d0a0SSimon Glass 			break;
11211043d0a0SSimon Glass 		case 'L':
11221043d0a0SSimon Glass 			disp->list_strings = 1;
11231043d0a0SSimon Glass 			break;
11241043d0a0SSimon Glass 		case 'm':
11251043d0a0SSimon Glass 			disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
11261043d0a0SSimon Glass 			break;
11271043d0a0SSimon Glass 		case 'N':
11281043d0a0SSimon Glass 			inc = 0;
11291043d0a0SSimon Glass 			/* no break */
11301043d0a0SSimon Glass 		case 'n':
11311043d0a0SSimon Glass 			type = FDT_IS_NODE;
11321043d0a0SSimon Glass 			break;
11331043d0a0SSimon Glass 		case 'o':
11341043d0a0SSimon Glass 			disp->output_fname = optarg;
11351043d0a0SSimon Glass 			break;
11361043d0a0SSimon Glass 		case 'O':
11371043d0a0SSimon Glass 			if (!strcmp(optarg, "dtb"))
11381043d0a0SSimon Glass 				disp->output = OUT_DTB;
11391043d0a0SSimon Glass 			else if (!strcmp(optarg, "dts"))
11401043d0a0SSimon Glass 				disp->output = OUT_DTS;
11411043d0a0SSimon Glass 			else if (!strcmp(optarg, "bin"))
11421043d0a0SSimon Glass 				disp->output = OUT_BIN;
11431043d0a0SSimon Glass 			else
11441043d0a0SSimon Glass 				usage("Unknown output format");
11451043d0a0SSimon Glass 			break;
11461043d0a0SSimon Glass 		case 'P':
11471043d0a0SSimon Glass 			inc = 0;
11481043d0a0SSimon Glass 			/* no break */
11491043d0a0SSimon Glass 		case 'p':
11501043d0a0SSimon Glass 			type = FDT_IS_PROP;
11511043d0a0SSimon Glass 			break;
11521043d0a0SSimon Glass 		case 'r':
11531043d0a0SSimon Glass 			disp->remove_strings = 1;
11541043d0a0SSimon Glass 			break;
11551043d0a0SSimon Glass 		case 'R':
11561043d0a0SSimon Glass 			disp->include_root = 1;
11571043d0a0SSimon Glass 			break;
11581043d0a0SSimon Glass 		case 's':
11591043d0a0SSimon Glass 			disp->flags |= FDT_REG_ALL_SUBNODES;
11601043d0a0SSimon Glass 			break;
11611043d0a0SSimon Glass 		case 'S':
11621043d0a0SSimon Glass 			disp->flags &= ~FDT_REG_SUPERNODES;
11631043d0a0SSimon Glass 			break;
11641043d0a0SSimon Glass 		case 't':
11651043d0a0SSimon Glass 			disp->flags |= FDT_REG_ADD_STRING_TAB;
11661043d0a0SSimon Glass 			break;
11671043d0a0SSimon Glass 		case 'T':
11681043d0a0SSimon Glass 			disp->add_aliases = 1;
11691043d0a0SSimon Glass 			break;
11701043d0a0SSimon Glass 		case 'v':
11711043d0a0SSimon Glass 			disp->invert = 1;
11721043d0a0SSimon Glass 			break;
11731043d0a0SSimon Glass 		case 'I':
11741043d0a0SSimon Glass 			disp->show_dts_version = 1;
11751043d0a0SSimon Glass 			break;
11761043d0a0SSimon Glass 		}
11771043d0a0SSimon Glass 
11781043d0a0SSimon Glass 		if (type && value_add(disp, &disp->value_head, type, inc,
11791043d0a0SSimon Glass 				      optarg))
11801043d0a0SSimon Glass 			usage("Cannot add value");
11811043d0a0SSimon Glass 	}
11821043d0a0SSimon Glass 
11831043d0a0SSimon Glass 	if (disp->invert && disp->types_exc)
11841043d0a0SSimon Glass 		usage("-v has no meaning when used with 'exclude' conditions");
11851043d0a0SSimon Glass }
11861043d0a0SSimon Glass 
main(int argc,char * argv[])11871043d0a0SSimon Glass int main(int argc, char *argv[])
11881043d0a0SSimon Glass {
11891043d0a0SSimon Glass 	char *filename = NULL;
11901043d0a0SSimon Glass 	struct display_info disp;
11911043d0a0SSimon Glass 	int ret;
11921043d0a0SSimon Glass 
11931043d0a0SSimon Glass 	/* set defaults */
11941043d0a0SSimon Glass 	memset(&disp, '\0', sizeof(disp));
11951043d0a0SSimon Glass 	disp.flags = FDT_REG_SUPERNODES;	/* Default flags */
11961043d0a0SSimon Glass 
11971043d0a0SSimon Glass 	scan_args(&disp, argc, argv);
11981043d0a0SSimon Glass 
11991043d0a0SSimon Glass 	/* Show matched lines in colour if we can */
12001043d0a0SSimon Glass 	disp.colour = disp.all && isatty(0);
12011043d0a0SSimon Glass 
12021043d0a0SSimon Glass 	/* Any additional arguments can match anything, just like -g */
12031043d0a0SSimon Glass 	while (optind < argc - 1) {
12041043d0a0SSimon Glass 		if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
12051043d0a0SSimon Glass 			      argv[optind++]))
12061043d0a0SSimon Glass 			usage("Cannot add value");
12071043d0a0SSimon Glass 	}
12081043d0a0SSimon Glass 
12091043d0a0SSimon Glass 	if (optind < argc)
12101043d0a0SSimon Glass 		filename = argv[optind++];
12111043d0a0SSimon Glass 	if (!filename)
12121043d0a0SSimon Glass 		usage("Missing filename");
12131043d0a0SSimon Glass 
12141043d0a0SSimon Glass 	/* If a valid .dtb is required, set flags to ensure we get one */
12151043d0a0SSimon Glass 	if (disp.output == OUT_DTB) {
12161043d0a0SSimon Glass 		disp.header = 1;
12171043d0a0SSimon Glass 		disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
12181043d0a0SSimon Glass 	}
12191043d0a0SSimon Glass 
12201043d0a0SSimon Glass 	if (disp.output_fname) {
12211043d0a0SSimon Glass 		disp.fout = fopen(disp.output_fname, "w");
12221043d0a0SSimon Glass 		if (!disp.fout)
12231043d0a0SSimon Glass 			usage("Cannot open output file");
12241043d0a0SSimon Glass 	} else {
12251043d0a0SSimon Glass 		disp.fout = stdout;
12261043d0a0SSimon Glass 	}
12271043d0a0SSimon Glass 
12281043d0a0SSimon Glass 	/* Run the grep and output the results */
12291043d0a0SSimon Glass 	ret = do_fdtgrep(&disp, filename);
12301043d0a0SSimon Glass 	if (disp.output_fname)
12311043d0a0SSimon Glass 		fclose(disp.fout);
12321043d0a0SSimon Glass 	if (ret)
12331043d0a0SSimon Glass 		return 1;
12341043d0a0SSimon Glass 
12351043d0a0SSimon Glass 	return 0;
12361043d0a0SSimon Glass }
1237