Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
0004  *
0005  * Portions from U-Boot cmd_fdt.c (C) Copyright 2007
0006  * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
0007  * Based on code written by:
0008  *   Pantelis Antoniou <pantelis.antoniou@gmail.com> and
0009  *   Matthew McClintock <msm@freescale.com>
0010  */
0011 
0012 #include <assert.h>
0013 #include <ctype.h>
0014 #include <getopt.h>
0015 #include <stdio.h>
0016 #include <stdlib.h>
0017 #include <string.h>
0018 
0019 #include <libfdt.h>
0020 
0021 #include "util.h"
0022 
0023 enum display_mode {
0024     MODE_SHOW_VALUE,    /* show values for node properties */
0025     MODE_LIST_PROPS,    /* list the properties for a node */
0026     MODE_LIST_SUBNODES, /* list the subnodes of a node */
0027 };
0028 
0029 /* Holds information which controls our output and options */
0030 struct display_info {
0031     int type;       /* data type (s/i/u/x or 0 for default) */
0032     int size;       /* data size (1/2/4) */
0033     enum display_mode mode; /* display mode that we are using */
0034     const char *default_val; /* default value if node/property not found */
0035 };
0036 
0037 static void report_error(const char *where, int err)
0038 {
0039     fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
0040 }
0041 
0042 /**
0043  * Displays data of a given length according to selected options
0044  *
0045  * If a specific data type is provided in disp, then this is used. Otherwise
0046  * we try to guess the data type / size from the contents.
0047  *
0048  * @param disp      Display information / options
0049  * @param data      Data to display
0050  * @param len       Maximum length of buffer
0051  * @return 0 if ok, -1 if data does not match format
0052  */
0053 static int show_data(struct display_info *disp, const char *data, int len)
0054 {
0055     int i, size;
0056     const uint8_t *p = (const uint8_t *)data;
0057     const char *s;
0058     int value;
0059     int is_string;
0060     char fmt[3];
0061 
0062     /* no data, don't print */
0063     if (len == 0)
0064         return 0;
0065 
0066     is_string = (disp->type) == 's' ||
0067         (!disp->type && util_is_printable_string(data, len));
0068     if (is_string) {
0069         if (data[len - 1] != '\0') {
0070             fprintf(stderr, "Unterminated string\n");
0071             return -1;
0072         }
0073         for (s = data; s - data < len; s += strlen(s) + 1) {
0074             if (s != data)
0075                 printf(" ");
0076             printf("%s", (const char *)s);
0077         }
0078         return 0;
0079     }
0080     size = disp->size;
0081     if (size == -1) {
0082         size = (len % 4) == 0 ? 4 : 1;
0083     } else if (len % size) {
0084         fprintf(stderr, "Property length must be a multiple of "
0085                 "selected data size\n");
0086         return -1;
0087     }
0088     fmt[0] = '%';
0089     fmt[1] = disp->type ? disp->type : 'd';
0090     fmt[2] = '\0';
0091     for (i = 0; i < len; i += size, p += size) {
0092         if (i)
0093             printf(" ");
0094         value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
0095             size == 2 ? (*p << 8) | p[1] : *p;
0096         printf(fmt, value);
0097     }
0098     return 0;
0099 }
0100 
0101 /**
0102  * List all properties in a node, one per line.
0103  *
0104  * @param blob      FDT blob
0105  * @param node      Node to display
0106  * @return 0 if ok, or FDT_ERR... if not.
0107  */
0108 static int list_properties(const void *blob, int node)
0109 {
0110     const struct fdt_property *data;
0111     const char *name;
0112     int prop;
0113 
0114     prop = fdt_first_property_offset(blob, node);
0115     do {
0116         /* Stop silently when there are no more properties */
0117         if (prop < 0)
0118             return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
0119         data = fdt_get_property_by_offset(blob, prop, NULL);
0120         name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
0121         if (name)
0122             puts(name);
0123         prop = fdt_next_property_offset(blob, prop);
0124     } while (1);
0125 }
0126 
0127 #define MAX_LEVEL   32      /* how deeply nested we will go */
0128 
0129 /**
0130  * List all subnodes in a node, one per line
0131  *
0132  * @param blob      FDT blob
0133  * @param node      Node to display
0134  * @return 0 if ok, or FDT_ERR... if not.
0135  */
0136 static int list_subnodes(const void *blob, int node)
0137 {
0138     int nextoffset;     /* next node offset from libfdt */
0139     uint32_t tag;       /* current tag */
0140     int level = 0;      /* keep track of nesting level */
0141     const char *pathp;
0142     int depth = 1;      /* the assumed depth of this node */
0143 
0144     while (level >= 0) {
0145         tag = fdt_next_tag(blob, node, &nextoffset);
0146         switch (tag) {
0147         case FDT_BEGIN_NODE:
0148             pathp = fdt_get_name(blob, node, NULL);
0149             if (level <= depth) {
0150                 if (pathp == NULL)
0151                     pathp = "/* NULL pointer error */";
0152                 if (*pathp == '\0')
0153                     pathp = "/";    /* root is nameless */
0154                 if (level == 1)
0155                     puts(pathp);
0156             }
0157             level++;
0158             if (level >= MAX_LEVEL) {
0159                 printf("Nested too deep, aborting.\n");
0160                 return 1;
0161             }
0162             break;
0163         case FDT_END_NODE:
0164             level--;
0165             if (level == 0)
0166                 level = -1;     /* exit the loop */
0167             break;
0168         case FDT_END:
0169             return 1;
0170         case FDT_PROP:
0171             break;
0172         default:
0173             if (level <= depth)
0174                 printf("Unknown tag 0x%08X\n", tag);
0175             return 1;
0176         }
0177         node = nextoffset;
0178     }
0179     return 0;
0180 }
0181 
0182 /**
0183  * Show the data for a given node (and perhaps property) according to the
0184  * display option provided.
0185  *
0186  * @param blob      FDT blob
0187  * @param disp      Display information / options
0188  * @param node      Node to display
0189  * @param property  Name of property to display, or NULL if none
0190  * @return 0 if ok, -ve on error
0191  */
0192 static int show_data_for_item(const void *blob, struct display_info *disp,
0193         int node, const char *property)
0194 {
0195     const void *value = NULL;
0196     int len, err = 0;
0197 
0198     switch (disp->mode) {
0199     case MODE_LIST_PROPS:
0200         err = list_properties(blob, node);
0201         break;
0202 
0203     case MODE_LIST_SUBNODES:
0204         err = list_subnodes(blob, node);
0205         break;
0206 
0207     default:
0208         assert(property);
0209         value = fdt_getprop(blob, node, property, &len);
0210         if (value) {
0211             if (show_data(disp, value, len))
0212                 err = -1;
0213             else
0214                 printf("\n");
0215         } else if (disp->default_val) {
0216             puts(disp->default_val);
0217         } else {
0218             report_error(property, len);
0219             err = -1;
0220         }
0221         break;
0222     }
0223 
0224     return err;
0225 }
0226 
0227 /**
0228  * Run the main fdtget operation, given a filename and valid arguments
0229  *
0230  * @param disp      Display information / options
0231  * @param filename  Filename of blob file
0232  * @param arg       List of arguments to process
0233  * @param arg_count Number of arguments
0234  * @param return 0 if ok, -ve on error
0235  */
0236 static int do_fdtget(struct display_info *disp, const char *filename,
0237              char **arg, int arg_count, int args_per_step)
0238 {
0239     char *blob;
0240     const char *prop;
0241     int i, node;
0242 
0243     blob = utilfdt_read(filename);
0244     if (!blob)
0245         return -1;
0246 
0247     for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
0248         node = fdt_path_offset(blob, arg[i]);
0249         if (node < 0) {
0250             if (disp->default_val) {
0251                 puts(disp->default_val);
0252                 continue;
0253             } else {
0254                 report_error(arg[i], node);
0255                 return -1;
0256             }
0257         }
0258         prop = args_per_step == 1 ? NULL : arg[i + 1];
0259 
0260         if (show_data_for_item(blob, disp, node, prop))
0261             return -1;
0262     }
0263     return 0;
0264 }
0265 
0266 static const char *usage_msg =
0267     "fdtget - read values from device tree\n"
0268     "\n"
0269     "Each value is printed on a new line.\n\n"
0270     "Usage:\n"
0271     "   fdtget <options> <dt file> [<node> <property>]...\n"
0272     "   fdtget -p <options> <dt file> [<node> ]...\n"
0273     "Options:\n"
0274     "\t-t <type>\tType of data\n"
0275     "\t-p\t\tList properties for each node\n"
0276     "\t-l\t\tList subnodes for each node\n"
0277     "\t-d\t\tDefault value to display when the property is "
0278             "missing\n"
0279     "\t-h\t\tPrint this help\n\n"
0280     USAGE_TYPE_MSG;
0281 
0282 static void usage(const char *msg)
0283 {
0284     if (msg)
0285         fprintf(stderr, "Error: %s\n\n", msg);
0286 
0287     fprintf(stderr, "%s", usage_msg);
0288     exit(2);
0289 }
0290 
0291 int main(int argc, char *argv[])
0292 {
0293     char *filename = NULL;
0294     struct display_info disp;
0295     int args_per_step = 2;
0296 
0297     /* set defaults */
0298     memset(&disp, '\0', sizeof(disp));
0299     disp.size = -1;
0300     disp.mode = MODE_SHOW_VALUE;
0301     for (;;) {
0302         int c = getopt(argc, argv, "d:hlpt:");
0303         if (c == -1)
0304             break;
0305 
0306         switch (c) {
0307         case 'h':
0308         case '?':
0309             usage(NULL);
0310 
0311         case 't':
0312             if (utilfdt_decode_type(optarg, &disp.type,
0313                     &disp.size))
0314                 usage("Invalid type string");
0315             break;
0316 
0317         case 'p':
0318             disp.mode = MODE_LIST_PROPS;
0319             args_per_step = 1;
0320             break;
0321 
0322         case 'l':
0323             disp.mode = MODE_LIST_SUBNODES;
0324             args_per_step = 1;
0325             break;
0326 
0327         case 'd':
0328             disp.default_val = optarg;
0329             break;
0330         }
0331     }
0332 
0333     if (optind < argc)
0334         filename = argv[optind++];
0335     if (!filename)
0336         usage("Missing filename");
0337 
0338     argv += optind;
0339     argc -= optind;
0340 
0341     /* Allow no arguments, and silently succeed */
0342     if (!argc)
0343         return 0;
0344 
0345     /* Check for node, property arguments */
0346     if (args_per_step == 2 && (argc % 2))
0347         usage("Must have an even number of arguments");
0348 
0349     if (do_fdtget(&disp, filename, argv, argc, args_per_step))
0350         return 1;
0351     return 0;
0352 }