1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2013, Google Inc.
3*4882a593Smuzhiyun * Written by Simon Glass <sjg@chromium.org>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Perform a grep of an FDT either displaying the source subset or producing
8*4882a593Smuzhiyun * a new .dtb subset which can be used as required.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <assert.h>
12*4882a593Smuzhiyun #include <ctype.h>
13*4882a593Smuzhiyun #include <errno.h>
14*4882a593Smuzhiyun #include <getopt.h>
15*4882a593Smuzhiyun #include <fcntl.h>
16*4882a593Smuzhiyun #include <stdbool.h>
17*4882a593Smuzhiyun #include <stdio.h>
18*4882a593Smuzhiyun #include <stdlib.h>
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun #include <unistd.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include "fdt_host.h"
23*4882a593Smuzhiyun #include "libfdt_internal.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /* Define DEBUG to get some debugging output on stderr */
26*4882a593Smuzhiyun #ifdef DEBUG
27*4882a593Smuzhiyun #define debug(a, b...) fprintf(stderr, a, ## b)
28*4882a593Smuzhiyun #else
29*4882a593Smuzhiyun #define debug(a, b...)
30*4882a593Smuzhiyun #endif
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /* A linked list of values we are grepping for */
33*4882a593Smuzhiyun struct value_node {
34*4882a593Smuzhiyun int type; /* Types this value matches (FDT_IS... mask) */
35*4882a593Smuzhiyun int include; /* 1 to include matches, 0 to exclude */
36*4882a593Smuzhiyun const char *string; /* String to match */
37*4882a593Smuzhiyun struct value_node *next; /* Pointer to next node, or NULL */
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* Output formats we support */
41*4882a593Smuzhiyun enum output_t {
42*4882a593Smuzhiyun OUT_DTS, /* Device tree source */
43*4882a593Smuzhiyun OUT_DTB, /* Valid device tree binary */
44*4882a593Smuzhiyun OUT_BIN, /* Fragment of .dtb, for hashing */
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* Holds information which controls our output and options */
48*4882a593Smuzhiyun struct display_info {
49*4882a593Smuzhiyun enum output_t output; /* Output format */
50*4882a593Smuzhiyun int add_aliases; /* Add aliases node to output */
51*4882a593Smuzhiyun int all; /* Display all properties/nodes */
52*4882a593Smuzhiyun int colour; /* Display output in ANSI colour */
53*4882a593Smuzhiyun int region_list; /* Output a region list */
54*4882a593Smuzhiyun int flags; /* Flags (FDT_REG_...) */
55*4882a593Smuzhiyun int list_strings; /* List strings in string table */
56*4882a593Smuzhiyun int show_offset; /* Show offset */
57*4882a593Smuzhiyun int show_addr; /* Show address */
58*4882a593Smuzhiyun int header; /* Output an FDT header */
59*4882a593Smuzhiyun int diff; /* Show +/- diff markers */
60*4882a593Smuzhiyun int include_root; /* Include the root node and all properties */
61*4882a593Smuzhiyun int remove_strings; /* Remove unused strings */
62*4882a593Smuzhiyun int show_dts_version; /* Put '/dts-v1/;' on the first line */
63*4882a593Smuzhiyun int types_inc; /* Mask of types that we include (FDT_IS...) */
64*4882a593Smuzhiyun int types_exc; /* Mask of types that we exclude (FDT_IS...) */
65*4882a593Smuzhiyun int invert; /* Invert polarity of match */
66*4882a593Smuzhiyun struct value_node *value_head; /* List of values to match */
67*4882a593Smuzhiyun const char *output_fname; /* Output filename */
68*4882a593Smuzhiyun FILE *fout; /* File to write dts/dtb output */
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun
report_error(const char * where,int err)71*4882a593Smuzhiyun static void report_error(const char *where, int err)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* Supported ANSI colours */
77*4882a593Smuzhiyun enum {
78*4882a593Smuzhiyun COL_BLACK,
79*4882a593Smuzhiyun COL_RED,
80*4882a593Smuzhiyun COL_GREEN,
81*4882a593Smuzhiyun COL_YELLOW,
82*4882a593Smuzhiyun COL_BLUE,
83*4882a593Smuzhiyun COL_MAGENTA,
84*4882a593Smuzhiyun COL_CYAN,
85*4882a593Smuzhiyun COL_WHITE,
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun COL_NONE = -1,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /**
91*4882a593Smuzhiyun * print_ansi_colour() - Print out the ANSI sequence for a colour
92*4882a593Smuzhiyun *
93*4882a593Smuzhiyun * @fout: Output file
94*4882a593Smuzhiyun * @col: Colour to output (COL_...), or COL_NONE to reset colour
95*4882a593Smuzhiyun */
print_ansi_colour(FILE * fout,int col)96*4882a593Smuzhiyun static void print_ansi_colour(FILE *fout, int col)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun if (col == COL_NONE)
99*4882a593Smuzhiyun fprintf(fout, "\033[0m");
100*4882a593Smuzhiyun else
101*4882a593Smuzhiyun fprintf(fout, "\033[1;%dm", col + 30);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /**
106*4882a593Smuzhiyun * value_add() - Add a new value to our list of things to grep for
107*4882a593Smuzhiyun *
108*4882a593Smuzhiyun * @disp: Display structure, holding info about our options
109*4882a593Smuzhiyun * @headp: Pointer to header pointer of list
110*4882a593Smuzhiyun * @type: Type of this value (FDT_IS_...)
111*4882a593Smuzhiyun * @include: 1 if we want to include matches, 0 to exclude
112*4882a593Smuzhiyun * @str: String value to match
113*4882a593Smuzhiyun */
value_add(struct display_info * disp,struct value_node ** headp,int type,int include,const char * str)114*4882a593Smuzhiyun static int value_add(struct display_info *disp, struct value_node **headp,
115*4882a593Smuzhiyun int type, int include, const char *str)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun struct value_node *node;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun * Keep track of which types we are excluding/including. We don't
121*4882a593Smuzhiyun * allow both including and excluding things, because it doesn't make
122*4882a593Smuzhiyun * sense. 'Including' means that everything not mentioned is
123*4882a593Smuzhiyun * excluded. 'Excluding' means that everything not mentioned is
124*4882a593Smuzhiyun * included. So using the two together would be meaningless.
125*4882a593Smuzhiyun */
126*4882a593Smuzhiyun if (include)
127*4882a593Smuzhiyun disp->types_inc |= type;
128*4882a593Smuzhiyun else
129*4882a593Smuzhiyun disp->types_exc |= type;
130*4882a593Smuzhiyun if (disp->types_inc & disp->types_exc & type) {
131*4882a593Smuzhiyun fprintf(stderr,
132*4882a593Smuzhiyun "Cannot use both include and exclude for '%s'\n", str);
133*4882a593Smuzhiyun return -1;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun str = strdup(str);
137*4882a593Smuzhiyun node = malloc(sizeof(*node));
138*4882a593Smuzhiyun if (!str || !node) {
139*4882a593Smuzhiyun fprintf(stderr, "Out of memory\n");
140*4882a593Smuzhiyun return -1;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun node->next = *headp;
143*4882a593Smuzhiyun node->type = type;
144*4882a593Smuzhiyun node->include = include;
145*4882a593Smuzhiyun node->string = str;
146*4882a593Smuzhiyun *headp = node;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
util_is_printable_string(const void * data,int len)151*4882a593Smuzhiyun static bool util_is_printable_string(const void *data, int len)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun const char *s = data;
154*4882a593Smuzhiyun const char *ss, *se;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* zero length is not */
157*4882a593Smuzhiyun if (len == 0)
158*4882a593Smuzhiyun return 0;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* must terminate with zero */
161*4882a593Smuzhiyun if (s[len - 1] != '\0')
162*4882a593Smuzhiyun return 0;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun se = s + len;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun while (s < se) {
167*4882a593Smuzhiyun ss = s;
168*4882a593Smuzhiyun while (s < se && *s && isprint((unsigned char)*s))
169*4882a593Smuzhiyun s++;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* not zero, or not done yet */
172*4882a593Smuzhiyun if (*s != '\0' || s == ss)
173*4882a593Smuzhiyun return 0;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun s++;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun return 1;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
utilfdt_print_data(const char * data,int len)181*4882a593Smuzhiyun static void utilfdt_print_data(const char *data, int len)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun int i;
184*4882a593Smuzhiyun const char *p = data;
185*4882a593Smuzhiyun const char *s;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* no data, don't print */
188*4882a593Smuzhiyun if (len == 0)
189*4882a593Smuzhiyun return;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun if (util_is_printable_string(data, len)) {
192*4882a593Smuzhiyun printf(" = ");
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun s = data;
195*4882a593Smuzhiyun do {
196*4882a593Smuzhiyun printf("\"%s\"", s);
197*4882a593Smuzhiyun s += strlen(s) + 1;
198*4882a593Smuzhiyun if (s < data + len)
199*4882a593Smuzhiyun printf(", ");
200*4882a593Smuzhiyun } while (s < data + len);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun } else if ((len % 4) == 0) {
203*4882a593Smuzhiyun const uint32_t *cell = (const uint32_t *)data;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun printf(" = <");
206*4882a593Smuzhiyun for (i = 0, len /= 4; i < len; i++)
207*4882a593Smuzhiyun printf("0x%08x%s", fdt32_to_cpu(cell[i]),
208*4882a593Smuzhiyun i < (len - 1) ? " " : "");
209*4882a593Smuzhiyun printf(">");
210*4882a593Smuzhiyun } else {
211*4882a593Smuzhiyun printf(" = [");
212*4882a593Smuzhiyun for (i = 0; i < len; i++)
213*4882a593Smuzhiyun printf("%02x%s", *p++, i < len - 1 ? " " : "");
214*4882a593Smuzhiyun printf("]");
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /**
219*4882a593Smuzhiyun * display_fdt_by_regions() - Display regions of an FDT source
220*4882a593Smuzhiyun *
221*4882a593Smuzhiyun * This dumps an FDT as source, but only certain regions of it. This is the
222*4882a593Smuzhiyun * final stage of the grep - we have a list of regions we want to display,
223*4882a593Smuzhiyun * and this function displays them.
224*4882a593Smuzhiyun *
225*4882a593Smuzhiyun * @disp: Display structure, holding info about our options
226*4882a593Smuzhiyun * @blob: FDT blob to display
227*4882a593Smuzhiyun * @region: List of regions to display
228*4882a593Smuzhiyun * @count: Number of regions
229*4882a593Smuzhiyun */
display_fdt_by_regions(struct display_info * disp,const void * blob,struct fdt_region region[],int count)230*4882a593Smuzhiyun static int display_fdt_by_regions(struct display_info *disp, const void *blob,
231*4882a593Smuzhiyun struct fdt_region region[], int count)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun struct fdt_region *reg = region, *reg_end = region + count;
234*4882a593Smuzhiyun uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
235*4882a593Smuzhiyun int base = fdt_off_dt_struct(blob);
236*4882a593Smuzhiyun int version = fdt_version(blob);
237*4882a593Smuzhiyun int offset, nextoffset;
238*4882a593Smuzhiyun int tag, depth, shift;
239*4882a593Smuzhiyun FILE *f = disp->fout;
240*4882a593Smuzhiyun uint64_t addr, size;
241*4882a593Smuzhiyun int in_region;
242*4882a593Smuzhiyun int file_ofs;
243*4882a593Smuzhiyun int i;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun if (disp->show_dts_version)
246*4882a593Smuzhiyun fprintf(f, "/dts-v1/;\n");
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun if (disp->header) {
249*4882a593Smuzhiyun fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
250*4882a593Smuzhiyun fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
251*4882a593Smuzhiyun fdt_totalsize(blob));
252*4882a593Smuzhiyun fprintf(f, "// off_dt_struct:\t0x%x\n",
253*4882a593Smuzhiyun fdt_off_dt_struct(blob));
254*4882a593Smuzhiyun fprintf(f, "// off_dt_strings:\t0x%x\n",
255*4882a593Smuzhiyun fdt_off_dt_strings(blob));
256*4882a593Smuzhiyun fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
257*4882a593Smuzhiyun fprintf(f, "// version:\t\t%d\n", version);
258*4882a593Smuzhiyun fprintf(f, "// last_comp_version:\t%d\n",
259*4882a593Smuzhiyun fdt_last_comp_version(blob));
260*4882a593Smuzhiyun if (version >= 2) {
261*4882a593Smuzhiyun fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
262*4882a593Smuzhiyun fdt_boot_cpuid_phys(blob));
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun if (version >= 3) {
265*4882a593Smuzhiyun fprintf(f, "// size_dt_strings:\t0x%x\n",
266*4882a593Smuzhiyun fdt_size_dt_strings(blob));
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun if (version >= 17) {
269*4882a593Smuzhiyun fprintf(f, "// size_dt_struct:\t0x%x\n",
270*4882a593Smuzhiyun fdt_size_dt_struct(blob));
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun fprintf(f, "\n");
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
276*4882a593Smuzhiyun const struct fdt_reserve_entry *p_rsvmap;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun p_rsvmap = (const struct fdt_reserve_entry *)
279*4882a593Smuzhiyun ((const char *)blob + off_mem_rsvmap);
280*4882a593Smuzhiyun for (i = 0; ; i++) {
281*4882a593Smuzhiyun addr = fdt64_to_cpu(p_rsvmap[i].address);
282*4882a593Smuzhiyun size = fdt64_to_cpu(p_rsvmap[i].size);
283*4882a593Smuzhiyun if (addr == 0 && size == 0)
284*4882a593Smuzhiyun break;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun fprintf(f, "/memreserve/ %llx %llx;\n",
287*4882a593Smuzhiyun (unsigned long long)addr,
288*4882a593Smuzhiyun (unsigned long long)size);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun depth = 0;
293*4882a593Smuzhiyun nextoffset = 0;
294*4882a593Smuzhiyun shift = 4; /* 4 spaces per indent */
295*4882a593Smuzhiyun do {
296*4882a593Smuzhiyun const struct fdt_property *prop;
297*4882a593Smuzhiyun const char *name;
298*4882a593Smuzhiyun int show;
299*4882a593Smuzhiyun int len;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun offset = nextoffset;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /*
304*4882a593Smuzhiyun * Work out the file offset of this offset, and decide
305*4882a593Smuzhiyun * whether it is in the region list or not
306*4882a593Smuzhiyun */
307*4882a593Smuzhiyun file_ofs = base + offset;
308*4882a593Smuzhiyun if (reg < reg_end && file_ofs >= reg->offset + reg->size)
309*4882a593Smuzhiyun reg++;
310*4882a593Smuzhiyun in_region = reg < reg_end && file_ofs >= reg->offset &&
311*4882a593Smuzhiyun file_ofs < reg->offset + reg->size;
312*4882a593Smuzhiyun tag = fdt_next_tag(blob, offset, &nextoffset);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (tag == FDT_END)
315*4882a593Smuzhiyun break;
316*4882a593Smuzhiyun show = in_region || disp->all;
317*4882a593Smuzhiyun if (show && disp->diff)
318*4882a593Smuzhiyun fprintf(f, "%c", in_region ? '+' : '-');
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (!show) {
321*4882a593Smuzhiyun /* Do this here to avoid 'if (show)' in every 'case' */
322*4882a593Smuzhiyun if (tag == FDT_BEGIN_NODE)
323*4882a593Smuzhiyun depth++;
324*4882a593Smuzhiyun else if (tag == FDT_END_NODE)
325*4882a593Smuzhiyun depth--;
326*4882a593Smuzhiyun continue;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun if (tag != FDT_END) {
329*4882a593Smuzhiyun if (disp->show_addr)
330*4882a593Smuzhiyun fprintf(f, "%4x: ", file_ofs);
331*4882a593Smuzhiyun if (disp->show_offset)
332*4882a593Smuzhiyun fprintf(f, "%4x: ", file_ofs - base);
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /* Green means included, red means excluded */
336*4882a593Smuzhiyun if (disp->colour)
337*4882a593Smuzhiyun print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun switch (tag) {
340*4882a593Smuzhiyun case FDT_PROP:
341*4882a593Smuzhiyun prop = fdt_get_property_by_offset(blob, offset, NULL);
342*4882a593Smuzhiyun name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
343*4882a593Smuzhiyun fprintf(f, "%*s%s", depth * shift, "", name);
344*4882a593Smuzhiyun utilfdt_print_data(prop->data,
345*4882a593Smuzhiyun fdt32_to_cpu(prop->len));
346*4882a593Smuzhiyun fprintf(f, ";");
347*4882a593Smuzhiyun break;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun case FDT_NOP:
350*4882a593Smuzhiyun fprintf(f, "%*s// [NOP]", depth * shift, "");
351*4882a593Smuzhiyun break;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun case FDT_BEGIN_NODE:
354*4882a593Smuzhiyun name = fdt_get_name(blob, offset, &len);
355*4882a593Smuzhiyun fprintf(f, "%*s%s {", depth++ * shift, "",
356*4882a593Smuzhiyun *name ? name : "/");
357*4882a593Smuzhiyun break;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun case FDT_END_NODE:
360*4882a593Smuzhiyun fprintf(f, "%*s};", --depth * shift, "");
361*4882a593Smuzhiyun break;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /* Reset colour back to normal before end of line */
365*4882a593Smuzhiyun if (disp->colour)
366*4882a593Smuzhiyun print_ansi_colour(f, COL_NONE);
367*4882a593Smuzhiyun fprintf(f, "\n");
368*4882a593Smuzhiyun } while (1);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun /* Print a list of strings if requested */
371*4882a593Smuzhiyun if (disp->list_strings) {
372*4882a593Smuzhiyun const char *str;
373*4882a593Smuzhiyun int str_base = fdt_off_dt_strings(blob);
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun for (offset = 0; offset < fdt_size_dt_strings(blob);
376*4882a593Smuzhiyun offset += strlen(str) + 1) {
377*4882a593Smuzhiyun str = fdt_string(blob, offset);
378*4882a593Smuzhiyun int len = strlen(str) + 1;
379*4882a593Smuzhiyun int show;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun /* Only print strings that are in the region */
382*4882a593Smuzhiyun file_ofs = str_base + offset;
383*4882a593Smuzhiyun in_region = reg < reg_end &&
384*4882a593Smuzhiyun file_ofs >= reg->offset &&
385*4882a593Smuzhiyun file_ofs + len < reg->offset +
386*4882a593Smuzhiyun reg->size;
387*4882a593Smuzhiyun show = in_region || disp->all;
388*4882a593Smuzhiyun if (show && disp->diff)
389*4882a593Smuzhiyun printf("%c", in_region ? '+' : '-');
390*4882a593Smuzhiyun if (disp->show_addr)
391*4882a593Smuzhiyun printf("%4x: ", file_ofs);
392*4882a593Smuzhiyun if (disp->show_offset)
393*4882a593Smuzhiyun printf("%4x: ", offset);
394*4882a593Smuzhiyun printf("%s\n", str);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun return 0;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun /**
402*4882a593Smuzhiyun * dump_fdt_regions() - Dump regions of an FDT as binary data
403*4882a593Smuzhiyun *
404*4882a593Smuzhiyun * This dumps an FDT as binary, but only certain regions of it. This is the
405*4882a593Smuzhiyun * final stage of the grep - we have a list of regions we want to dump,
406*4882a593Smuzhiyun * and this function dumps them.
407*4882a593Smuzhiyun *
408*4882a593Smuzhiyun * The output of this function may or may not be a valid FDT. To ensure it
409*4882a593Smuzhiyun * is, these disp->flags must be set:
410*4882a593Smuzhiyun *
411*4882a593Smuzhiyun * FDT_REG_SUPERNODES: ensures that subnodes are preceded by their
412*4882a593Smuzhiyun * parents. Without this option, fragments of subnode data may be
413*4882a593Smuzhiyun * output without the supernodes above them. This is useful for
414*4882a593Smuzhiyun * hashing but cannot produce a valid FDT.
415*4882a593Smuzhiyun * FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
416*4882a593Smuzhiyun * Without this none of the properties will have names
417*4882a593Smuzhiyun * FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
418*4882a593Smuzhiyun * without this.
419*4882a593Smuzhiyun *
420*4882a593Smuzhiyun * @disp: Display structure, holding info about our options
421*4882a593Smuzhiyun * @blob: FDT blob to display
422*4882a593Smuzhiyun * @region: List of regions to display
423*4882a593Smuzhiyun * @count: Number of regions
424*4882a593Smuzhiyun * @out: Output destination
425*4882a593Smuzhiyun */
dump_fdt_regions(struct display_info * disp,const void * blob,struct fdt_region region[],int count,char * out)426*4882a593Smuzhiyun static int dump_fdt_regions(struct display_info *disp, const void *blob,
427*4882a593Smuzhiyun struct fdt_region region[], int count, char *out)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun struct fdt_header *fdt;
430*4882a593Smuzhiyun int size, struct_start;
431*4882a593Smuzhiyun int ptr;
432*4882a593Smuzhiyun int i;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* Set up a basic header (even if we don't actually write it) */
435*4882a593Smuzhiyun fdt = (struct fdt_header *)out;
436*4882a593Smuzhiyun memset(fdt, '\0', sizeof(*fdt));
437*4882a593Smuzhiyun fdt_set_magic(fdt, FDT_MAGIC);
438*4882a593Smuzhiyun struct_start = FDT_ALIGN(sizeof(struct fdt_header),
439*4882a593Smuzhiyun sizeof(struct fdt_reserve_entry));
440*4882a593Smuzhiyun fdt_set_off_mem_rsvmap(fdt, struct_start);
441*4882a593Smuzhiyun fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
442*4882a593Smuzhiyun fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun /*
445*4882a593Smuzhiyun * Calculate the total size of the regions we are writing out. The
446*4882a593Smuzhiyun * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
447*4882a593Smuzhiyun * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
448*4882a593Smuzhiyun * is set.
449*4882a593Smuzhiyun */
450*4882a593Smuzhiyun for (i = size = 0; i < count; i++)
451*4882a593Smuzhiyun size += region[i].size;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /* Bring in the mem_rsvmap section from the old file if requested */
454*4882a593Smuzhiyun if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
455*4882a593Smuzhiyun struct_start += region[0].size;
456*4882a593Smuzhiyun size -= region[0].size;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun fdt_set_off_dt_struct(fdt, struct_start);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun /* Update the header to have the correct offsets/sizes */
461*4882a593Smuzhiyun if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
462*4882a593Smuzhiyun int str_size;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun str_size = region[count - 1].size;
465*4882a593Smuzhiyun fdt_set_size_dt_struct(fdt, size - str_size);
466*4882a593Smuzhiyun fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
467*4882a593Smuzhiyun fdt_set_size_dt_strings(fdt, str_size);
468*4882a593Smuzhiyun fdt_set_totalsize(fdt, struct_start + size);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun /* Write the header if required */
472*4882a593Smuzhiyun ptr = 0;
473*4882a593Smuzhiyun if (disp->header) {
474*4882a593Smuzhiyun ptr = sizeof(*fdt);
475*4882a593Smuzhiyun while (ptr < fdt_off_mem_rsvmap(fdt))
476*4882a593Smuzhiyun out[ptr++] = '\0';
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun /* Output all the nodes including any mem_rsvmap/string table */
480*4882a593Smuzhiyun for (i = 0; i < count; i++) {
481*4882a593Smuzhiyun struct fdt_region *reg = ®ion[i];
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
484*4882a593Smuzhiyun ptr += reg->size;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun return ptr;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /**
491*4882a593Smuzhiyun * show_region_list() - Print out a list of regions
492*4882a593Smuzhiyun *
493*4882a593Smuzhiyun * The list includes the region offset (absolute offset from start of FDT
494*4882a593Smuzhiyun * blob in bytes) and size
495*4882a593Smuzhiyun *
496*4882a593Smuzhiyun * @reg: List of regions to print
497*4882a593Smuzhiyun * @count: Number of regions
498*4882a593Smuzhiyun */
show_region_list(struct fdt_region * reg,int count)499*4882a593Smuzhiyun static void show_region_list(struct fdt_region *reg, int count)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun int i;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun printf("Regions: %d\n", count);
504*4882a593Smuzhiyun for (i = 0; i < count; i++, reg++) {
505*4882a593Smuzhiyun printf("%d: %-10x %-10x\n", i, reg->offset,
506*4882a593Smuzhiyun reg->offset + reg->size);
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
check_type_include(void * priv,int type,const char * data,int size)510*4882a593Smuzhiyun static int check_type_include(void *priv, int type, const char *data, int size)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun struct display_info *disp = priv;
513*4882a593Smuzhiyun struct value_node *val;
514*4882a593Smuzhiyun int match, none_match = FDT_IS_ANY;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun /* If none of our conditions mention this type, we know nothing */
517*4882a593Smuzhiyun debug("type=%x, data=%s\n", type, data ? data : "(null)");
518*4882a593Smuzhiyun if (!((disp->types_inc | disp->types_exc) & type)) {
519*4882a593Smuzhiyun debug(" - not in any condition\n");
520*4882a593Smuzhiyun return -1;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun /*
524*4882a593Smuzhiyun * Go through the list of conditions. For inclusive conditions, we
525*4882a593Smuzhiyun * return 1 at the first match. For exclusive conditions, we must
526*4882a593Smuzhiyun * check that there are no matches.
527*4882a593Smuzhiyun */
528*4882a593Smuzhiyun if (data) {
529*4882a593Smuzhiyun for (val = disp->value_head; val; val = val->next) {
530*4882a593Smuzhiyun if (!(type & val->type))
531*4882a593Smuzhiyun continue;
532*4882a593Smuzhiyun match = fdt_stringlist_contains(data, size,
533*4882a593Smuzhiyun val->string);
534*4882a593Smuzhiyun debug(" - val->type=%x, str='%s', match=%d\n",
535*4882a593Smuzhiyun val->type, val->string, match);
536*4882a593Smuzhiyun if (match && val->include) {
537*4882a593Smuzhiyun debug(" - match inc %s\n", val->string);
538*4882a593Smuzhiyun return 1;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun if (match)
541*4882a593Smuzhiyun none_match &= ~val->type;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun /*
546*4882a593Smuzhiyun * If this is an exclusive condition, and nothing matches, then we
547*4882a593Smuzhiyun * should return 1.
548*4882a593Smuzhiyun */
549*4882a593Smuzhiyun if ((type & disp->types_exc) && (none_match & type)) {
550*4882a593Smuzhiyun debug(" - match exc\n");
551*4882a593Smuzhiyun /*
552*4882a593Smuzhiyun * Allow FDT_IS_COMPAT to make the final decision in the
553*4882a593Smuzhiyun * case where there is no specific type
554*4882a593Smuzhiyun */
555*4882a593Smuzhiyun if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
556*4882a593Smuzhiyun debug(" - supressed exc node\n");
557*4882a593Smuzhiyun return -1;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun return 1;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun /*
563*4882a593Smuzhiyun * Allow FDT_IS_COMPAT to make the final decision in the
564*4882a593Smuzhiyun * case where there is no specific type (inclusive)
565*4882a593Smuzhiyun */
566*4882a593Smuzhiyun if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
567*4882a593Smuzhiyun return -1;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun debug(" - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
570*4882a593Smuzhiyun disp->types_inc, disp->types_exc, none_match);
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun return 0;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /**
576*4882a593Smuzhiyun * h_include() - Include handler function for fdt_find_regions()
577*4882a593Smuzhiyun *
578*4882a593Smuzhiyun * This function decides whether to include or exclude a node, property or
579*4882a593Smuzhiyun * compatible string. The function is defined by fdt_find_regions().
580*4882a593Smuzhiyun *
581*4882a593Smuzhiyun * The algorithm is documented in the code - disp->invert is 0 for normal
582*4882a593Smuzhiyun * operation, and 1 to invert the sense of all matches.
583*4882a593Smuzhiyun *
584*4882a593Smuzhiyun * See
585*4882a593Smuzhiyun */
h_include(void * priv,const void * fdt,int offset,int type,const char * data,int size)586*4882a593Smuzhiyun static int h_include(void *priv, const void *fdt, int offset, int type,
587*4882a593Smuzhiyun const char *data, int size)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun struct display_info *disp = priv;
590*4882a593Smuzhiyun int inc, len;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun inc = check_type_include(priv, type, data, size);
593*4882a593Smuzhiyun if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
594*4882a593Smuzhiyun return 1;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun /*
597*4882a593Smuzhiyun * If the node name does not tell us anything, check the
598*4882a593Smuzhiyun * compatible string
599*4882a593Smuzhiyun */
600*4882a593Smuzhiyun if (inc == -1 && type == FDT_IS_NODE) {
601*4882a593Smuzhiyun debug(" - checking compatible2\n");
602*4882a593Smuzhiyun data = fdt_getprop(fdt, offset, "compatible", &len);
603*4882a593Smuzhiyun inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun /* If we still have no idea, check for properties in the node */
607*4882a593Smuzhiyun if (inc != 1 && type == FDT_IS_NODE &&
608*4882a593Smuzhiyun (disp->types_inc & FDT_NODE_HAS_PROP)) {
609*4882a593Smuzhiyun debug(" - checking node '%s'\n",
610*4882a593Smuzhiyun fdt_get_name(fdt, offset, NULL));
611*4882a593Smuzhiyun for (offset = fdt_first_property_offset(fdt, offset);
612*4882a593Smuzhiyun offset > 0 && inc != 1;
613*4882a593Smuzhiyun offset = fdt_next_property_offset(fdt, offset)) {
614*4882a593Smuzhiyun const struct fdt_property *prop;
615*4882a593Smuzhiyun const char *str;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun prop = fdt_get_property_by_offset(fdt, offset, NULL);
618*4882a593Smuzhiyun if (!prop)
619*4882a593Smuzhiyun continue;
620*4882a593Smuzhiyun str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
621*4882a593Smuzhiyun inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
622*4882a593Smuzhiyun strlen(str));
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun if (inc == -1)
625*4882a593Smuzhiyun inc = 0;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun switch (inc) {
629*4882a593Smuzhiyun case 1:
630*4882a593Smuzhiyun inc = !disp->invert;
631*4882a593Smuzhiyun break;
632*4882a593Smuzhiyun case 0:
633*4882a593Smuzhiyun inc = disp->invert;
634*4882a593Smuzhiyun break;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun debug(" - returning %d\n", inc);
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun return inc;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
h_cmp_region(const void * v1,const void * v2)641*4882a593Smuzhiyun static int h_cmp_region(const void *v1, const void *v2)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun const struct fdt_region *region1 = v1, *region2 = v2;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun return region1->offset - region2->offset;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
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)648*4882a593Smuzhiyun static int fdtgrep_find_regions(const void *fdt,
649*4882a593Smuzhiyun int (*include_func)(void *priv, const void *fdt, int offset,
650*4882a593Smuzhiyun int type, const char *data, int size),
651*4882a593Smuzhiyun struct display_info *disp, struct fdt_region *region,
652*4882a593Smuzhiyun int max_regions, char *path, int path_len, int flags)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun struct fdt_region_state state;
655*4882a593Smuzhiyun int count;
656*4882a593Smuzhiyun int ret;
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun count = 0;
659*4882a593Smuzhiyun ret = fdt_first_region(fdt, include_func, disp,
660*4882a593Smuzhiyun ®ion[count++], path, path_len,
661*4882a593Smuzhiyun disp->flags, &state);
662*4882a593Smuzhiyun while (ret == 0) {
663*4882a593Smuzhiyun ret = fdt_next_region(fdt, include_func, disp,
664*4882a593Smuzhiyun count < max_regions ? ®ion[count] : NULL,
665*4882a593Smuzhiyun path, path_len, disp->flags, &state);
666*4882a593Smuzhiyun if (!ret)
667*4882a593Smuzhiyun count++;
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun if (ret && ret != -FDT_ERR_NOTFOUND)
670*4882a593Smuzhiyun return ret;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun /* Find all the aliases and add those regions back in */
673*4882a593Smuzhiyun if (disp->add_aliases && count < max_regions) {
674*4882a593Smuzhiyun int new_count;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun new_count = fdt_add_alias_regions(fdt, region, count,
677*4882a593Smuzhiyun max_regions, &state);
678*4882a593Smuzhiyun if (new_count == -FDT_ERR_NOTFOUND) {
679*4882a593Smuzhiyun /* No alias node found */
680*4882a593Smuzhiyun } else if (new_count < 0) {
681*4882a593Smuzhiyun return new_count;
682*4882a593Smuzhiyun } else if (new_count <= max_regions) {
683*4882a593Smuzhiyun /*
684*4882a593Smuzhiyun * The alias regions will now be at the end of the list.
685*4882a593Smuzhiyun * Sort the regions by offset to get things into the
686*4882a593Smuzhiyun * right order
687*4882a593Smuzhiyun */
688*4882a593Smuzhiyun count = new_count;
689*4882a593Smuzhiyun qsort(region, count, sizeof(struct fdt_region),
690*4882a593Smuzhiyun h_cmp_region);
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun return count;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun
utilfdt_read_err_len(const char * filename,char ** buffp,off_t * len)697*4882a593Smuzhiyun int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun int fd = 0; /* assume stdin */
700*4882a593Smuzhiyun char *buf = NULL;
701*4882a593Smuzhiyun off_t bufsize = 1024, offset = 0;
702*4882a593Smuzhiyun int ret = 0;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun *buffp = NULL;
705*4882a593Smuzhiyun if (strcmp(filename, "-") != 0) {
706*4882a593Smuzhiyun fd = open(filename, O_RDONLY);
707*4882a593Smuzhiyun if (fd < 0)
708*4882a593Smuzhiyun return errno;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun /* Loop until we have read everything */
712*4882a593Smuzhiyun buf = malloc(bufsize);
713*4882a593Smuzhiyun if (!buf)
714*4882a593Smuzhiyun return -ENOMEM;
715*4882a593Smuzhiyun do {
716*4882a593Smuzhiyun /* Expand the buffer to hold the next chunk */
717*4882a593Smuzhiyun if (offset == bufsize) {
718*4882a593Smuzhiyun bufsize *= 2;
719*4882a593Smuzhiyun buf = realloc(buf, bufsize);
720*4882a593Smuzhiyun if (!buf)
721*4882a593Smuzhiyun return -ENOMEM;
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun ret = read(fd, &buf[offset], bufsize - offset);
725*4882a593Smuzhiyun if (ret < 0) {
726*4882a593Smuzhiyun ret = errno;
727*4882a593Smuzhiyun break;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun offset += ret;
730*4882a593Smuzhiyun } while (ret != 0);
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun /* Clean up, including closing stdin; return errno on error */
733*4882a593Smuzhiyun close(fd);
734*4882a593Smuzhiyun if (ret)
735*4882a593Smuzhiyun free(buf);
736*4882a593Smuzhiyun else
737*4882a593Smuzhiyun *buffp = buf;
738*4882a593Smuzhiyun *len = bufsize;
739*4882a593Smuzhiyun return ret;
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun
utilfdt_read_err(const char * filename,char ** buffp)742*4882a593Smuzhiyun int utilfdt_read_err(const char *filename, char **buffp)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun off_t len;
745*4882a593Smuzhiyun return utilfdt_read_err_len(filename, buffp, &len);
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun
utilfdt_read_len(const char * filename,off_t * len)748*4882a593Smuzhiyun char *utilfdt_read_len(const char *filename, off_t *len)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun char *buff;
751*4882a593Smuzhiyun int ret = utilfdt_read_err_len(filename, &buff, len);
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun if (ret) {
754*4882a593Smuzhiyun fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
755*4882a593Smuzhiyun strerror(ret));
756*4882a593Smuzhiyun return NULL;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun /* Successful read */
759*4882a593Smuzhiyun return buff;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun
utilfdt_read(const char * filename)762*4882a593Smuzhiyun char *utilfdt_read(const char *filename)
763*4882a593Smuzhiyun {
764*4882a593Smuzhiyun off_t len;
765*4882a593Smuzhiyun return utilfdt_read_len(filename, &len);
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun /**
769*4882a593Smuzhiyun * Run the main fdtgrep operation, given a filename and valid arguments
770*4882a593Smuzhiyun *
771*4882a593Smuzhiyun * @param disp Display information / options
772*4882a593Smuzhiyun * @param filename Filename of blob file
773*4882a593Smuzhiyun * @param return 0 if ok, -ve on error
774*4882a593Smuzhiyun */
do_fdtgrep(struct display_info * disp,const char * filename)775*4882a593Smuzhiyun static int do_fdtgrep(struct display_info *disp, const char *filename)
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun struct fdt_region *region;
778*4882a593Smuzhiyun int max_regions;
779*4882a593Smuzhiyun int count = 100;
780*4882a593Smuzhiyun char path[1024];
781*4882a593Smuzhiyun char *blob;
782*4882a593Smuzhiyun int i, ret;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun blob = utilfdt_read(filename);
785*4882a593Smuzhiyun if (!blob)
786*4882a593Smuzhiyun return -1;
787*4882a593Smuzhiyun ret = fdt_check_header(blob);
788*4882a593Smuzhiyun if (ret) {
789*4882a593Smuzhiyun fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
790*4882a593Smuzhiyun return ret;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun /* Allow old files, but they are untested */
794*4882a593Smuzhiyun if (fdt_version(blob) < 17 && disp->value_head) {
795*4882a593Smuzhiyun fprintf(stderr,
796*4882a593Smuzhiyun "Warning: fdtgrep does not fully support version %d files\n",
797*4882a593Smuzhiyun fdt_version(blob));
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun /*
801*4882a593Smuzhiyun * We do two passes, since we don't know how many regions we need.
802*4882a593Smuzhiyun * The first pass will count the regions, but if it is too many,
803*4882a593Smuzhiyun * we do another pass to actually record them.
804*4882a593Smuzhiyun */
805*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
806*4882a593Smuzhiyun region = malloc(count * sizeof(struct fdt_region));
807*4882a593Smuzhiyun if (!region) {
808*4882a593Smuzhiyun fprintf(stderr, "Out of memory for %d regions\n",
809*4882a593Smuzhiyun count);
810*4882a593Smuzhiyun return -1;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun max_regions = count;
813*4882a593Smuzhiyun count = fdtgrep_find_regions(blob,
814*4882a593Smuzhiyun h_include, disp,
815*4882a593Smuzhiyun region, max_regions, path, sizeof(path),
816*4882a593Smuzhiyun disp->flags);
817*4882a593Smuzhiyun if (count < 0) {
818*4882a593Smuzhiyun report_error("fdt_find_regions", count);
819*4882a593Smuzhiyun return -1;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun if (count <= max_regions)
822*4882a593Smuzhiyun break;
823*4882a593Smuzhiyun free(region);
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun /* Optionally print a list of regions */
827*4882a593Smuzhiyun if (disp->region_list)
828*4882a593Smuzhiyun show_region_list(region, count);
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun /* Output either source .dts or binary .dtb */
831*4882a593Smuzhiyun if (disp->output == OUT_DTS) {
832*4882a593Smuzhiyun ret = display_fdt_by_regions(disp, blob, region, count);
833*4882a593Smuzhiyun } else {
834*4882a593Smuzhiyun void *fdt;
835*4882a593Smuzhiyun /* Allow reserved memory section to expand slightly */
836*4882a593Smuzhiyun int size = fdt_totalsize(blob) + 16;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun fdt = malloc(size);
839*4882a593Smuzhiyun if (!fdt) {
840*4882a593Smuzhiyun fprintf(stderr, "Out_of_memory\n");
841*4882a593Smuzhiyun ret = -1;
842*4882a593Smuzhiyun goto err;
843*4882a593Smuzhiyun }
844*4882a593Smuzhiyun size = dump_fdt_regions(disp, blob, region, count, fdt);
845*4882a593Smuzhiyun if (disp->remove_strings) {
846*4882a593Smuzhiyun void *out;
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun out = malloc(size);
849*4882a593Smuzhiyun if (!out) {
850*4882a593Smuzhiyun fprintf(stderr, "Out_of_memory\n");
851*4882a593Smuzhiyun ret = -1;
852*4882a593Smuzhiyun goto err;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun ret = fdt_remove_unused_strings(fdt, out);
855*4882a593Smuzhiyun if (ret < 0) {
856*4882a593Smuzhiyun fprintf(stderr,
857*4882a593Smuzhiyun "Failed to remove unused strings: err=%d\n",
858*4882a593Smuzhiyun ret);
859*4882a593Smuzhiyun goto err;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun free(fdt);
862*4882a593Smuzhiyun fdt = out;
863*4882a593Smuzhiyun ret = fdt_pack(fdt);
864*4882a593Smuzhiyun if (ret < 0) {
865*4882a593Smuzhiyun fprintf(stderr, "Failed to pack: err=%d\n",
866*4882a593Smuzhiyun ret);
867*4882a593Smuzhiyun goto err;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun size = fdt_totalsize(fdt);
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun if (size != fwrite(fdt, 1, size, disp->fout)) {
873*4882a593Smuzhiyun fprintf(stderr, "Write failure, %d bytes\n", size);
874*4882a593Smuzhiyun free(fdt);
875*4882a593Smuzhiyun ret = 1;
876*4882a593Smuzhiyun goto err;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun free(fdt);
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun err:
881*4882a593Smuzhiyun free(blob);
882*4882a593Smuzhiyun free(region);
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun return ret;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun static const char usage_synopsis[] =
888*4882a593Smuzhiyun "fdtgrep - extract portions from device tree\n"
889*4882a593Smuzhiyun "\n"
890*4882a593Smuzhiyun "Usage:\n"
891*4882a593Smuzhiyun " fdtgrep <options> <dt file>|-\n\n"
892*4882a593Smuzhiyun "Output formats are:\n"
893*4882a593Smuzhiyun "\tdts - device tree soure text\n"
894*4882a593Smuzhiyun "\tdtb - device tree blob (sets -Hmt automatically)\n"
895*4882a593Smuzhiyun "\tbin - device tree fragment (may not be a valid .dtb)";
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun /* Helper for usage_short_opts string constant */
898*4882a593Smuzhiyun #define USAGE_COMMON_SHORT_OPTS "hV"
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun /* Helper for aligning long_opts array */
901*4882a593Smuzhiyun #define a_argument required_argument
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun /* Helper for usage_long_opts option array */
904*4882a593Smuzhiyun #define USAGE_COMMON_LONG_OPTS \
905*4882a593Smuzhiyun {"help", no_argument, NULL, 'h'}, \
906*4882a593Smuzhiyun {"version", no_argument, NULL, 'V'}, \
907*4882a593Smuzhiyun {NULL, no_argument, NULL, 0x0}
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun /* Helper for usage_opts_help array */
910*4882a593Smuzhiyun #define USAGE_COMMON_OPTS_HELP \
911*4882a593Smuzhiyun "Print this help and exit", \
912*4882a593Smuzhiyun "Print version and exit", \
913*4882a593Smuzhiyun NULL
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun /* Helper for getopt case statements */
916*4882a593Smuzhiyun #define case_USAGE_COMMON_FLAGS \
917*4882a593Smuzhiyun case 'h': usage(NULL); \
918*4882a593Smuzhiyun case 'V': util_version(); \
919*4882a593Smuzhiyun case '?': usage("unknown option");
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun static const char usage_short_opts[] =
922*4882a593Smuzhiyun "haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
923*4882a593Smuzhiyun USAGE_COMMON_SHORT_OPTS;
924*4882a593Smuzhiyun static struct option const usage_long_opts[] = {
925*4882a593Smuzhiyun {"show-address", no_argument, NULL, 'a'},
926*4882a593Smuzhiyun {"colour", no_argument, NULL, 'A'},
927*4882a593Smuzhiyun {"include-node-with-prop", a_argument, NULL, 'b'},
928*4882a593Smuzhiyun {"include-compat", a_argument, NULL, 'c'},
929*4882a593Smuzhiyun {"exclude-compat", a_argument, NULL, 'C'},
930*4882a593Smuzhiyun {"diff", no_argument, NULL, 'd'},
931*4882a593Smuzhiyun {"enter-node", no_argument, NULL, 'e'},
932*4882a593Smuzhiyun {"show-offset", no_argument, NULL, 'f'},
933*4882a593Smuzhiyun {"include-match", a_argument, NULL, 'g'},
934*4882a593Smuzhiyun {"exclude-match", a_argument, NULL, 'G'},
935*4882a593Smuzhiyun {"show-header", no_argument, NULL, 'H'},
936*4882a593Smuzhiyun {"show-version", no_argument, NULL, 'I'},
937*4882a593Smuzhiyun {"list-regions", no_argument, NULL, 'l'},
938*4882a593Smuzhiyun {"list-strings", no_argument, NULL, 'L'},
939*4882a593Smuzhiyun {"include-mem", no_argument, NULL, 'm'},
940*4882a593Smuzhiyun {"include-node", a_argument, NULL, 'n'},
941*4882a593Smuzhiyun {"exclude-node", a_argument, NULL, 'N'},
942*4882a593Smuzhiyun {"include-prop", a_argument, NULL, 'p'},
943*4882a593Smuzhiyun {"exclude-prop", a_argument, NULL, 'P'},
944*4882a593Smuzhiyun {"remove-strings", no_argument, NULL, 'r'},
945*4882a593Smuzhiyun {"include-root", no_argument, NULL, 'R'},
946*4882a593Smuzhiyun {"show-subnodes", no_argument, NULL, 's'},
947*4882a593Smuzhiyun {"skip-supernodes", no_argument, NULL, 'S'},
948*4882a593Smuzhiyun {"show-stringtab", no_argument, NULL, 't'},
949*4882a593Smuzhiyun {"show-aliases", no_argument, NULL, 'T'},
950*4882a593Smuzhiyun {"out", a_argument, NULL, 'o'},
951*4882a593Smuzhiyun {"out-format", a_argument, NULL, 'O'},
952*4882a593Smuzhiyun {"invert-match", no_argument, NULL, 'v'},
953*4882a593Smuzhiyun USAGE_COMMON_LONG_OPTS,
954*4882a593Smuzhiyun };
955*4882a593Smuzhiyun static const char * const usage_opts_help[] = {
956*4882a593Smuzhiyun "Display address",
957*4882a593Smuzhiyun "Show all nodes/tags, colour those that match",
958*4882a593Smuzhiyun "Include contains containing property",
959*4882a593Smuzhiyun "Compatible nodes to include in grep",
960*4882a593Smuzhiyun "Compatible nodes to exclude in grep",
961*4882a593Smuzhiyun "Diff: Mark matching nodes with +, others with -",
962*4882a593Smuzhiyun "Enter direct subnode names of matching nodes",
963*4882a593Smuzhiyun "Display offset",
964*4882a593Smuzhiyun "Node/property/compatible string to include in grep",
965*4882a593Smuzhiyun "Node/property/compatible string to exclude in grep",
966*4882a593Smuzhiyun "Output a header",
967*4882a593Smuzhiyun "Put \"/dts-v1/;\" on first line of dts output",
968*4882a593Smuzhiyun "Output a region list",
969*4882a593Smuzhiyun "List strings in string table",
970*4882a593Smuzhiyun "Include mem_rsvmap section in binary output",
971*4882a593Smuzhiyun "Node to include in grep",
972*4882a593Smuzhiyun "Node to exclude in grep",
973*4882a593Smuzhiyun "Property to include in grep",
974*4882a593Smuzhiyun "Property to exclude in grep",
975*4882a593Smuzhiyun "Remove unused strings from string table",
976*4882a593Smuzhiyun "Include root node and all properties",
977*4882a593Smuzhiyun "Show all subnodes matching nodes",
978*4882a593Smuzhiyun "Don't include supernodes of matching nodes",
979*4882a593Smuzhiyun "Include string table in binary output",
980*4882a593Smuzhiyun "Include matching aliases in output",
981*4882a593Smuzhiyun "-o <output file>",
982*4882a593Smuzhiyun "-O <output format>",
983*4882a593Smuzhiyun "Invert the sense of matching (select non-matching lines)",
984*4882a593Smuzhiyun USAGE_COMMON_OPTS_HELP
985*4882a593Smuzhiyun };
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun /**
988*4882a593Smuzhiyun * Call getopt_long() with standard options
989*4882a593Smuzhiyun *
990*4882a593Smuzhiyun * Since all util code runs getopt in the same way, provide a helper.
991*4882a593Smuzhiyun */
992*4882a593Smuzhiyun #define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
993*4882a593Smuzhiyun usage_long_opts, NULL)
994*4882a593Smuzhiyun
util_usage(const char * errmsg,const char * synopsis,const char * short_opts,struct option const long_opts[],const char * const opts_help[])995*4882a593Smuzhiyun void util_usage(const char *errmsg, const char *synopsis,
996*4882a593Smuzhiyun const char *short_opts, struct option const long_opts[],
997*4882a593Smuzhiyun const char * const opts_help[])
998*4882a593Smuzhiyun {
999*4882a593Smuzhiyun FILE *fp = errmsg ? stderr : stdout;
1000*4882a593Smuzhiyun const char a_arg[] = "<arg>";
1001*4882a593Smuzhiyun size_t a_arg_len = strlen(a_arg) + 1;
1002*4882a593Smuzhiyun size_t i;
1003*4882a593Smuzhiyun int optlen;
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun fprintf(fp,
1006*4882a593Smuzhiyun "Usage: %s\n"
1007*4882a593Smuzhiyun "\n"
1008*4882a593Smuzhiyun "Options: -[%s]\n", synopsis, short_opts);
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun /* prescan the --long opt length to auto-align */
1011*4882a593Smuzhiyun optlen = 0;
1012*4882a593Smuzhiyun for (i = 0; long_opts[i].name; ++i) {
1013*4882a593Smuzhiyun /* +1 is for space between --opt and help text */
1014*4882a593Smuzhiyun int l = strlen(long_opts[i].name) + 1;
1015*4882a593Smuzhiyun if (long_opts[i].has_arg == a_argument)
1016*4882a593Smuzhiyun l += a_arg_len;
1017*4882a593Smuzhiyun if (optlen < l)
1018*4882a593Smuzhiyun optlen = l;
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun for (i = 0; long_opts[i].name; ++i) {
1022*4882a593Smuzhiyun /* helps when adding new applets or options */
1023*4882a593Smuzhiyun assert(opts_help[i] != NULL);
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun /* first output the short flag if it has one */
1026*4882a593Smuzhiyun if (long_opts[i].val > '~')
1027*4882a593Smuzhiyun fprintf(fp, " ");
1028*4882a593Smuzhiyun else
1029*4882a593Smuzhiyun fprintf(fp, " -%c, ", long_opts[i].val);
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun /* then the long flag */
1032*4882a593Smuzhiyun if (long_opts[i].has_arg == no_argument) {
1033*4882a593Smuzhiyun fprintf(fp, "--%-*s", optlen, long_opts[i].name);
1034*4882a593Smuzhiyun } else {
1035*4882a593Smuzhiyun fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
1036*4882a593Smuzhiyun (int)(optlen - strlen(long_opts[i].name) -
1037*4882a593Smuzhiyun a_arg_len), "");
1038*4882a593Smuzhiyun }
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun /* finally the help text */
1041*4882a593Smuzhiyun fprintf(fp, "%s\n", opts_help[i]);
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun if (errmsg) {
1045*4882a593Smuzhiyun fprintf(fp, "\nError: %s\n", errmsg);
1046*4882a593Smuzhiyun exit(EXIT_FAILURE);
1047*4882a593Smuzhiyun } else {
1048*4882a593Smuzhiyun exit(EXIT_SUCCESS);
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun /**
1053*4882a593Smuzhiyun * Show usage and exit
1054*4882a593Smuzhiyun *
1055*4882a593Smuzhiyun * If you name all your usage variables with usage_xxx, then you can call this
1056*4882a593Smuzhiyun * help macro rather than expanding all arguments yourself.
1057*4882a593Smuzhiyun *
1058*4882a593Smuzhiyun * @param errmsg If non-NULL, an error message to display
1059*4882a593Smuzhiyun */
1060*4882a593Smuzhiyun #define usage(errmsg) \
1061*4882a593Smuzhiyun util_usage(errmsg, usage_synopsis, usage_short_opts, \
1062*4882a593Smuzhiyun usage_long_opts, usage_opts_help)
1063*4882a593Smuzhiyun
util_version(void)1064*4882a593Smuzhiyun void util_version(void)
1065*4882a593Smuzhiyun {
1066*4882a593Smuzhiyun printf("Version: %s\n", "(U-Boot)");
1067*4882a593Smuzhiyun exit(0);
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun
scan_args(struct display_info * disp,int argc,char * argv[])1070*4882a593Smuzhiyun static void scan_args(struct display_info *disp, int argc, char *argv[])
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun int opt;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun while ((opt = util_getopt_long()) != EOF) {
1075*4882a593Smuzhiyun int type = 0;
1076*4882a593Smuzhiyun int inc = 1;
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun switch (opt) {
1079*4882a593Smuzhiyun case_USAGE_COMMON_FLAGS
1080*4882a593Smuzhiyun case 'a':
1081*4882a593Smuzhiyun disp->show_addr = 1;
1082*4882a593Smuzhiyun break;
1083*4882a593Smuzhiyun case 'A':
1084*4882a593Smuzhiyun disp->all = 1;
1085*4882a593Smuzhiyun break;
1086*4882a593Smuzhiyun case 'b':
1087*4882a593Smuzhiyun type = FDT_NODE_HAS_PROP;
1088*4882a593Smuzhiyun break;
1089*4882a593Smuzhiyun case 'C':
1090*4882a593Smuzhiyun inc = 0;
1091*4882a593Smuzhiyun /* no break */
1092*4882a593Smuzhiyun case 'c':
1093*4882a593Smuzhiyun type = FDT_IS_COMPAT;
1094*4882a593Smuzhiyun break;
1095*4882a593Smuzhiyun case 'd':
1096*4882a593Smuzhiyun disp->diff = 1;
1097*4882a593Smuzhiyun break;
1098*4882a593Smuzhiyun case 'e':
1099*4882a593Smuzhiyun disp->flags |= FDT_REG_DIRECT_SUBNODES;
1100*4882a593Smuzhiyun break;
1101*4882a593Smuzhiyun case 'f':
1102*4882a593Smuzhiyun disp->show_offset = 1;
1103*4882a593Smuzhiyun break;
1104*4882a593Smuzhiyun case 'G':
1105*4882a593Smuzhiyun inc = 0;
1106*4882a593Smuzhiyun /* no break */
1107*4882a593Smuzhiyun case 'g':
1108*4882a593Smuzhiyun type = FDT_ANY_GLOBAL;
1109*4882a593Smuzhiyun break;
1110*4882a593Smuzhiyun case 'H':
1111*4882a593Smuzhiyun disp->header = 1;
1112*4882a593Smuzhiyun break;
1113*4882a593Smuzhiyun case 'l':
1114*4882a593Smuzhiyun disp->region_list = 1;
1115*4882a593Smuzhiyun break;
1116*4882a593Smuzhiyun case 'L':
1117*4882a593Smuzhiyun disp->list_strings = 1;
1118*4882a593Smuzhiyun break;
1119*4882a593Smuzhiyun case 'm':
1120*4882a593Smuzhiyun disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
1121*4882a593Smuzhiyun break;
1122*4882a593Smuzhiyun case 'N':
1123*4882a593Smuzhiyun inc = 0;
1124*4882a593Smuzhiyun /* no break */
1125*4882a593Smuzhiyun case 'n':
1126*4882a593Smuzhiyun type = FDT_IS_NODE;
1127*4882a593Smuzhiyun break;
1128*4882a593Smuzhiyun case 'o':
1129*4882a593Smuzhiyun disp->output_fname = optarg;
1130*4882a593Smuzhiyun break;
1131*4882a593Smuzhiyun case 'O':
1132*4882a593Smuzhiyun if (!strcmp(optarg, "dtb"))
1133*4882a593Smuzhiyun disp->output = OUT_DTB;
1134*4882a593Smuzhiyun else if (!strcmp(optarg, "dts"))
1135*4882a593Smuzhiyun disp->output = OUT_DTS;
1136*4882a593Smuzhiyun else if (!strcmp(optarg, "bin"))
1137*4882a593Smuzhiyun disp->output = OUT_BIN;
1138*4882a593Smuzhiyun else
1139*4882a593Smuzhiyun usage("Unknown output format");
1140*4882a593Smuzhiyun break;
1141*4882a593Smuzhiyun case 'P':
1142*4882a593Smuzhiyun inc = 0;
1143*4882a593Smuzhiyun /* no break */
1144*4882a593Smuzhiyun case 'p':
1145*4882a593Smuzhiyun type = FDT_IS_PROP;
1146*4882a593Smuzhiyun break;
1147*4882a593Smuzhiyun case 'r':
1148*4882a593Smuzhiyun disp->remove_strings = 1;
1149*4882a593Smuzhiyun break;
1150*4882a593Smuzhiyun case 'R':
1151*4882a593Smuzhiyun disp->include_root = 1;
1152*4882a593Smuzhiyun break;
1153*4882a593Smuzhiyun case 's':
1154*4882a593Smuzhiyun disp->flags |= FDT_REG_ALL_SUBNODES;
1155*4882a593Smuzhiyun break;
1156*4882a593Smuzhiyun case 'S':
1157*4882a593Smuzhiyun disp->flags &= ~FDT_REG_SUPERNODES;
1158*4882a593Smuzhiyun break;
1159*4882a593Smuzhiyun case 't':
1160*4882a593Smuzhiyun disp->flags |= FDT_REG_ADD_STRING_TAB;
1161*4882a593Smuzhiyun break;
1162*4882a593Smuzhiyun case 'T':
1163*4882a593Smuzhiyun disp->add_aliases = 1;
1164*4882a593Smuzhiyun break;
1165*4882a593Smuzhiyun case 'v':
1166*4882a593Smuzhiyun disp->invert = 1;
1167*4882a593Smuzhiyun break;
1168*4882a593Smuzhiyun case 'I':
1169*4882a593Smuzhiyun disp->show_dts_version = 1;
1170*4882a593Smuzhiyun break;
1171*4882a593Smuzhiyun }
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun if (type && value_add(disp, &disp->value_head, type, inc,
1174*4882a593Smuzhiyun optarg))
1175*4882a593Smuzhiyun usage("Cannot add value");
1176*4882a593Smuzhiyun }
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun if (disp->invert && disp->types_exc)
1179*4882a593Smuzhiyun usage("-v has no meaning when used with 'exclude' conditions");
1180*4882a593Smuzhiyun }
1181*4882a593Smuzhiyun
main(int argc,char * argv[])1182*4882a593Smuzhiyun int main(int argc, char *argv[])
1183*4882a593Smuzhiyun {
1184*4882a593Smuzhiyun char *filename = NULL;
1185*4882a593Smuzhiyun struct display_info disp;
1186*4882a593Smuzhiyun int ret;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun /* set defaults */
1189*4882a593Smuzhiyun memset(&disp, '\0', sizeof(disp));
1190*4882a593Smuzhiyun disp.flags = FDT_REG_SUPERNODES; /* Default flags */
1191*4882a593Smuzhiyun
1192*4882a593Smuzhiyun scan_args(&disp, argc, argv);
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun /* Show matched lines in colour if we can */
1195*4882a593Smuzhiyun disp.colour = disp.all && isatty(0);
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun /* Any additional arguments can match anything, just like -g */
1198*4882a593Smuzhiyun while (optind < argc - 1) {
1199*4882a593Smuzhiyun if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
1200*4882a593Smuzhiyun argv[optind++]))
1201*4882a593Smuzhiyun usage("Cannot add value");
1202*4882a593Smuzhiyun }
1203*4882a593Smuzhiyun
1204*4882a593Smuzhiyun if (optind < argc)
1205*4882a593Smuzhiyun filename = argv[optind++];
1206*4882a593Smuzhiyun if (!filename)
1207*4882a593Smuzhiyun usage("Missing filename");
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun /* If a valid .dtb is required, set flags to ensure we get one */
1210*4882a593Smuzhiyun if (disp.output == OUT_DTB) {
1211*4882a593Smuzhiyun disp.header = 1;
1212*4882a593Smuzhiyun disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun if (disp.output_fname) {
1216*4882a593Smuzhiyun disp.fout = fopen(disp.output_fname, "w");
1217*4882a593Smuzhiyun if (!disp.fout)
1218*4882a593Smuzhiyun usage("Cannot open output file");
1219*4882a593Smuzhiyun } else {
1220*4882a593Smuzhiyun disp.fout = stdout;
1221*4882a593Smuzhiyun }
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun /* Run the grep and output the results */
1224*4882a593Smuzhiyun ret = do_fdtgrep(&disp, filename);
1225*4882a593Smuzhiyun if (disp.output_fname)
1226*4882a593Smuzhiyun fclose(disp.fout);
1227*4882a593Smuzhiyun if (ret)
1228*4882a593Smuzhiyun return 1;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun return 0;
1231*4882a593Smuzhiyun }
1232