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 = ®ion[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 ®ion[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 ? ®ion[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