/* $NetBSD: fdt_ddb.c,v 1.2 2021/03/06 13:21:26 skrll Exp $ */ /*- * Copyright (c) 2020 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Nick Hudson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: fdt_ddb.c,v 1.2 2021/03/06 13:21:26 skrll Exp $"); #include #include #include #include #define FDT_MAX_DEPTH 16 static bool fdt_isprint(const void *data, int len) { const uint8_t *c = (const uint8_t *)data; if (len == 0) return false; /* Count consecutive zeroes */ int cz = 0; for (size_t j = 0; j < len; j++) { if (c[j] == '\0') cz++; else if (isprint(c[j])) cz = 0; else return false; if (cz > 1) return false; } return true; } static void fdt_print_properties(const void *fdt, int node, void (*pr)(const char *, ...) __printflike(1, 2)) { int property; fdt_for_each_property_offset(property, fdt, node) { int len; const struct fdt_property *prop = fdt_get_property_by_offset(fdt, property, &len); const char *name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); pr(" %s", name); if (len == 0) { pr("\n"); continue; } if (fdt_isprint(prop->data, len)) { const uint8_t *c = (const uint8_t *)prop->data; pr(" = \""); for (size_t j = 0; j < len; j++) { if (c[j] == '\0') { if (j + 1 != len) pr("\", \""); } else pr("%c", c[j]); } pr("\"\n"); continue; } if ((len % 4) == 0) { const uint32_t *cell = (const uint32_t *)prop->data; size_t count = len / sizeof(uint32_t); pr(" = <"); for (size_t j = 0; j < count; j++) { pr("%#" PRIx32 "%s", fdt32_to_cpu(cell[j]), (j != count - 1) ? " " : ""); } pr(">\n"); } else { const uint8_t *byte = (const uint8_t *)prop->data; pr(" = ["); for (size_t j = 0; j < len; j++) { pr("%02x%s", byte[j], (j != len - 1) ? " " : ""); } pr("]\n"); } } } void fdt_print(const void *addr, bool full, void (*pr)(const char *, ...) __printflike(1, 2)) { const void *fdt = addr; const char *pname[FDT_MAX_DEPTH] = { NULL }; int error = fdt_check_header(fdt); if (error) { pr("Invalid FDT at %p\n", fdt); return; } int depth = 0; for (int node = fdt_path_offset(fdt, "/"); node >= 0 && depth >= 0; node = fdt_next_node(fdt, node, &depth)) { const char *name = fdt_get_name(fdt, node, NULL); if (depth > FDT_MAX_DEPTH) { pr("max depth exceeded: %d\n", depth); continue; } pname[depth] = name; /* * change conditional for when alternative root nodes * can be specified */ if (depth == 0) pr("/"); for (size_t i = 1; i <= depth; i++) { if (pname[i] == NULL) break; pr("/%s", pname[i]); } pr("\n"); if (!full) continue; fdt_print_properties(fdt, node, pr); } }