Merge tag 'u-boot-stm32-20220617' of https://source.denx.de/u-boot/custodians/u-boot-stm
[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                 return -ENOMEM;
717         do {
718                 /* Expand the buffer to hold the next chunk */
719                 if (offset == bufsize) {
720                         bufsize *= 2;
721                         buf = realloc(buf, bufsize);
722                         if (!buf)
723                                 return -ENOMEM;
724                 }
725
726                 ret = read(fd, &buf[offset], bufsize - offset);
727                 if (ret < 0) {
728                         ret = errno;
729                         break;
730                 }
731                 offset += ret;
732         } while (ret != 0);
733
734         /* Clean up, including closing stdin; return errno on error */
735         close(fd);
736         if (ret)
737                 free(buf);
738         else
739                 *buffp = buf;
740         *len = bufsize;
741         return ret;
742 }
743
744 int utilfdt_read_err(const char *filename, char **buffp)
745 {
746         off_t len;
747         return utilfdt_read_err_len(filename, buffp, &len);
748 }
749
750 char *utilfdt_read_len(const char *filename, off_t *len)
751 {
752         char *buff;
753         int ret = utilfdt_read_err_len(filename, &buff, len);
754
755         if (ret) {
756                 fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
757                         strerror(ret));
758                 return NULL;
759         }
760         /* Successful read */
761         return buff;
762 }
763
764 char *utilfdt_read(const char *filename)
765 {
766         off_t len;
767         return utilfdt_read_len(filename, &len);
768 }
769
770 /**
771  * Run the main fdtgrep operation, given a filename and valid arguments
772  *
773  * @param disp          Display information / options
774  * @param filename      Filename of blob file
775  * @param return 0 if ok, -ve on error
776  */
777 static int do_fdtgrep(struct display_info *disp, const char *filename)
778 {
779         struct fdt_region *region = NULL;
780         int max_regions;
781         int count = 100;
782         char path[1024];
783         char *blob;
784         int i, ret;
785
786         blob = utilfdt_read(filename);
787         if (!blob)
788                 return -1;
789         ret = fdt_check_header(blob);
790         if (ret) {
791                 fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
792                 return ret;
793         }
794
795         /* Allow old files, but they are untested */
796         if (fdt_version(blob) < 17 && disp->value_head) {
797                 fprintf(stderr,
798                         "Warning: fdtgrep does not fully support version %d files\n",
799                         fdt_version(blob));
800         }
801
802         /*
803          * We do two passes, since we don't know how many regions we need.
804          * The first pass will count the regions, but if it is too many,
805          * we do another pass to actually record them.
806          */
807         for (i = 0; i < 2; i++) {
808                 region = realloc(region, count * sizeof(struct fdt_region));
809                 if (!region) {
810                         fprintf(stderr, "Out of memory for %d regions\n",
811                                 count);
812                         return -1;
813                 }
814                 max_regions = count;
815                 count = fdtgrep_find_regions(blob,
816                                 h_include, disp,
817                                 region, max_regions, path, sizeof(path),
818                                 disp->flags);
819                 if (count < 0) {
820                         report_error("fdt_find_regions", count);
821                         free(region);
822                         return -1;
823                 }
824                 if (count <= max_regions)
825                         break;
826         }
827         if (count > max_regions) {
828                 free(region);
829                 fprintf(stderr, "Internal error with fdtgrep_find_region()\n");
830                 return -1;
831         }
832
833         /* Optionally print a list of regions */
834         if (disp->region_list)
835                 show_region_list(region, count);
836
837         /* Output either source .dts or binary .dtb */
838         if (disp->output == OUT_DTS) {
839                 ret = display_fdt_by_regions(disp, blob, region, count);
840         } else {
841                 void *fdt;
842                 /* Allow reserved memory section to expand slightly */
843                 int size = fdt_totalsize(blob) + 16;
844
845                 fdt = malloc(size);
846                 if (!fdt) {
847                         fprintf(stderr, "Out_of_memory\n");
848                         ret = -1;
849                         goto err;
850                 }
851                 size = dump_fdt_regions(disp, blob, region, count, fdt);
852                 if (disp->remove_strings) {
853                         void *out;
854
855                         out = malloc(size);
856                         if (!out) {
857                                 fprintf(stderr, "Out_of_memory\n");
858                                 ret = -1;
859                                 goto err;
860                         }
861                         ret = fdt_remove_unused_strings(fdt, out);
862                         if (ret < 0) {
863                                 fprintf(stderr,
864                                         "Failed to remove unused strings: err=%d\n",
865                                         ret);
866                                 goto err;
867                         }
868                         free(fdt);
869                         fdt = out;
870                         ret = fdt_pack(fdt);
871                         if (ret < 0) {
872                                 fprintf(stderr, "Failed to pack: err=%d\n",
873                                         ret);
874                                 goto err;
875                         }
876                         size = fdt_totalsize(fdt);
877                 }
878
879                 if (size != fwrite(fdt, 1, size, disp->fout)) {
880                         fprintf(stderr, "Write failure, %d bytes\n", size);
881                         free(fdt);
882                         ret = 1;
883                         goto err;
884                 }
885                 free(fdt);
886         }
887 err:
888         free(blob);
889         free(region);
890
891         return ret;
892 }
893
894 static const char usage_synopsis[] =
895         "fdtgrep - extract portions from device tree\n"
896         "\n"
897         "Usage:\n"
898         "       fdtgrep <options> <dt file>|-\n\n"
899         "Output formats are:\n"
900         "\tdts - device tree soure text\n"
901         "\tdtb - device tree blob (sets -Hmt automatically)\n"
902         "\tbin - device tree fragment (may not be a valid .dtb)";
903
904 /* Helper for usage_short_opts string constant */
905 #define USAGE_COMMON_SHORT_OPTS "hV"
906
907 /* Helper for aligning long_opts array */
908 #define a_argument required_argument
909
910 /* Helper for usage_long_opts option array */
911 #define USAGE_COMMON_LONG_OPTS \
912         {"help",      no_argument, NULL, 'h'}, \
913         {"version",   no_argument, NULL, 'V'}, \
914         {NULL,        no_argument, NULL, 0x0}
915
916 /* Helper for usage_opts_help array */
917 #define USAGE_COMMON_OPTS_HELP \
918         "Print this help and exit", \
919         "Print version and exit", \
920         NULL
921
922 /* Helper for getopt case statements */
923 #define case_USAGE_COMMON_FLAGS \
924         case 'h': usage(NULL); \
925         /* fallthrough */ \
926         case 'V': util_version(); \
927         /* fallthrough */ \
928         case '?': usage("unknown option");
929
930 static const char usage_short_opts[] =
931                 "haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
932                 USAGE_COMMON_SHORT_OPTS;
933 static struct option const usage_long_opts[] = {
934         {"show-address",        no_argument, NULL, 'a'},
935         {"colour",              no_argument, NULL, 'A'},
936         {"include-node-with-prop", a_argument, NULL, 'b'},
937         {"include-compat",      a_argument, NULL, 'c'},
938         {"exclude-compat",      a_argument, NULL, 'C'},
939         {"diff",                no_argument, NULL, 'd'},
940         {"enter-node",          no_argument, NULL, 'e'},
941         {"show-offset",         no_argument, NULL, 'f'},
942         {"include-match",       a_argument, NULL, 'g'},
943         {"exclude-match",       a_argument, NULL, 'G'},
944         {"show-header",         no_argument, NULL, 'H'},
945         {"show-version",        no_argument, NULL, 'I'},
946         {"list-regions",        no_argument, NULL, 'l'},
947         {"list-strings",        no_argument, NULL, 'L'},
948         {"include-mem",         no_argument, NULL, 'm'},
949         {"include-node",        a_argument, NULL, 'n'},
950         {"exclude-node",        a_argument, NULL, 'N'},
951         {"include-prop",        a_argument, NULL, 'p'},
952         {"exclude-prop",        a_argument, NULL, 'P'},
953         {"remove-strings",      no_argument, NULL, 'r'},
954         {"include-root",        no_argument, NULL, 'R'},
955         {"show-subnodes",       no_argument, NULL, 's'},
956         {"skip-supernodes",     no_argument, NULL, 'S'},
957         {"show-stringtab",      no_argument, NULL, 't'},
958         {"show-aliases",        no_argument, NULL, 'T'},
959         {"out",                 a_argument, NULL, 'o'},
960         {"out-format",          a_argument, NULL, 'O'},
961         {"invert-match",        no_argument, NULL, 'v'},
962         USAGE_COMMON_LONG_OPTS,
963 };
964 static const char * const usage_opts_help[] = {
965         "Display address",
966         "Show all nodes/tags, colour those that match",
967         "Include contains containing property",
968         "Compatible nodes to include in grep",
969         "Compatible nodes to exclude in grep",
970         "Diff: Mark matching nodes with +, others with -",
971         "Enter direct subnode names of matching nodes",
972         "Display offset",
973         "Node/property/compatible string to include in grep",
974         "Node/property/compatible string to exclude in grep",
975         "Output a header",
976         "Put \"/dts-v1/;\" on first line of dts output",
977         "Output a region list",
978         "List strings in string table",
979         "Include mem_rsvmap section in binary output",
980         "Node to include in grep",
981         "Node to exclude in grep",
982         "Property to include in grep",
983         "Property to exclude in grep",
984         "Remove unused strings from string table",
985         "Include root node and all properties",
986         "Show all subnodes matching nodes",
987         "Don't include supernodes of matching nodes",
988         "Include string table in binary output",
989         "Include matching aliases in output",
990         "-o <output file>",
991         "-O <output format>",
992         "Invert the sense of matching (select non-matching lines)",
993         USAGE_COMMON_OPTS_HELP
994 };
995
996 /**
997  * Call getopt_long() with standard options
998  *
999  * Since all util code runs getopt in the same way, provide a helper.
1000  */
1001 #define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
1002                                        usage_long_opts, NULL)
1003
1004 void util_usage(const char *errmsg, const char *synopsis,
1005                 const char *short_opts, struct option const long_opts[],
1006                 const char * const opts_help[])
1007 {
1008         FILE *fp = errmsg ? stderr : stdout;
1009         const char a_arg[] = "<arg>";
1010         size_t a_arg_len = strlen(a_arg) + 1;
1011         size_t i;
1012         int optlen;
1013
1014         fprintf(fp,
1015                 "Usage: %s\n"
1016                 "\n"
1017                 "Options: -[%s]\n", synopsis, short_opts);
1018
1019         /* prescan the --long opt length to auto-align */
1020         optlen = 0;
1021         for (i = 0; long_opts[i].name; ++i) {
1022                 /* +1 is for space between --opt and help text */
1023                 int l = strlen(long_opts[i].name) + 1;
1024                 if (long_opts[i].has_arg == a_argument)
1025                         l += a_arg_len;
1026                 if (optlen < l)
1027                         optlen = l;
1028         }
1029
1030         for (i = 0; long_opts[i].name; ++i) {
1031                 /* helps when adding new applets or options */
1032                 assert(opts_help[i] != NULL);
1033
1034                 /* first output the short flag if it has one */
1035                 if (long_opts[i].val > '~')
1036                         fprintf(fp, "      ");
1037                 else
1038                         fprintf(fp, "  -%c, ", long_opts[i].val);
1039
1040                 /* then the long flag */
1041                 if (long_opts[i].has_arg == no_argument) {
1042                         fprintf(fp, "--%-*s", optlen, long_opts[i].name);
1043                 } else {
1044                         fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
1045                                 (int)(optlen - strlen(long_opts[i].name) -
1046                                 a_arg_len), "");
1047                 }
1048
1049                 /* finally the help text */
1050                 fprintf(fp, "%s\n", opts_help[i]);
1051         }
1052
1053         if (errmsg) {
1054                 fprintf(fp, "\nError: %s\n", errmsg);
1055                 exit(EXIT_FAILURE);
1056         } else {
1057                 exit(EXIT_SUCCESS);
1058         }
1059 }
1060
1061 /**
1062  * Show usage and exit
1063  *
1064  * If you name all your usage variables with usage_xxx, then you can call this
1065  * help macro rather than expanding all arguments yourself.
1066  *
1067  * @param errmsg        If non-NULL, an error message to display
1068  */
1069 #define usage(errmsg) \
1070         util_usage(errmsg, usage_synopsis, usage_short_opts, \
1071                    usage_long_opts, usage_opts_help)
1072
1073 void util_version(void)
1074 {
1075         printf("Version: %s\n", "(U-Boot)");
1076         exit(0);
1077 }
1078
1079 static void scan_args(struct display_info *disp, int argc, char *argv[])
1080 {
1081         int opt;
1082
1083         while ((opt = util_getopt_long()) != EOF) {
1084                 int type = 0;
1085                 int inc = 1;
1086
1087                 switch (opt) {
1088                 case_USAGE_COMMON_FLAGS
1089                 /* fallthrough */
1090                 case 'a':
1091                         disp->show_addr = 1;
1092                         break;
1093                 case 'A':
1094                         disp->all = 1;
1095                         break;
1096                 case 'b':
1097                         type = FDT_NODE_HAS_PROP;
1098                         break;
1099                 case 'C':
1100                         inc = 0;
1101                         /* fallthrough */
1102                 case 'c':
1103                         type = FDT_IS_COMPAT;
1104                         break;
1105                 case 'd':
1106                         disp->diff = 1;
1107                         break;
1108                 case 'e':
1109                         disp->flags |= FDT_REG_DIRECT_SUBNODES;
1110                         break;
1111                 case 'f':
1112                         disp->show_offset = 1;
1113                         break;
1114                 case 'G':
1115                         inc = 0;
1116                         /* fallthrough */
1117                 case 'g':
1118                         type = FDT_ANY_GLOBAL;
1119                         break;
1120                 case 'H':
1121                         disp->header = 1;
1122                         break;
1123                 case 'l':
1124                         disp->region_list = 1;
1125                         break;
1126                 case 'L':
1127                         disp->list_strings = 1;
1128                         break;
1129                 case 'm':
1130                         disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
1131                         break;
1132                 case 'N':
1133                         inc = 0;
1134                         /* fallthrough */
1135                 case 'n':
1136                         type = FDT_IS_NODE;
1137                         break;
1138                 case 'o':
1139                         disp->output_fname = optarg;
1140                         break;
1141                 case 'O':
1142                         if (!strcmp(optarg, "dtb"))
1143                                 disp->output = OUT_DTB;
1144                         else if (!strcmp(optarg, "dts"))
1145                                 disp->output = OUT_DTS;
1146                         else if (!strcmp(optarg, "bin"))
1147                                 disp->output = OUT_BIN;
1148                         else
1149                                 usage("Unknown output format");
1150                         break;
1151                 case 'P':
1152                         inc = 0;
1153                         /* fallthrough */
1154                 case 'p':
1155                         type = FDT_IS_PROP;
1156                         break;
1157                 case 'r':
1158                         disp->remove_strings = 1;
1159                         break;
1160                 case 'R':
1161                         disp->include_root = 1;
1162                         break;
1163                 case 's':
1164                         disp->flags |= FDT_REG_ALL_SUBNODES;
1165                         break;
1166                 case 'S':
1167                         disp->flags &= ~FDT_REG_SUPERNODES;
1168                         break;
1169                 case 't':
1170                         disp->flags |= FDT_REG_ADD_STRING_TAB;
1171                         break;
1172                 case 'T':
1173                         disp->add_aliases = 1;
1174                         break;
1175                 case 'v':
1176                         disp->invert = 1;
1177                         break;
1178                 case 'I':
1179                         disp->show_dts_version = 1;
1180                         break;
1181                 }
1182
1183                 if (type && value_add(disp, &disp->value_head, type, inc,
1184                                       optarg))
1185                         usage("Cannot add value");
1186         }
1187
1188         if (disp->invert && disp->types_exc)
1189                 usage("-v has no meaning when used with 'exclude' conditions");
1190 }
1191
1192 int main(int argc, char *argv[])
1193 {
1194         char *filename = NULL;
1195         struct display_info disp;
1196         int ret;
1197
1198         /* set defaults */
1199         memset(&disp, '\0', sizeof(disp));
1200         disp.flags = FDT_REG_SUPERNODES;        /* Default flags */
1201
1202         scan_args(&disp, argc, argv);
1203
1204         /* Show matched lines in colour if we can */
1205         disp.colour = disp.all && isatty(0);
1206
1207         /* Any additional arguments can match anything, just like -g */
1208         while (optind < argc - 1) {
1209                 if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
1210                               argv[optind++]))
1211                         usage("Cannot add value");
1212         }
1213
1214         if (optind < argc)
1215                 filename = argv[optind++];
1216         if (!filename)
1217                 usage("Missing filename");
1218
1219         /* If a valid .dtb is required, set flags to ensure we get one */
1220         if (disp.output == OUT_DTB) {
1221                 disp.header = 1;
1222                 disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
1223         }
1224
1225         if (disp.output_fname) {
1226                 disp.fout = fopen(disp.output_fname, "w");
1227                 if (!disp.fout)
1228                         usage("Cannot open output file");
1229         } else {
1230                 disp.fout = stdout;
1231         }
1232
1233         /* Run the grep and output the results */
1234         ret = do_fdtgrep(&disp, filename);
1235         if (disp.output_fname)
1236                 fclose(disp.fout);
1237         if (ret)
1238                 return 1;
1239
1240         return 0;
1241 }