// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2007 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com * Based on code written by: * Pantelis Antoniou and * Matthew McClintock */ #include #include #include #include #include #define MAX_LEVEL 32 /* how deeply nested we will go */ bool fdt_printable_str(const void *data, int len) { const char *s = data; const char *ss, *se; /* zero length is not */ if (!len) return false; /* must terminate with zero */ if (s[len - 1]) return false; se = s + len; while (s < se) { ss = s; while (s < se && *s && isprint((unsigned char)*s)) s++; /* not zero, or not done yet */ if (*s || s == ss) return false; s++; } return true; } /* * Print the property in the best format, a heuristic guess. Print as * a string, concatenated strings, a byte, word, double word, or (if all * else fails) it is printed as a stream of bytes. */ static void print_data(const void *data, int len) { int j; const char *env_max_dump; ulong max_dump = ULONG_MAX; /* no data, don't print */ if (len == 0) return; env_max_dump = env_get("fdt_max_dump"); if (env_max_dump) max_dump = hextoul(env_max_dump, NULL); /* * It is a string, but it may have multiple strings (embedded '\0's). */ if (fdt_printable_str(data, len)) { puts("\""); j = 0; while (j < len) { if (j > 0) puts("\", \""); puts(data); j += strlen(data) + 1; data += strlen(data) + 1; } puts("\""); return; } if ((len %4) == 0) { if (len > max_dump) printf("* 0x%p [0x%08x]", data, len); else { const __be32 *p; printf("<"); for (j = 0, p = data; j < len/4; j++) printf("0x%08x%s", fdt32_to_cpu(p[j]), j < (len/4 - 1) ? " " : ""); printf(">"); } } else { /* anything else... hexdump */ if (len > max_dump) printf("* 0x%p [0x%08x]", data, len); else { const u8 *s; printf("["); for (j = 0, s = data; j < len; j++) printf("%02x%s", s[j], j < len - 1 ? " " : ""); printf("]"); } } } /****************************************************************************/ /* * Recursively print (a portion of) the working_fdt. The depth parameter * determines how deeply nested the fdt is printed. */ int fdt_print(const char *pathp, char *prop, int depth) { static char tabs[MAX_LEVEL+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; const void *nodep; /* property node pointer */ int nodeoffset; /* node offset from libfdt */ int nextoffset; /* next node offset from libfdt */ uint32_t tag; /* tag */ int len; /* length of the property */ int level = 0; /* keep track of nesting level */ const struct fdt_property *fdt_prop; nodeoffset = fdt_path_offset (working_fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); return 1; } /* * The user passed in a property as well as node path. * Print only the given property and then return. */ if (prop) { nodep = fdt_getprop (working_fdt, nodeoffset, prop, &len); if (len == 0) { /* no property value */ printf("%s %s\n", pathp, prop); return 0; } else if (nodep && len > 0) { printf("%s = ", prop); print_data (nodep, len); printf("\n"); return 0; } else { printf ("libfdt fdt_getprop(): %s\n", fdt_strerror(len)); return 1; } } /* * The user passed in a node path and no property, * print the node and all subnodes. */ while(level >= 0) { tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset); switch(tag) { case FDT_BEGIN_NODE: pathp = fdt_get_name(working_fdt, nodeoffset, NULL); if (level <= depth) { if (pathp == NULL) pathp = "/* NULL pointer error */"; if (*pathp == '\0') pathp = "/"; /* root is nameless */ printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp); } level++; if (level >= MAX_LEVEL) { printf("Nested too deep, aborting.\n"); return 1; } break; case FDT_END_NODE: level--; if (level <= depth) printf("%s};\n", &tabs[MAX_LEVEL - level]); if (level == 0) { level = -1; /* exit the loop */ } break; case FDT_PROP: fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset, sizeof(*fdt_prop)); pathp = fdt_string(working_fdt, fdt32_to_cpu(fdt_prop->nameoff)); len = fdt32_to_cpu(fdt_prop->len); nodep = fdt_prop->data; if (len < 0) { printf ("libfdt fdt_getprop(): %s\n", fdt_strerror(len)); return 1; } else if (len == 0) { /* the property has no value */ if (level <= depth) printf("%s%s;\n", &tabs[MAX_LEVEL - level], pathp); } else { if (level <= depth) { printf("%s%s = ", &tabs[MAX_LEVEL - level], pathp); print_data (nodep, len); printf(";\n"); } } break; case FDT_NOP: printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]); break; case FDT_END: return 1; default: if (level <= depth) printf("Unknown tag 0x%08X\n", tag); return 1; } nodeoffset = nextoffset; } return 0; }