#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fdt_ddb.c,v 1.2 2021/03/06 13:21:26 skrll Exp $");
#include <sys/param.h>
#include <libfdt.h>
#include <dev/fdt/fdt_ddb.h>
#include <dev/fdt/fdtvar.h>
#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;
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;
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);
}
}