xref: /netbsd-src/sys/dev/fdt/fdt_ddb.c (revision c901baed96cedf11c49b6661314a7ee295198df5)
1 /*	$NetBSD: fdt_ddb.c,v 1.2 2021/03/06 13:21:26 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.2 2021/03/06 13:21:26 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
fdt_isprint(const void * data,int len)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 	/* Count consecutive zeroes */
53 	int cz = 0;
54 	for (size_t j = 0; j < len; j++) {
55 		if (c[j] == '\0')
56 			cz++;
57 		else if (isprint(c[j]))
58 			cz = 0;
59 		else
60 			return false;
61 		if (cz > 1)
62 			return false;
63 	}
64 	return true;
65 }
66 
67 static void
68 fdt_print_properties(const void *fdt, int node,
69     void (*pr)(const char *, ...) __printflike(1, 2))
70 {
71 	int property;
72 
fdt_for_each_property_offset(property,fdt,node)73 	fdt_for_each_property_offset(property, fdt, node) {
74 		int len;
75 		const struct fdt_property *prop =
76 		    fdt_get_property_by_offset(fdt, property, &len);
77 		const char *name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
78 
79 		pr("    %s", name);
80 		if (len == 0) {
81 			pr("\n");
82 			continue;
83 		}
84 		if (fdt_isprint(prop->data, len)) {
85 			const uint8_t *c = (const uint8_t *)prop->data;
86 
87 			pr(" = \"");
88 			for (size_t j = 0; j < len; j++) {
89 				if (c[j] == '\0') {
90 					if (j + 1 != len)
91 						pr("\", \"");
92 				} else
93 					pr("%c", c[j]);
94 			}
95 			pr("\"\n");
96 			continue;
97 		}
98 		if ((len % 4) == 0) {
99 			const uint32_t *cell = (const uint32_t *)prop->data;
100 			size_t count = len / sizeof(uint32_t);
101 
102 			pr(" = <");
103 			for (size_t j = 0; j < count; j++) {
104 				pr("%#" PRIx32 "%s", fdt32_to_cpu(cell[j]),
105 				    (j != count - 1) ? " " : "");
106 			}
107 			pr(">\n");
108 		} else {
109 			const uint8_t *byte = (const uint8_t *)prop->data;
110 
111 			pr(" = [");
112 			for (size_t j = 0; j < len; j++) {
113 				pr("%02x%s", byte[j],
114 				   (j != len - 1) ? " " : "");
115 			}
116 			pr("]\n");
117 		}
118 	}
119 }
120 
121 
122 void
123 fdt_print(const void *addr, bool full,
124     void (*pr)(const char *, ...) __printflike(1, 2))
125 {
126 	const void *fdt = addr;
127 	const char *pname[FDT_MAX_DEPTH] = { NULL };
128 
129 	int error = fdt_check_header(fdt);
130 	if (error) {
131 		pr("Invalid FDT at %p\n", fdt);
132 		return;
133 	}
134 
135 	int depth = 0;
136 	for (int node = fdt_path_offset(fdt, "/");
137 	     node >= 0 && depth >= 0;
138 	     node = fdt_next_node(fdt, node, &depth)) {
139 		const char *name = fdt_get_name(fdt, node, NULL);
140 
141 		if (depth > FDT_MAX_DEPTH) {
142 			pr("max depth exceeded: %d\n", depth);
143 			continue;
144 		}
145 		pname[depth] = name;
146 		/*
147 		 * change conditional for when alternative root nodes
148 		 * can be specified
149 		 */
150 		if (depth == 0)
151 			pr("/");
152 		for (size_t i = 1; i <= depth; i++) {
153 			if (pname[i] == NULL)
154 				break;
155 			pr("/%s", pname[i]);
156 		}
157 		pr("\n");
158 		if (!full)
159 			continue;
160 		fdt_print_properties(fdt, node, pr);
161 	}
162 }
163