1 /* $NetBSD: fdt_ddb.c,v 1.1 2020/10/30 16:08:45 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nick Hudson 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: fdt_ddb.c,v 1.1 2020/10/30 16:08:45 skrll Exp $"); 35 36 #include <sys/param.h> 37 38 #include <libfdt.h> 39 #include <dev/fdt/fdt_ddb.h> 40 #include <dev/fdt/fdtvar.h> 41 42 #define FDT_MAX_DEPTH 16 43 44 static bool 45 fdt_isprint(const void *data, int len) 46 { 47 const uint8_t *c = (const uint8_t *)data; 48 49 if (len == 0) 50 return false; 51 52 for (size_t j = 0; j < len; j++) { 53 if (!(isprint(c[j]) || c[j] == '\0')) 54 return false; 55 } 56 return true; 57 } 58 59 static void 60 fdt_print_properties(const void *fdt, int node, 61 void (*pr)(const char *, ...) __printflike(1, 2)) 62 { 63 int property; 64 65 fdt_for_each_property_offset(property, fdt, node) { 66 int len; 67 const struct fdt_property *prop = 68 fdt_get_property_by_offset(fdt, property, &len); 69 const char *name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); 70 71 pr(" %s", name); 72 if (len == 0) { 73 pr("\n"); 74 continue; 75 } 76 if (fdt_isprint(prop->data, len)) { 77 const uint8_t *c = (const uint8_t *)prop->data; 78 79 pr(" = \""); 80 for (size_t j = 0; j < len; j++) { 81 if (c[j] == '\0') { 82 if (j + 1 != len) 83 pr("\", \""); 84 } else 85 pr("%c", c[j]); 86 } 87 pr("\"\n"); 88 continue; 89 } 90 if ((len % 4) == 0) { 91 const uint32_t *cell = (const uint32_t *)prop->data; 92 size_t count = len / sizeof(uint32_t); 93 94 pr(" = <"); 95 for (size_t j = 0; j < count; j++) { 96 pr("%#" PRIx32 "%s", fdt32_to_cpu(cell[j]), 97 (j != count - 1) ? " " : ""); 98 } 99 pr(">\n"); 100 } else { 101 const uint8_t *byte = (const uint8_t *)prop->data; 102 103 pr(" = ["); 104 for (size_t j = 0; j < len; j++) { 105 pr("%02x%s", byte[j], 106 (j != len - 1) ? " " : ""); 107 } 108 pr("]\n"); 109 } 110 } 111 } 112 113 114 void 115 fdt_print(const void *addr, bool full, 116 void (*pr)(const char *, ...) __printflike(1, 2)) 117 { 118 const void *fdt = addr; 119 const char *pname[FDT_MAX_DEPTH] = { NULL }; 120 121 int error = fdt_check_header(fdt); 122 if (error) { 123 pr("Invalid FDT at %p\n", fdt); 124 return; 125 } 126 127 int depth = 0; 128 for (int node = fdt_path_offset(fdt, "/"); 129 node >= 0 && depth >= 0; 130 node = fdt_next_node(fdt, node, &depth)) { 131 const char *name = fdt_get_name(fdt, node, NULL); 132 133 if (depth > FDT_MAX_DEPTH) { 134 pr("max depth exceeded: %d\n", depth); 135 continue; 136 } 137 pname[depth] = name; 138 /* 139 * change conditional for when alternative root nodes 140 * can be specified 141 */ 142 if (depth == 0) 143 pr("/"); 144 for (size_t i = 1; i <= depth; i++) { 145 if (pname[i] == NULL) 146 break; 147 pr("/%s", pname[i]); 148 } 149 pr("\n"); 150 if (!full) 151 continue; 152 fdt_print_properties(fdt, node, pr); 153 } 154 } 155