linux/scripts/dtc/fdtget.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
   4 *
   5 * Portions from U-Boot cmd_fdt.c (C) Copyright 2007
   6 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
   7 * Based on code written by:
   8 *   Pantelis Antoniou <pantelis.antoniou@gmail.com> and
   9 *   Matthew McClintock <msm@freescale.com>
  10 */
  11
  12#include <assert.h>
  13#include <ctype.h>
  14#include <getopt.h>
  15#include <stdio.h>
  16#include <stdlib.h>
  17#include <string.h>
  18
  19#include <libfdt.h>
  20
  21#include "util.h"
  22
  23enum display_mode {
  24        MODE_SHOW_VALUE,        /* show values for node properties */
  25        MODE_LIST_PROPS,        /* list the properties for a node */
  26        MODE_LIST_SUBNODES,     /* list the subnodes of a node */
  27};
  28
  29/* Holds information which controls our output and options */
  30struct display_info {
  31        int type;               /* data type (s/i/u/x or 0 for default) */
  32        int size;               /* data size (1/2/4) */
  33        enum display_mode mode; /* display mode that we are using */
  34        const char *default_val; /* default value if node/property not found */
  35};
  36
  37static void report_error(const char *where, int err)
  38{
  39        fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
  40}
  41
  42/**
  43 * Displays data of a given length according to selected options
  44 *
  45 * If a specific data type is provided in disp, then this is used. Otherwise
  46 * we try to guess the data type / size from the contents.
  47 *
  48 * @param disp          Display information / options
  49 * @param data          Data to display
  50 * @param len           Maximum length of buffer
  51 * @return 0 if ok, -1 if data does not match format
  52 */
  53static int show_data(struct display_info *disp, const char *data, int len)
  54{
  55        int i, size;
  56        const uint8_t *p = (const uint8_t *)data;
  57        const char *s;
  58        int value;
  59        int is_string;
  60        char fmt[3];
  61
  62        /* no data, don't print */
  63        if (len == 0)
  64                return 0;
  65
  66        is_string = (disp->type) == 's' ||
  67                (!disp->type && util_is_printable_string(data, len));
  68        if (is_string) {
  69                if (data[len - 1] != '\0') {
  70                        fprintf(stderr, "Unterminated string\n");
  71                        return -1;
  72                }
  73                for (s = data; s - data < len; s += strlen(s) + 1) {
  74                        if (s != data)
  75                                printf(" ");
  76                        printf("%s", (const char *)s);
  77                }
  78                return 0;
  79        }
  80        size = disp->size;
  81        if (size == -1) {
  82                size = (len % 4) == 0 ? 4 : 1;
  83        } else if (len % size) {
  84                fprintf(stderr, "Property length must be a multiple of "
  85                                "selected data size\n");
  86                return -1;
  87        }
  88        fmt[0] = '%';
  89        fmt[1] = disp->type ? disp->type : 'd';
  90        fmt[2] = '\0';
  91        for (i = 0; i < len; i += size, p += size) {
  92                if (i)
  93                        printf(" ");
  94                value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
  95                        size == 2 ? (*p << 8) | p[1] : *p;
  96                printf(fmt, value);
  97        }
  98        return 0;
  99}
 100
 101/**
 102 * List all properties in a node, one per line.
 103 *
 104 * @param blob          FDT blob
 105 * @param node          Node to display
 106 * @return 0 if ok, or FDT_ERR... if not.
 107 */
 108static int list_properties(const void *blob, int node)
 109{
 110        const struct fdt_property *data;
 111        const char *name;
 112        int prop;
 113
 114        prop = fdt_first_property_offset(blob, node);
 115        do {
 116                /* Stop silently when there are no more properties */
 117                if (prop < 0)
 118                        return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
 119                data = fdt_get_property_by_offset(blob, prop, NULL);
 120                name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
 121                if (name)
 122                        puts(name);
 123                prop = fdt_next_property_offset(blob, prop);
 124        } while (1);
 125}
 126
 127#define MAX_LEVEL       32              /* how deeply nested we will go */
 128
 129/**
 130 * List all subnodes in a node, one per line
 131 *
 132 * @param blob          FDT blob
 133 * @param node          Node to display
 134 * @return 0 if ok, or FDT_ERR... if not.
 135 */
 136static int list_subnodes(const void *blob, int node)
 137{
 138        int nextoffset;         /* next node offset from libfdt */
 139        uint32_t tag;           /* current tag */
 140        int level = 0;          /* keep track of nesting level */
 141        const char *pathp;
 142        int depth = 1;          /* the assumed depth of this node */
 143
 144        while (level >= 0) {
 145                tag = fdt_next_tag(blob, node, &nextoffset);
 146                switch (tag) {
 147                case FDT_BEGIN_NODE:
 148                        pathp = fdt_get_name(blob, node, NULL);
 149                        if (level <= depth) {
 150                                if (pathp == NULL)
 151                                        pathp = "/* NULL pointer error */";
 152                                if (*pathp == '\0')
 153                                        pathp = "/";    /* root is nameless */
 154                                if (level == 1)
 155                                        puts(pathp);
 156                        }
 157                        level++;
 158                        if (level >= MAX_LEVEL) {
 159                                printf("Nested too deep, aborting.\n");
 160                                return 1;
 161                        }
 162                        break;
 163                case FDT_END_NODE:
 164                        level--;
 165                        if (level == 0)
 166                                level = -1;             /* exit the loop */
 167                        break;
 168                case FDT_END:
 169                        return 1;
 170                case FDT_PROP:
 171                        break;
 172                default:
 173                        if (level <= depth)
 174                                printf("Unknown tag 0x%08X\n", tag);
 175                        return 1;
 176                }
 177                node = nextoffset;
 178        }
 179        return 0;
 180}
 181
 182/**
 183 * Show the data for a given node (and perhaps property) according to the
 184 * display option provided.
 185 *
 186 * @param blob          FDT blob
 187 * @param disp          Display information / options
 188 * @param node          Node to display
 189 * @param property      Name of property to display, or NULL if none
 190 * @return 0 if ok, -ve on error
 191 */
 192static int show_data_for_item(const void *blob, struct display_info *disp,
 193                int node, const char *property)
 194{
 195        const void *value = NULL;
 196        int len, err = 0;
 197
 198        switch (disp->mode) {
 199        case MODE_LIST_PROPS:
 200                err = list_properties(blob, node);
 201                break;
 202
 203        case MODE_LIST_SUBNODES:
 204                err = list_subnodes(blob, node);
 205                break;
 206
 207        default:
 208                assert(property);
 209                value = fdt_getprop(blob, node, property, &len);
 210                if (value) {
 211                        if (show_data(disp, value, len))
 212                                err = -1;
 213                        else
 214                                printf("\n");
 215                } else if (disp->default_val) {
 216                        puts(disp->default_val);
 217                } else {
 218                        report_error(property, len);
 219                        err = -1;
 220                }
 221                break;
 222        }
 223
 224        return err;
 225}
 226
 227/**
 228 * Run the main fdtget operation, given a filename and valid arguments
 229 *
 230 * @param disp          Display information / options
 231 * @param filename      Filename of blob file
 232 * @param arg           List of arguments to process
 233 * @param arg_count     Number of arguments
 234 * @param return 0 if ok, -ve on error
 235 */
 236static int do_fdtget(struct display_info *disp, const char *filename,
 237                     char **arg, int arg_count, int args_per_step)
 238{
 239        char *blob;
 240        const char *prop;
 241        int i, node;
 242
 243        blob = utilfdt_read(filename);
 244        if (!blob)
 245                return -1;
 246
 247        for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
 248                node = fdt_path_offset(blob, arg[i]);
 249                if (node < 0) {
 250                        if (disp->default_val) {
 251                                puts(disp->default_val);
 252                                continue;
 253                        } else {
 254                                report_error(arg[i], node);
 255                                return -1;
 256                        }
 257                }
 258                prop = args_per_step == 1 ? NULL : arg[i + 1];
 259
 260                if (show_data_for_item(blob, disp, node, prop))
 261                        return -1;
 262        }
 263        return 0;
 264}
 265
 266static const char *usage_msg =
 267        "fdtget - read values from device tree\n"
 268        "\n"
 269        "Each value is printed on a new line.\n\n"
 270        "Usage:\n"
 271        "       fdtget <options> <dt file> [<node> <property>]...\n"
 272        "       fdtget -p <options> <dt file> [<node> ]...\n"
 273        "Options:\n"
 274        "\t-t <type>\tType of data\n"
 275        "\t-p\t\tList properties for each node\n"
 276        "\t-l\t\tList subnodes for each node\n"
 277        "\t-d\t\tDefault value to display when the property is "
 278                        "missing\n"
 279        "\t-h\t\tPrint this help\n\n"
 280        USAGE_TYPE_MSG;
 281
 282static void usage(const char *msg)
 283{
 284        if (msg)
 285                fprintf(stderr, "Error: %s\n\n", msg);
 286
 287        fprintf(stderr, "%s", usage_msg);
 288        exit(2);
 289}
 290
 291int main(int argc, char *argv[])
 292{
 293        char *filename = NULL;
 294        struct display_info disp;
 295        int args_per_step = 2;
 296
 297        /* set defaults */
 298        memset(&disp, '\0', sizeof(disp));
 299        disp.size = -1;
 300        disp.mode = MODE_SHOW_VALUE;
 301        for (;;) {
 302                int c = getopt(argc, argv, "d:hlpt:");
 303                if (c == -1)
 304                        break;
 305
 306                switch (c) {
 307                case 'h':
 308                case '?':
 309                        usage(NULL);
 310
 311                case 't':
 312                        if (utilfdt_decode_type(optarg, &disp.type,
 313                                        &disp.size))
 314                                usage("Invalid type string");
 315                        break;
 316
 317                case 'p':
 318                        disp.mode = MODE_LIST_PROPS;
 319                        args_per_step = 1;
 320                        break;
 321
 322                case 'l':
 323                        disp.mode = MODE_LIST_SUBNODES;
 324                        args_per_step = 1;
 325                        break;
 326
 327                case 'd':
 328                        disp.default_val = optarg;
 329                        break;
 330                }
 331        }
 332
 333        if (optind < argc)
 334                filename = argv[optind++];
 335        if (!filename)
 336                usage("Missing filename");
 337
 338        argv += optind;
 339        argc -= optind;
 340
 341        /* Allow no arguments, and silently succeed */
 342        if (!argc)
 343                return 0;
 344
 345        /* Check for node, property arguments */
 346        if (args_per_step == 2 && (argc % 2))
 347                usage("Must have an even number of arguments");
 348
 349        if (do_fdtget(&disp, filename, argv, argc, args_per_step))
 350                return 1;
 351        return 0;
 352}
 353