pico-imx7d: Add default DFU targets
[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
21 #include "fdt_host.h"
22 #include "libfdt_internal.h"
23
24 /* Define DEBUG to get some debugging output on stderr */
25 #ifdef DEBUG
26 #define debug(a, b...) fprintf(stderr, a, ## b)
27 #else
28 #define debug(a, b...)
29 #endif
30
31 /* A linked list of values we are grepping for */
32 struct value_node {
33         int type;               /* Types this value matches (FDT_IS... mask) */
34         int include;            /* 1 to include matches, 0 to exclude */
35         const char *string;     /* String to match */
36         struct value_node *next;        /* Pointer to next node, or NULL */
37 };
38
39 /* Output formats we support */
40 enum output_t {
41         OUT_DTS,                /* Device tree source */
42         OUT_DTB,                /* Valid device tree binary */
43         OUT_BIN,                /* Fragment of .dtb, for hashing */
44 };
45
46 /* Holds information which controls our output and options */
47 struct display_info {
48         enum output_t output;   /* Output format */
49         int add_aliases;        /* Add aliases node to output */
50         int all;                /* Display all properties/nodes */
51         int colour;             /* Display output in ANSI colour */
52         int region_list;        /* Output a region list */
53         int flags;              /* Flags (FDT_REG_...) */
54         int list_strings;       /* List strings in string table */
55         int show_offset;        /* Show offset */
56         int show_addr;          /* Show address */
57         int header;             /* Output an FDT header */
58         int diff;               /* Show +/- diff markers */
59         int include_root;       /* Include the root node and all properties */
60         int remove_strings;     /* Remove unused strings */
61         int show_dts_version;   /* Put '/dts-v1/;' on the first line */
62         int types_inc;          /* Mask of types that we include (FDT_IS...) */
63         int types_exc;          /* Mask of types that we exclude (FDT_IS...) */
64         int invert;             /* Invert polarity of match */
65         struct value_node *value_head;  /* List of values to match */
66         const char *output_fname;       /* Output filename */
67         FILE *fout;             /* File to write dts/dtb output */
68 };
69
70 static void report_error(const char *where, int err)
71 {
72         fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
73 }
74
75 /* Supported ANSI colours */
76 enum {
77         COL_BLACK,
78         COL_RED,
79         COL_GREEN,
80         COL_YELLOW,
81         COL_BLUE,
82         COL_MAGENTA,
83         COL_CYAN,
84         COL_WHITE,
85
86         COL_NONE = -1,
87 };
88
89 /**
90  * print_ansi_colour() - Print out the ANSI sequence for a colour
91  *
92  * @fout:       Output file
93  * @col:        Colour to output (COL_...), or COL_NONE to reset colour
94  */
95 static void print_ansi_colour(FILE *fout, int col)
96 {
97         if (col == COL_NONE)
98                 fprintf(fout, "\033[0m");
99         else
100                 fprintf(fout, "\033[1;%dm", col + 30);
101 }
102
103
104 /**
105  * value_add() - Add a new value to our list of things to grep for
106  *
107  * @disp:       Display structure, holding info about our options
108  * @headp:      Pointer to header pointer of list
109  * @type:       Type of this value (FDT_IS_...)
110  * @include:    1 if we want to include matches, 0 to exclude
111  * @str:        String value to match
112  */
113 static int value_add(struct display_info *disp, struct value_node **headp,
114                      int type, int include, const char *str)
115 {
116         struct value_node *node;
117
118         /*
119          * Keep track of which types we are excluding/including. We don't
120          * allow both including and excluding things, because it doesn't make
121          * sense. 'Including' means that everything not mentioned is
122          * excluded. 'Excluding' means that everything not mentioned is
123          * included. So using the two together would be meaningless.
124          */
125         if (include)
126                 disp->types_inc |= type;
127         else
128                 disp->types_exc |= type;
129         if (disp->types_inc & disp->types_exc & type) {
130                 fprintf(stderr,
131                         "Cannot use both include and exclude for '%s'\n", str);
132                 return -1;
133         }
134
135         str = strdup(str);
136         if (!str)
137                 goto err_mem;
138         node = malloc(sizeof(*node));
139         if (!node)
140                 goto err_mem;
141         node->next = *headp;
142         node->type = type;
143         node->include = include;
144         node->string = str;
145         *headp = node;
146
147         return 0;
148 err_mem:
149         fprintf(stderr, "Out of memory\n");
150         return -1;
151 }
152
153 static bool util_is_printable_string(const void *data, int len)
154 {
155         const char *s = data;
156         const char *ss, *se;
157
158         /* zero length is not */
159         if (len == 0)
160                 return 0;
161
162         /* must terminate with zero */
163         if (s[len - 1] != '\0')
164                 return 0;
165
166         se = s + len;
167
168         while (s < se) {
169                 ss = s;
170                 while (s < se && *s && isprint((unsigned char)*s))
171                         s++;
172
173                 /* not zero, or not done yet */
174                 if (*s != '\0' || s == ss)
175                         return 0;
176
177                 s++;
178         }
179
180         return 1;
181 }
182
183 static void utilfdt_print_data(const char *data, int len)
184 {
185         int i;
186         const char *p = data;
187         const char *s;
188
189         /* no data, don't print */
190         if (len == 0)
191                 return;
192
193         if (util_is_printable_string(data, len)) {
194                 printf(" = ");
195
196                 s = data;
197                 do {
198                         printf("\"%s\"", s);
199                         s += strlen(s) + 1;
200                         if (s < data + len)
201                                 printf(", ");
202                 } while (s < data + len);
203
204         } else if ((len % 4) == 0) {
205                 const uint32_t *cell = (const uint32_t *)data;
206
207                 printf(" = <");
208                 for (i = 0, len /= 4; i < len; i++)
209                         printf("0x%08x%s", fdt32_to_cpu(cell[i]),
210                                i < (len - 1) ? " " : "");
211                 printf(">");
212         } else {
213                 printf(" = [");
214                 for (i = 0; i < len; i++)
215                         printf("%02x%s", *p++, i < len - 1 ? " " : "");
216                 printf("]");
217         }
218 }
219
220 /**
221  * display_fdt_by_regions() - Display regions of an FDT source
222  *
223  * This dumps an FDT as source, but only certain regions of it. This is the
224  * final stage of the grep - we have a list of regions we want to display,
225  * and this function displays them.
226  *
227  * @disp:       Display structure, holding info about our options
228  * @blob:       FDT blob to display
229  * @region:     List of regions to display
230  * @count:      Number of regions
231  */
232 static int display_fdt_by_regions(struct display_info *disp, const void *blob,
233                 struct fdt_region region[], int count)
234 {
235         struct fdt_region *reg = region, *reg_end = region + count;
236         uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
237         int base = fdt_off_dt_struct(blob);
238         int version = fdt_version(blob);
239         int offset, nextoffset;
240         int tag, depth, shift;
241         FILE *f = disp->fout;
242         uint64_t addr, size;
243         int in_region;
244         int file_ofs;
245         int i;
246
247         if (disp->show_dts_version)
248                 fprintf(f, "/dts-v1/;\n");
249
250         if (disp->header) {
251                 fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
252                 fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
253                         fdt_totalsize(blob));
254                 fprintf(f, "// off_dt_struct:\t0x%x\n",
255                         fdt_off_dt_struct(blob));
256                 fprintf(f, "// off_dt_strings:\t0x%x\n",
257                         fdt_off_dt_strings(blob));
258                 fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
259                 fprintf(f, "// version:\t\t%d\n", version);
260                 fprintf(f, "// last_comp_version:\t%d\n",
261                         fdt_last_comp_version(blob));
262                 if (version >= 2) {
263                         fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
264                                 fdt_boot_cpuid_phys(blob));
265                 }
266                 if (version >= 3) {
267                         fprintf(f, "// size_dt_strings:\t0x%x\n",
268                                 fdt_size_dt_strings(blob));
269                 }
270                 if (version >= 17) {
271                         fprintf(f, "// size_dt_struct:\t0x%x\n",
272                                 fdt_size_dt_struct(blob));
273                 }
274                 fprintf(f, "\n");
275         }
276
277         if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
278                 const struct fdt_reserve_entry *p_rsvmap;
279
280                 p_rsvmap = (const struct fdt_reserve_entry *)
281                                 ((const char *)blob + off_mem_rsvmap);
282                 for (i = 0; ; i++) {
283                         addr = fdt64_to_cpu(p_rsvmap[i].address);
284                         size = fdt64_to_cpu(p_rsvmap[i].size);
285                         if (addr == 0 && size == 0)
286                                 break;
287
288                         fprintf(f, "/memreserve/ %llx %llx;\n",
289                                 (unsigned long long)addr,
290                                 (unsigned long long)size);
291                 }
292         }
293
294         depth = 0;
295         nextoffset = 0;
296         shift = 4;      /* 4 spaces per indent */
297         do {
298                 const struct fdt_property *prop;
299                 const char *name;
300                 int show;
301                 int len;
302
303                 offset = nextoffset;
304
305                 /*
306                  * Work out the file offset of this offset, and decide
307                  * whether it is in the region list or not
308                  */
309                 file_ofs = base + offset;
310                 if (reg < reg_end && file_ofs >= reg->offset + reg->size)
311                         reg++;
312                 in_region = reg < reg_end && file_ofs >= reg->offset &&
313                                 file_ofs < reg->offset + reg->size;
314                 tag = fdt_next_tag(blob, offset, &nextoffset);
315
316                 if (tag == FDT_END)
317                         break;
318                 show = in_region || disp->all;
319                 if (show && disp->diff)
320                         fprintf(f, "%c", in_region ? '+' : '-');
321
322                 if (!show) {
323                         /* Do this here to avoid 'if (show)' in every 'case' */
324                         if (tag == FDT_BEGIN_NODE)
325                                 depth++;
326                         else if (tag == FDT_END_NODE)
327                                 depth--;
328                         continue;
329                 }
330                 if (tag != FDT_END) {
331                         if (disp->show_addr)
332                                 fprintf(f, "%4x: ", file_ofs);
333                         if (disp->show_offset)
334                                 fprintf(f, "%4x: ", file_ofs - base);
335                 }
336
337                 /* Green means included, red means excluded */
338                 if (disp->colour)
339                         print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
340
341                 switch (tag) {
342                 case FDT_PROP:
343                         prop = fdt_get_property_by_offset(blob, offset, NULL);
344                         name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
345                         fprintf(f, "%*s%s", depth * shift, "", name);
346                         utilfdt_print_data(prop->data,
347                                            fdt32_to_cpu(prop->len));
348                         fprintf(f, ";");
349                         break;
350
351                 case FDT_NOP:
352                         fprintf(f, "%*s// [NOP]", depth * shift, "");
353                         break;
354
355                 case FDT_BEGIN_NODE:
356                         name = fdt_get_name(blob, offset, &len);
357                         fprintf(f, "%*s%s {", depth++ * shift, "",
358                                 *name ? name : "/");
359                         break;
360
361                 case FDT_END_NODE:
362                         fprintf(f, "%*s};", --depth * shift, "");
363                         break;
364                 }
365
366                 /* Reset colour back to normal before end of line */
367                 if (disp->colour)
368                         print_ansi_colour(f, COL_NONE);
369                 fprintf(f, "\n");
370         } while (1);
371
372         /* Print a list of strings if requested */
373         if (disp->list_strings) {
374                 const char *str;
375                 int str_base = fdt_off_dt_strings(blob);
376
377                 for (offset = 0; offset < fdt_size_dt_strings(blob);
378                                 offset += strlen(str) + 1) {
379                         str = fdt_string(blob, offset);
380                         int len = strlen(str) + 1;
381                         int show;
382
383                         /* Only print strings that are in the region */
384                         file_ofs = str_base + offset;
385                         in_region = reg < reg_end &&
386                                         file_ofs >= reg->offset &&
387                                         file_ofs + len < reg->offset +
388                                                 reg->size;
389                         show = in_region || disp->all;
390                         if (show && disp->diff)
391                                 printf("%c", in_region ? '+' : '-');
392                         if (disp->show_addr)
393                                 printf("%4x: ", file_ofs);
394                         if (disp->show_offset)
395                                 printf("%4x: ", offset);
396                         printf("%s\n", str);
397                 }
398         }
399
400         return 0;
401 }
402
403 /**
404  * dump_fdt_regions() - Dump regions of an FDT as binary data
405  *
406  * This dumps an FDT as binary, but only certain regions of it. This is the
407  * final stage of the grep - we have a list of regions we want to dump,
408  * and this function dumps them.
409  *
410  * The output of this function may or may not be a valid FDT. To ensure it
411  * is, these disp->flags must be set:
412  *
413  *   FDT_REG_SUPERNODES: ensures that subnodes are preceded by their
414  *              parents. Without this option, fragments of subnode data may be
415  *              output without the supernodes above them. This is useful for
416  *              hashing but cannot produce a valid FDT.
417  *   FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
418  *              Without this none of the properties will have names
419  *   FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
420  *              without this.
421  *
422  * @disp:       Display structure, holding info about our options
423  * @blob:       FDT blob to display
424  * @region:     List of regions to display
425  * @count:      Number of regions
426  * @out:        Output destination
427  */
428 static int dump_fdt_regions(struct display_info *disp, const void *blob,
429                 struct fdt_region region[], int count, char *out)
430 {
431         struct fdt_header *fdt;
432         int size, struct_start;
433         int ptr;
434         int i;
435
436         /* Set up a basic header (even if we don't actually write it) */
437         fdt = (struct fdt_header *)out;
438         memset(fdt, '\0', sizeof(*fdt));
439         fdt_set_magic(fdt, FDT_MAGIC);
440         struct_start = FDT_ALIGN(sizeof(struct fdt_header),
441                                         sizeof(struct fdt_reserve_entry));
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 = malloc(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                 free(region);
827                 fprintf(stderr, "Internal error with fdtgrep_find_region)(\n");
828                 return -1;
829         }
830
831         /* Optionally print a list of regions */
832         if (disp->region_list)
833                 show_region_list(region, count);
834
835         /* Output either source .dts or binary .dtb */
836         if (disp->output == OUT_DTS) {
837                 ret = display_fdt_by_regions(disp, blob, region, count);
838         } else {
839                 void *fdt;
840                 /* Allow reserved memory section to expand slightly */
841                 int size = fdt_totalsize(blob) + 16;
842
843                 fdt = malloc(size);
844                 if (!fdt) {
845                         fprintf(stderr, "Out_of_memory\n");
846                         ret = -1;
847                         goto err;
848                 }
849                 size = dump_fdt_regions(disp, blob, region, count, fdt);
850                 if (disp->remove_strings) {
851                         void *out;
852
853                         out = malloc(size);
854                         if (!out) {
855                                 fprintf(stderr, "Out_of_memory\n");
856                                 ret = -1;
857                                 goto err;
858                         }
859                         ret = fdt_remove_unused_strings(fdt, out);
860                         if (ret < 0) {
861                                 fprintf(stderr,
862                                         "Failed to remove unused strings: err=%d\n",
863                                         ret);
864                                 goto err;
865                         }
866                         free(fdt);
867                         fdt = out;
868                         ret = fdt_pack(fdt);
869                         if (ret < 0) {
870                                 fprintf(stderr, "Failed to pack: err=%d\n",
871                                         ret);
872                                 goto err;
873                         }
874                         size = fdt_totalsize(fdt);
875                 }
876
877                 if (size != fwrite(fdt, 1, size, disp->fout)) {
878                         fprintf(stderr, "Write failure, %d bytes\n", size);
879                         free(fdt);
880                         ret = 1;
881                         goto err;
882                 }
883                 free(fdt);
884         }
885 err:
886         free(blob);
887         free(region);
888
889         return ret;
890 }
891
892 static const char usage_synopsis[] =
893         "fdtgrep - extract portions from device tree\n"
894         "\n"
895         "Usage:\n"
896         "       fdtgrep <options> <dt file>|-\n\n"
897         "Output formats are:\n"
898         "\tdts - device tree soure text\n"
899         "\tdtb - device tree blob (sets -Hmt automatically)\n"
900         "\tbin - device tree fragment (may not be a valid .dtb)";
901
902 /* Helper for usage_short_opts string constant */
903 #define USAGE_COMMON_SHORT_OPTS "hV"
904
905 /* Helper for aligning long_opts array */
906 #define a_argument required_argument
907
908 /* Helper for usage_long_opts option array */
909 #define USAGE_COMMON_LONG_OPTS \
910         {"help",      no_argument, NULL, 'h'}, \
911         {"version",   no_argument, NULL, 'V'}, \
912         {NULL,        no_argument, NULL, 0x0}
913
914 /* Helper for usage_opts_help array */
915 #define USAGE_COMMON_OPTS_HELP \
916         "Print this help and exit", \
917         "Print version and exit", \
918         NULL
919
920 /* Helper for getopt case statements */
921 #define case_USAGE_COMMON_FLAGS \
922         case 'h': usage(NULL); \
923         case 'V': util_version(); \
924         case '?': usage("unknown option");
925
926 static const char usage_short_opts[] =
927                 "haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
928                 USAGE_COMMON_SHORT_OPTS;
929 static struct option const usage_long_opts[] = {
930         {"show-address",        no_argument, NULL, 'a'},
931         {"colour",              no_argument, NULL, 'A'},
932         {"include-node-with-prop", a_argument, NULL, 'b'},
933         {"include-compat",      a_argument, NULL, 'c'},
934         {"exclude-compat",      a_argument, NULL, 'C'},
935         {"diff",                no_argument, NULL, 'd'},
936         {"enter-node",          no_argument, NULL, 'e'},
937         {"show-offset",         no_argument, NULL, 'f'},
938         {"include-match",       a_argument, NULL, 'g'},
939         {"exclude-match",       a_argument, NULL, 'G'},
940         {"show-header",         no_argument, NULL, 'H'},
941         {"show-version",        no_argument, NULL, 'I'},
942         {"list-regions",        no_argument, NULL, 'l'},
943         {"list-strings",        no_argument, NULL, 'L'},
944         {"include-mem",         no_argument, NULL, 'm'},
945         {"include-node",        a_argument, NULL, 'n'},
946         {"exclude-node",        a_argument, NULL, 'N'},
947         {"include-prop",        a_argument, NULL, 'p'},
948         {"exclude-prop",        a_argument, NULL, 'P'},
949         {"remove-strings",      no_argument, NULL, 'r'},
950         {"include-root",        no_argument, NULL, 'R'},
951         {"show-subnodes",       no_argument, NULL, 's'},
952         {"skip-supernodes",     no_argument, NULL, 'S'},
953         {"show-stringtab",      no_argument, NULL, 't'},
954         {"show-aliases",        no_argument, NULL, 'T'},
955         {"out",                 a_argument, NULL, 'o'},
956         {"out-format",          a_argument, NULL, 'O'},
957         {"invert-match",        no_argument, NULL, 'v'},
958         USAGE_COMMON_LONG_OPTS,
959 };
960 static const char * const usage_opts_help[] = {
961         "Display address",
962         "Show all nodes/tags, colour those that match",
963         "Include contains containing property",
964         "Compatible nodes to include in grep",
965         "Compatible nodes to exclude in grep",
966         "Diff: Mark matching nodes with +, others with -",
967         "Enter direct subnode names of matching nodes",
968         "Display offset",
969         "Node/property/compatible string to include in grep",
970         "Node/property/compatible string to exclude in grep",
971         "Output a header",
972         "Put \"/dts-v1/;\" on first line of dts output",
973         "Output a region list",
974         "List strings in string table",
975         "Include mem_rsvmap section in binary output",
976         "Node to include in grep",
977         "Node to exclude in grep",
978         "Property to include in grep",
979         "Property to exclude in grep",
980         "Remove unused strings from string table",
981         "Include root node and all properties",
982         "Show all subnodes matching nodes",
983         "Don't include supernodes of matching nodes",
984         "Include string table in binary output",
985         "Include matching aliases in output",
986         "-o <output file>",
987         "-O <output format>",
988         "Invert the sense of matching (select non-matching lines)",
989         USAGE_COMMON_OPTS_HELP
990 };
991
992 /**
993  * Call getopt_long() with standard options
994  *
995  * Since all util code runs getopt in the same way, provide a helper.
996  */
997 #define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
998                                        usage_long_opts, NULL)
999
1000 void util_usage(const char *errmsg, const char *synopsis,
1001                 const char *short_opts, struct option const long_opts[],
1002                 const char * const opts_help[])
1003 {
1004         FILE *fp = errmsg ? stderr : stdout;
1005         const char a_arg[] = "<arg>";
1006         size_t a_arg_len = strlen(a_arg) + 1;
1007         size_t i;
1008         int optlen;
1009
1010         fprintf(fp,
1011                 "Usage: %s\n"
1012                 "\n"
1013                 "Options: -[%s]\n", synopsis, short_opts);
1014
1015         /* prescan the --long opt length to auto-align */
1016         optlen = 0;
1017         for (i = 0; long_opts[i].name; ++i) {
1018                 /* +1 is for space between --opt and help text */
1019                 int l = strlen(long_opts[i].name) + 1;
1020                 if (long_opts[i].has_arg == a_argument)
1021                         l += a_arg_len;
1022                 if (optlen < l)
1023                         optlen = l;
1024         }
1025
1026         for (i = 0; long_opts[i].name; ++i) {
1027                 /* helps when adding new applets or options */
1028                 assert(opts_help[i] != NULL);
1029
1030                 /* first output the short flag if it has one */
1031                 if (long_opts[i].val > '~')
1032                         fprintf(fp, "      ");
1033                 else
1034                         fprintf(fp, "  -%c, ", long_opts[i].val);
1035
1036                 /* then the long flag */
1037                 if (long_opts[i].has_arg == no_argument) {
1038                         fprintf(fp, "--%-*s", optlen, long_opts[i].name);
1039                 } else {
1040                         fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
1041                                 (int)(optlen - strlen(long_opts[i].name) -
1042                                 a_arg_len), "");
1043                 }
1044
1045                 /* finally the help text */
1046                 fprintf(fp, "%s\n", opts_help[i]);
1047         }
1048
1049         if (errmsg) {
1050                 fprintf(fp, "\nError: %s\n", errmsg);
1051                 exit(EXIT_FAILURE);
1052         } else {
1053                 exit(EXIT_SUCCESS);
1054         }
1055 }
1056
1057 /**
1058  * Show usage and exit
1059  *
1060  * If you name all your usage variables with usage_xxx, then you can call this
1061  * help macro rather than expanding all arguments yourself.
1062  *
1063  * @param errmsg        If non-NULL, an error message to display
1064  */
1065 #define usage(errmsg) \
1066         util_usage(errmsg, usage_synopsis, usage_short_opts, \
1067                    usage_long_opts, usage_opts_help)
1068
1069 void util_version(void)
1070 {
1071         printf("Version: %s\n", "(U-Boot)");
1072         exit(0);
1073 }
1074
1075 static void scan_args(struct display_info *disp, int argc, char *argv[])
1076 {
1077         int opt;
1078
1079         while ((opt = util_getopt_long()) != EOF) {
1080                 int type = 0;
1081                 int inc = 1;
1082
1083                 switch (opt) {
1084                 case_USAGE_COMMON_FLAGS
1085                 case 'a':
1086                         disp->show_addr = 1;
1087                         break;
1088                 case 'A':
1089                         disp->all = 1;
1090                         break;
1091                 case 'b':
1092                         type = FDT_NODE_HAS_PROP;
1093                         break;
1094                 case 'C':
1095                         inc = 0;
1096                         /* no break */
1097                 case 'c':
1098                         type = FDT_IS_COMPAT;
1099                         break;
1100                 case 'd':
1101                         disp->diff = 1;
1102                         break;
1103                 case 'e':
1104                         disp->flags |= FDT_REG_DIRECT_SUBNODES;
1105                         break;
1106                 case 'f':
1107                         disp->show_offset = 1;
1108                         break;
1109                 case 'G':
1110                         inc = 0;
1111                         /* no break */
1112                 case 'g':
1113                         type = FDT_ANY_GLOBAL;
1114                         break;
1115                 case 'H':
1116                         disp->header = 1;
1117                         break;
1118                 case 'l':
1119                         disp->region_list = 1;
1120                         break;
1121                 case 'L':
1122                         disp->list_strings = 1;
1123                         break;
1124                 case 'm':
1125                         disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
1126                         break;
1127                 case 'N':
1128                         inc = 0;
1129                         /* no break */
1130                 case 'n':
1131                         type = FDT_IS_NODE;
1132                         break;
1133                 case 'o':
1134                         disp->output_fname = optarg;
1135                         break;
1136                 case 'O':
1137                         if (!strcmp(optarg, "dtb"))
1138                                 disp->output = OUT_DTB;
1139                         else if (!strcmp(optarg, "dts"))
1140                                 disp->output = OUT_DTS;
1141                         else if (!strcmp(optarg, "bin"))
1142                                 disp->output = OUT_BIN;
1143                         else
1144                                 usage("Unknown output format");
1145                         break;
1146                 case 'P':
1147                         inc = 0;
1148                         /* no break */
1149                 case 'p':
1150                         type = FDT_IS_PROP;
1151                         break;
1152                 case 'r':
1153                         disp->remove_strings = 1;
1154                         break;
1155                 case 'R':
1156                         disp->include_root = 1;
1157                         break;
1158                 case 's':
1159                         disp->flags |= FDT_REG_ALL_SUBNODES;
1160                         break;
1161                 case 'S':
1162                         disp->flags &= ~FDT_REG_SUPERNODES;
1163                         break;
1164                 case 't':
1165                         disp->flags |= FDT_REG_ADD_STRING_TAB;
1166                         break;
1167                 case 'T':
1168                         disp->add_aliases = 1;
1169                         break;
1170                 case 'v':
1171                         disp->invert = 1;
1172                         break;
1173                 case 'I':
1174                         disp->show_dts_version = 1;
1175                         break;
1176                 }
1177
1178                 if (type && value_add(disp, &disp->value_head, type, inc,
1179                                       optarg))
1180                         usage("Cannot add value");
1181         }
1182
1183         if (disp->invert && disp->types_exc)
1184                 usage("-v has no meaning when used with 'exclude' conditions");
1185 }
1186
1187 int main(int argc, char *argv[])
1188 {
1189         char *filename = NULL;
1190         struct display_info disp;
1191         int ret;
1192
1193         /* set defaults */
1194         memset(&disp, '\0', sizeof(disp));
1195         disp.flags = FDT_REG_SUPERNODES;        /* Default flags */
1196
1197         scan_args(&disp, argc, argv);
1198
1199         /* Show matched lines in colour if we can */
1200         disp.colour = disp.all && isatty(0);
1201
1202         /* Any additional arguments can match anything, just like -g */
1203         while (optind < argc - 1) {
1204                 if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
1205                               argv[optind++]))
1206                         usage("Cannot add value");
1207         }
1208
1209         if (optind < argc)
1210                 filename = argv[optind++];
1211         if (!filename)
1212                 usage("Missing filename");
1213
1214         /* If a valid .dtb is required, set flags to ensure we get one */
1215         if (disp.output == OUT_DTB) {
1216                 disp.header = 1;
1217                 disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
1218         }
1219
1220         if (disp.output_fname) {
1221                 disp.fout = fopen(disp.output_fname, "w");
1222                 if (!disp.fout)
1223                         usage("Cannot open output file");
1224         } else {
1225                 disp.fout = stdout;
1226         }
1227
1228         /* Run the grep and output the results */
1229         ret = do_fdtgrep(&disp, filename);
1230         if (disp.output_fname)
1231                 fclose(disp.fout);
1232         if (ret)
1233                 return 1;
1234
1235         return 0;
1236 }