Merge tag 'u-boot-amlogic-20200428' of https://gitlab.denx.de/u-boot/custodians/u...
[oweals/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", *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 = FDT_ALIGN(sizeof(struct fdt_header),
442                                         sizeof(struct fdt_reserve_entry));
443         fdt_set_off_mem_rsvmap(fdt, struct_start);
444         fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
445         fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
446
447         /*
448          * Calculate the total size of the regions we are writing out. The
449          * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
450          * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
451          * is set.
452          */
453         for (i = size = 0; i < count; i++)
454                 size += region[i].size;
455
456         /* Bring in the mem_rsvmap section from the old file if requested */
457         if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
458                 struct_start += region[0].size;
459                 size -= region[0].size;
460         }
461         fdt_set_off_dt_struct(fdt, struct_start);
462
463         /* Update the header to have the correct offsets/sizes */
464         if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
465                 int str_size;
466
467                 str_size = region[count - 1].size;
468                 fdt_set_size_dt_struct(fdt, size - str_size);
469                 fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
470                 fdt_set_size_dt_strings(fdt, str_size);
471                 fdt_set_totalsize(fdt, struct_start + size);
472         }
473
474         /* Write the header if required */
475         ptr = 0;
476         if (disp->header) {
477                 ptr = sizeof(*fdt);
478                 while (ptr < fdt_off_mem_rsvmap(fdt))
479                         out[ptr++] = '\0';
480         }
481
482         /* Output all the nodes including any mem_rsvmap/string table */
483         for (i = 0; i < count; i++) {
484                 struct fdt_region *reg = &region[i];
485
486                 memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
487                 ptr += reg->size;
488         }
489
490         return ptr;
491 }
492
493 /**
494  * show_region_list() - Print out a list of regions
495  *
496  * The list includes the region offset (absolute offset from start of FDT
497  * blob in bytes) and size
498  *
499  * @reg:        List of regions to print
500  * @count:      Number of regions
501  */
502 static void show_region_list(struct fdt_region *reg, int count)
503 {
504         int i;
505
506         printf("Regions: %d\n", count);
507         for (i = 0; i < count; i++, reg++) {
508                 printf("%d:  %-10x  %-10x\n", i, reg->offset,
509                        reg->offset + reg->size);
510         }
511 }
512
513 static int check_type_include(void *priv, int type, const char *data, int size)
514 {
515         struct display_info *disp = priv;
516         struct value_node *val;
517         int match, none_match = FDT_IS_ANY;
518
519         /* If none of our conditions mention this type, we know nothing */
520         debug("type=%x, data=%s\n", type, data ? data : "(null)");
521         if (!((disp->types_inc | disp->types_exc) & type)) {
522                 debug("   - not in any condition\n");
523                 return -1;
524         }
525
526         /*
527          * Go through the list of conditions. For inclusive conditions, we
528          * return 1 at the first match. For exclusive conditions, we must
529          * check that there are no matches.
530          */
531         if (data) {
532                 for (val = disp->value_head; val; val = val->next) {
533                         if (!(type & val->type))
534                                 continue;
535                         match = fdt_stringlist_contains(data, size,
536                                                         val->string);
537                         debug("      - val->type=%x, str='%s', match=%d\n",
538                               val->type, val->string, match);
539                         if (match && val->include) {
540                                 debug("   - match inc %s\n", val->string);
541                                 return 1;
542                         }
543                         if (match)
544                                 none_match &= ~val->type;
545                 }
546         }
547
548         /*
549          * If this is an exclusive condition, and nothing matches, then we
550          * should return 1.
551          */
552         if ((type & disp->types_exc) && (none_match & type)) {
553                 debug("   - match exc\n");
554                 /*
555                  * Allow FDT_IS_COMPAT to make the final decision in the
556                  * case where there is no specific type
557                  */
558                 if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
559                         debug("   - supressed exc node\n");
560                         return -1;
561                 }
562                 return 1;
563         }
564
565         /*
566          * Allow FDT_IS_COMPAT to make the final decision in the
567          * case where there is no specific type (inclusive)
568          */
569         if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
570                 return -1;
571
572         debug("   - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
573               disp->types_inc, disp->types_exc, none_match);
574
575         return 0;
576 }
577
578 /**
579  * h_include() - Include handler function for fdt_find_regions()
580  *
581  * This function decides whether to include or exclude a node, property or
582  * compatible string. The function is defined by fdt_find_regions().
583  *
584  * The algorithm is documented in the code - disp->invert is 0 for normal
585  * operation, and 1 to invert the sense of all matches.
586  *
587  * See
588  */
589 static int h_include(void *priv, const void *fdt, int offset, int type,
590                      const char *data, int size)
591 {
592         struct display_info *disp = priv;
593         int inc, len;
594
595         inc = check_type_include(priv, type, data, size);
596         if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
597                 return 1;
598
599         /*
600          * If the node name does not tell us anything, check the
601          * compatible string
602          */
603         if (inc == -1 && type == FDT_IS_NODE) {
604                 debug("   - checking compatible2\n");
605                 data = fdt_getprop(fdt, offset, "compatible", &len);
606                 inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
607         }
608
609         /* If we still have no idea, check for properties in the node */
610         if (inc != 1 && type == FDT_IS_NODE &&
611             (disp->types_inc & FDT_NODE_HAS_PROP)) {
612                 debug("   - checking node '%s'\n",
613                       fdt_get_name(fdt, offset, NULL));
614                 for (offset = fdt_first_property_offset(fdt, offset);
615                      offset > 0 && inc != 1;
616                      offset = fdt_next_property_offset(fdt, offset)) {
617                         const struct fdt_property *prop;
618                         const char *str;
619
620                         prop = fdt_get_property_by_offset(fdt, offset, NULL);
621                         if (!prop)
622                                 continue;
623                         str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
624                         inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
625                                                  strlen(str));
626                 }
627                 if (inc == -1)
628                         inc = 0;
629         }
630
631         switch (inc) {
632         case 1:
633                 inc = !disp->invert;
634                 break;
635         case 0:
636                 inc = disp->invert;
637                 break;
638         }
639         debug("   - returning %d\n", inc);
640
641         return inc;
642 }
643
644 static int h_cmp_region(const void *v1, const void *v2)
645 {
646         const struct fdt_region *region1 = v1, *region2 = v2;
647
648         return region1->offset - region2->offset;
649 }
650
651 static int fdtgrep_find_regions(const void *fdt,
652                 int (*include_func)(void *priv, const void *fdt, int offset,
653                                  int type, const char *data, int size),
654                 struct display_info *disp, struct fdt_region *region,
655                 int max_regions, char *path, int path_len, int flags)
656 {
657         struct fdt_region_state state;
658         int count;
659         int ret;
660
661         count = 0;
662         ret = fdt_first_region(fdt, include_func, disp,
663                         &region[count++], path, path_len,
664                         disp->flags, &state);
665         while (ret == 0) {
666                 ret = fdt_next_region(fdt, include_func, disp,
667                                 count < max_regions ? &region[count] : NULL,
668                                 path, path_len, disp->flags, &state);
669                 if (!ret)
670                         count++;
671         }
672         if (ret && ret != -FDT_ERR_NOTFOUND)
673                 return ret;
674
675         /* Find all the aliases and add those regions back in */
676         if (disp->add_aliases && count < max_regions) {
677                 int new_count;
678
679                 new_count = fdt_add_alias_regions(fdt, region, count,
680                                                   max_regions, &state);
681                 if (new_count == -FDT_ERR_NOTFOUND) {
682                         /* No alias node found */
683                 } else if (new_count < 0) {
684                         return new_count;
685                 } else if (new_count <= max_regions) {
686                         /*
687                         * The alias regions will now be at the end of the list.
688                         * Sort the regions by offset to get things into the
689                         * right order
690                         */
691                         count = new_count;
692                         qsort(region, count, sizeof(struct fdt_region),
693                               h_cmp_region);
694                 }
695         }
696
697         return count;
698 }
699
700 int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
701 {
702         int fd = 0;     /* assume stdin */
703         char *buf = NULL;
704         off_t bufsize = 1024, offset = 0;
705         int ret = 0;
706
707         *buffp = NULL;
708         if (strcmp(filename, "-") != 0) {
709                 fd = open(filename, O_RDONLY);
710                 if (fd < 0)
711                         return errno;
712         }
713
714         /* Loop until we have read everything */
715         buf = malloc(bufsize);
716         if (!buf)
717                 return -ENOMEM;
718         do {
719                 /* Expand the buffer to hold the next chunk */
720                 if (offset == bufsize) {
721                         bufsize *= 2;
722                         buf = realloc(buf, bufsize);
723                         if (!buf)
724                                 return -ENOMEM;
725                 }
726
727                 ret = read(fd, &buf[offset], bufsize - offset);
728                 if (ret < 0) {
729                         ret = errno;
730                         break;
731                 }
732                 offset += ret;
733         } while (ret != 0);
734
735         /* Clean up, including closing stdin; return errno on error */
736         close(fd);
737         if (ret)
738                 free(buf);
739         else
740                 *buffp = buf;
741         *len = bufsize;
742         return ret;
743 }
744
745 int utilfdt_read_err(const char *filename, char **buffp)
746 {
747         off_t len;
748         return utilfdt_read_err_len(filename, buffp, &len);
749 }
750
751 char *utilfdt_read_len(const char *filename, off_t *len)
752 {
753         char *buff;
754         int ret = utilfdt_read_err_len(filename, &buff, len);
755
756         if (ret) {
757                 fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
758                         strerror(ret));
759                 return NULL;
760         }
761         /* Successful read */
762         return buff;
763 }
764
765 char *utilfdt_read(const char *filename)
766 {
767         off_t len;
768         return utilfdt_read_len(filename, &len);
769 }
770
771 /**
772  * Run the main fdtgrep operation, given a filename and valid arguments
773  *
774  * @param disp          Display information / options
775  * @param filename      Filename of blob file
776  * @param return 0 if ok, -ve on error
777  */
778 static int do_fdtgrep(struct display_info *disp, const char *filename)
779 {
780         struct fdt_region *region = NULL;
781         int max_regions;
782         int count = 100;
783         char path[1024];
784         char *blob;
785         int i, ret;
786
787         blob = utilfdt_read(filename);
788         if (!blob)
789                 return -1;
790         ret = fdt_check_header(blob);
791         if (ret) {
792                 fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
793                 return ret;
794         }
795
796         /* Allow old files, but they are untested */
797         if (fdt_version(blob) < 17 && disp->value_head) {
798                 fprintf(stderr,
799                         "Warning: fdtgrep does not fully support version %d files\n",
800                         fdt_version(blob));
801         }
802
803         /*
804          * We do two passes, since we don't know how many regions we need.
805          * The first pass will count the regions, but if it is too many,
806          * we do another pass to actually record them.
807          */
808         for (i = 0; i < 2; i++) {
809                 region = realloc(region, count * sizeof(struct fdt_region));
810                 if (!region) {
811                         fprintf(stderr, "Out of memory for %d regions\n",
812                                 count);
813                         return -1;
814                 }
815                 max_regions = count;
816                 count = fdtgrep_find_regions(blob,
817                                 h_include, disp,
818                                 region, max_regions, path, sizeof(path),
819                                 disp->flags);
820                 if (count < 0) {
821                         report_error("fdt_find_regions", count);
822                         free(region);
823                         return -1;
824                 }
825                 if (count <= max_regions)
826                         break;
827         }
828         if (count > max_regions) {
829                 free(region);
830                 fprintf(stderr, "Internal error with fdtgrep_find_region()\n");
831                 return -1;
832         }
833
834         /* Optionally print a list of regions */
835         if (disp->region_list)
836                 show_region_list(region, count);
837
838         /* Output either source .dts or binary .dtb */
839         if (disp->output == OUT_DTS) {
840                 ret = display_fdt_by_regions(disp, blob, region, count);
841         } else {
842                 void *fdt;
843                 /* Allow reserved memory section to expand slightly */
844                 int size = fdt_totalsize(blob) + 16;
845
846                 fdt = malloc(size);
847                 if (!fdt) {
848                         fprintf(stderr, "Out_of_memory\n");
849                         ret = -1;
850                         goto err;
851                 }
852                 size = dump_fdt_regions(disp, blob, region, count, fdt);
853                 if (disp->remove_strings) {
854                         void *out;
855
856                         out = malloc(size);
857                         if (!out) {
858                                 fprintf(stderr, "Out_of_memory\n");
859                                 ret = -1;
860                                 goto err;
861                         }
862                         ret = fdt_remove_unused_strings(fdt, out);
863                         if (ret < 0) {
864                                 fprintf(stderr,
865                                         "Failed to remove unused strings: err=%d\n",
866                                         ret);
867                                 goto err;
868                         }
869                         free(fdt);
870                         fdt = out;
871                         ret = fdt_pack(fdt);
872                         if (ret < 0) {
873                                 fprintf(stderr, "Failed to pack: err=%d\n",
874                                         ret);
875                                 goto err;
876                         }
877                         size = fdt_totalsize(fdt);
878                 }
879
880                 if (size != fwrite(fdt, 1, size, disp->fout)) {
881                         fprintf(stderr, "Write failure, %d bytes\n", size);
882                         free(fdt);
883                         ret = 1;
884                         goto err;
885                 }
886                 free(fdt);
887         }
888 err:
889         free(blob);
890         free(region);
891
892         return ret;
893 }
894
895 static const char usage_synopsis[] =
896         "fdtgrep - extract portions from device tree\n"
897         "\n"
898         "Usage:\n"
899         "       fdtgrep <options> <dt file>|-\n\n"
900         "Output formats are:\n"
901         "\tdts - device tree soure text\n"
902         "\tdtb - device tree blob (sets -Hmt automatically)\n"
903         "\tbin - device tree fragment (may not be a valid .dtb)";
904
905 /* Helper for usage_short_opts string constant */
906 #define USAGE_COMMON_SHORT_OPTS "hV"
907
908 /* Helper for aligning long_opts array */
909 #define a_argument required_argument
910
911 /* Helper for usage_long_opts option array */
912 #define USAGE_COMMON_LONG_OPTS \
913         {"help",      no_argument, NULL, 'h'}, \
914         {"version",   no_argument, NULL, 'V'}, \
915         {NULL,        no_argument, NULL, 0x0}
916
917 /* Helper for usage_opts_help array */
918 #define USAGE_COMMON_OPTS_HELP \
919         "Print this help and exit", \
920         "Print version and exit", \
921         NULL
922
923 /* Helper for getopt case statements */
924 #define case_USAGE_COMMON_FLAGS \
925         case 'h': usage(NULL); \
926         case 'V': util_version(); \
927         case '?': usage("unknown option");
928
929 static const char usage_short_opts[] =
930                 "haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
931                 USAGE_COMMON_SHORT_OPTS;
932 static struct option const usage_long_opts[] = {
933         {"show-address",        no_argument, NULL, 'a'},
934         {"colour",              no_argument, NULL, 'A'},
935         {"include-node-with-prop", a_argument, NULL, 'b'},
936         {"include-compat",      a_argument, NULL, 'c'},
937         {"exclude-compat",      a_argument, NULL, 'C'},
938         {"diff",                no_argument, NULL, 'd'},
939         {"enter-node",          no_argument, NULL, 'e'},
940         {"show-offset",         no_argument, NULL, 'f'},
941         {"include-match",       a_argument, NULL, 'g'},
942         {"exclude-match",       a_argument, NULL, 'G'},
943         {"show-header",         no_argument, NULL, 'H'},
944         {"show-version",        no_argument, NULL, 'I'},
945         {"list-regions",        no_argument, NULL, 'l'},
946         {"list-strings",        no_argument, NULL, 'L'},
947         {"include-mem",         no_argument, NULL, 'm'},
948         {"include-node",        a_argument, NULL, 'n'},
949         {"exclude-node",        a_argument, NULL, 'N'},
950         {"include-prop",        a_argument, NULL, 'p'},
951         {"exclude-prop",        a_argument, NULL, 'P'},
952         {"remove-strings",      no_argument, NULL, 'r'},
953         {"include-root",        no_argument, NULL, 'R'},
954         {"show-subnodes",       no_argument, NULL, 's'},
955         {"skip-supernodes",     no_argument, NULL, 'S'},
956         {"show-stringtab",      no_argument, NULL, 't'},
957         {"show-aliases",        no_argument, NULL, 'T'},
958         {"out",                 a_argument, NULL, 'o'},
959         {"out-format",          a_argument, NULL, 'O'},
960         {"invert-match",        no_argument, NULL, 'v'},
961         USAGE_COMMON_LONG_OPTS,
962 };
963 static const char * const usage_opts_help[] = {
964         "Display address",
965         "Show all nodes/tags, colour those that match",
966         "Include contains containing property",
967         "Compatible nodes to include in grep",
968         "Compatible nodes to exclude in grep",
969         "Diff: Mark matching nodes with +, others with -",
970         "Enter direct subnode names of matching nodes",
971         "Display offset",
972         "Node/property/compatible string to include in grep",
973         "Node/property/compatible string to exclude in grep",
974         "Output a header",
975         "Put \"/dts-v1/;\" on first line of dts output",
976         "Output a region list",
977         "List strings in string table",
978         "Include mem_rsvmap section in binary output",
979         "Node to include in grep",
980         "Node to exclude in grep",
981         "Property to include in grep",
982         "Property to exclude in grep",
983         "Remove unused strings from string table",
984         "Include root node and all properties",
985         "Show all subnodes matching nodes",
986         "Don't include supernodes of matching nodes",
987         "Include string table in binary output",
988         "Include matching aliases in output",
989         "-o <output file>",
990         "-O <output format>",
991         "Invert the sense of matching (select non-matching lines)",
992         USAGE_COMMON_OPTS_HELP
993 };
994
995 /**
996  * Call getopt_long() with standard options
997  *
998  * Since all util code runs getopt in the same way, provide a helper.
999  */
1000 #define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
1001                                        usage_long_opts, NULL)
1002
1003 void util_usage(const char *errmsg, const char *synopsis,
1004                 const char *short_opts, struct option const long_opts[],
1005                 const char * const opts_help[])
1006 {
1007         FILE *fp = errmsg ? stderr : stdout;
1008         const char a_arg[] = "<arg>";
1009         size_t a_arg_len = strlen(a_arg) + 1;
1010         size_t i;
1011         int optlen;
1012
1013         fprintf(fp,
1014                 "Usage: %s\n"
1015                 "\n"
1016                 "Options: -[%s]\n", synopsis, short_opts);
1017
1018         /* prescan the --long opt length to auto-align */
1019         optlen = 0;
1020         for (i = 0; long_opts[i].name; ++i) {
1021                 /* +1 is for space between --opt and help text */
1022                 int l = strlen(long_opts[i].name) + 1;
1023                 if (long_opts[i].has_arg == a_argument)
1024                         l += a_arg_len;
1025                 if (optlen < l)
1026                         optlen = l;
1027         }
1028
1029         for (i = 0; long_opts[i].name; ++i) {
1030                 /* helps when adding new applets or options */
1031                 assert(opts_help[i] != NULL);
1032
1033                 /* first output the short flag if it has one */
1034                 if (long_opts[i].val > '~')
1035                         fprintf(fp, "      ");
1036                 else
1037                         fprintf(fp, "  -%c, ", long_opts[i].val);
1038
1039                 /* then the long flag */
1040                 if (long_opts[i].has_arg == no_argument) {
1041                         fprintf(fp, "--%-*s", optlen, long_opts[i].name);
1042                 } else {
1043                         fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
1044                                 (int)(optlen - strlen(long_opts[i].name) -
1045                                 a_arg_len), "");
1046                 }
1047
1048                 /* finally the help text */
1049                 fprintf(fp, "%s\n", opts_help[i]);
1050         }
1051
1052         if (errmsg) {
1053                 fprintf(fp, "\nError: %s\n", errmsg);
1054                 exit(EXIT_FAILURE);
1055         } else {
1056                 exit(EXIT_SUCCESS);
1057         }
1058 }
1059
1060 /**
1061  * Show usage and exit
1062  *
1063  * If you name all your usage variables with usage_xxx, then you can call this
1064  * help macro rather than expanding all arguments yourself.
1065  *
1066  * @param errmsg        If non-NULL, an error message to display
1067  */
1068 #define usage(errmsg) \
1069         util_usage(errmsg, usage_synopsis, usage_short_opts, \
1070                    usage_long_opts, usage_opts_help)
1071
1072 void util_version(void)
1073 {
1074         printf("Version: %s\n", "(U-Boot)");
1075         exit(0);
1076 }
1077
1078 static void scan_args(struct display_info *disp, int argc, char *argv[])
1079 {
1080         int opt;
1081
1082         while ((opt = util_getopt_long()) != EOF) {
1083                 int type = 0;
1084                 int inc = 1;
1085
1086                 switch (opt) {
1087                 case_USAGE_COMMON_FLAGS
1088                 case 'a':
1089                         disp->show_addr = 1;
1090                         break;
1091                 case 'A':
1092                         disp->all = 1;
1093                         break;
1094                 case 'b':
1095                         type = FDT_NODE_HAS_PROP;
1096                         break;
1097                 case 'C':
1098                         inc = 0;
1099                         /* no break */
1100                 case 'c':
1101                         type = FDT_IS_COMPAT;
1102                         break;
1103                 case 'd':
1104                         disp->diff = 1;
1105                         break;
1106                 case 'e':
1107                         disp->flags |= FDT_REG_DIRECT_SUBNODES;
1108                         break;
1109                 case 'f':
1110                         disp->show_offset = 1;
1111                         break;
1112                 case 'G':
1113                         inc = 0;
1114                         /* no break */
1115                 case 'g':
1116                         type = FDT_ANY_GLOBAL;
1117                         break;
1118                 case 'H':
1119                         disp->header = 1;
1120                         break;
1121                 case 'l':
1122                         disp->region_list = 1;
1123                         break;
1124                 case 'L':
1125                         disp->list_strings = 1;
1126                         break;
1127                 case 'm':
1128                         disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
1129                         break;
1130                 case 'N':
1131                         inc = 0;
1132                         /* no break */
1133                 case 'n':
1134                         type = FDT_IS_NODE;
1135                         break;
1136                 case 'o':
1137                         disp->output_fname = optarg;
1138                         break;
1139                 case 'O':
1140                         if (!strcmp(optarg, "dtb"))
1141                                 disp->output = OUT_DTB;
1142                         else if (!strcmp(optarg, "dts"))
1143                                 disp->output = OUT_DTS;
1144                         else if (!strcmp(optarg, "bin"))
1145                                 disp->output = OUT_BIN;
1146                         else
1147                                 usage("Unknown output format");
1148                         break;
1149                 case 'P':
1150                         inc = 0;
1151                         /* no break */
1152                 case 'p':
1153                         type = FDT_IS_PROP;
1154                         break;
1155                 case 'r':
1156                         disp->remove_strings = 1;
1157                         break;
1158                 case 'R':
1159                         disp->include_root = 1;
1160                         break;
1161                 case 's':
1162                         disp->flags |= FDT_REG_ALL_SUBNODES;
1163                         break;
1164                 case 'S':
1165                         disp->flags &= ~FDT_REG_SUPERNODES;
1166                         break;
1167                 case 't':
1168                         disp->flags |= FDT_REG_ADD_STRING_TAB;
1169                         break;
1170                 case 'T':
1171                         disp->add_aliases = 1;
1172                         break;
1173                 case 'v':
1174                         disp->invert = 1;
1175                         break;
1176                 case 'I':
1177                         disp->show_dts_version = 1;
1178                         break;
1179                 }
1180
1181                 if (type && value_add(disp, &disp->value_head, type, inc,
1182                                       optarg))
1183                         usage("Cannot add value");
1184         }
1185
1186         if (disp->invert && disp->types_exc)
1187                 usage("-v has no meaning when used with 'exclude' conditions");
1188 }
1189
1190 int main(int argc, char *argv[])
1191 {
1192         char *filename = NULL;
1193         struct display_info disp;
1194         int ret;
1195
1196         /* set defaults */
1197         memset(&disp, '\0', sizeof(disp));
1198         disp.flags = FDT_REG_SUPERNODES;        /* Default flags */
1199
1200         scan_args(&disp, argc, argv);
1201
1202         /* Show matched lines in colour if we can */
1203         disp.colour = disp.all && isatty(0);
1204
1205         /* Any additional arguments can match anything, just like -g */
1206         while (optind < argc - 1) {
1207                 if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
1208                               argv[optind++]))
1209                         usage("Cannot add value");
1210         }
1211
1212         if (optind < argc)
1213                 filename = argv[optind++];
1214         if (!filename)
1215                 usage("Missing filename");
1216
1217         /* If a valid .dtb is required, set flags to ensure we get one */
1218         if (disp.output == OUT_DTB) {
1219                 disp.header = 1;
1220                 disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
1221         }
1222
1223         if (disp.output_fname) {
1224                 disp.fout = fopen(disp.output_fname, "w");
1225                 if (!disp.fout)
1226                         usage("Cannot open output file");
1227         } else {
1228                 disp.fout = stdout;
1229         }
1230
1231         /* Run the grep and output the results */
1232         ret = do_fdtgrep(&disp, filename);
1233         if (disp.output_fname)
1234                 fclose(disp.fout);
1235         if (ret)
1236                 return 1;
1237
1238         return 0;
1239 }