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