summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-05-17 21:26:33 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-05-17 21:26:33 +0000
commit116b6fec4cd7bb90f26b8168f0faabdfe0a5e7e7 (patch)
tree5ee632f7805c0a99c02d8405d58ab718b38dd4aa /sys
parente51d0f8eaab5b95a9c2ba99f5bfa0f7445b3f410 (diff)
Add support for passing an FDT. The bootloader will update the "bootargs"
property of the "/chosen" node to pass arguments to the kernel.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/armv7/stand/efiboot/Makefile10
-rw-r--r--sys/arch/armv7/stand/efiboot/efiboot.c39
-rw-r--r--sys/arch/armv7/stand/efiboot/efiboot.h18
-rw-r--r--sys/arch/armv7/stand/efiboot/exec.c42
-rw-r--r--sys/arch/armv7/stand/efiboot/fdt.c553
-rw-r--r--sys/arch/armv7/stand/efiboot/fdt.h67
6 files changed, 694 insertions, 35 deletions
diff --git a/sys/arch/armv7/stand/efiboot/Makefile b/sys/arch/armv7/stand/efiboot/Makefile
index eb537e7bff5..4c1378a6e8e 100644
--- a/sys/arch/armv7/stand/efiboot/Makefile
+++ b/sys/arch/armv7/stand/efiboot/Makefile
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.1 2016/05/14 17:55:15 kettenis Exp $
+# $OpenBSD: Makefile,v 1.2 2016/05/17 21:26:32 kettenis Exp $
PROG= BOOTARM.EFI
NOMAN= #
OBJFMT= binary
-SRCS= start.S self_reloc.c efiboot.c conf.c exec.c efidev.c
+SRCS= start.S self_reloc.c efiboot.c conf.c exec.c efidev.c fdt.c
S= ${.CURDIR}/../../../..
EFIDIR= ${S}/stand/efi
@@ -17,9 +17,9 @@ LDFLAGS+=-nostdlib -T ${.CURDIR}/ldscript.arm -Bsymbolic -shared
SRCS+= boot.c cmd.c vars.c
.PATH: ${S}/lib/libsa
-SRCS+= alloc.c ctime.c exit.c getchar.c memcmp.o memcpy.o memset.c printf.c \
- putchar.c snprintf.c strchr.c strcmp.c strerror.c strncmp.c strncpy.c \
- strtol.c
+SRCS+= alloc.c ctime.c exit.c getchar.c memcmp.o memcpy.o memmove.c memset.c \
+ printf.c putchar.c snprintf.c strchr.c strcmp.c strerror.c strncmp.c \
+ strncpy.c strtol.c
SRCS+= close.c closeall.c cons.c cread.c dev.c disklabel.c dkcksum.c fstat.c \
lseek.c open.c read.c readdir.c stat.c
SRCS+= loadfile.c
diff --git a/sys/arch/armv7/stand/efiboot/efiboot.c b/sys/arch/armv7/stand/efiboot/efiboot.c
index 8f7aae61d91..822460e1e21 100644
--- a/sys/arch/armv7/stand/efiboot/efiboot.c
+++ b/sys/arch/armv7/stand/efiboot/efiboot.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: efiboot.c,v 1.4 2016/05/14 21:22:56 kettenis Exp $ */
+/* $OpenBSD: efiboot.c,v 1.5 2016/05/17 21:26:32 kettenis Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -28,6 +28,7 @@
#include <eficonsctl.h>
#include "eficall.h"
+#include "fdt.h"
#include "libsa.h"
EFI_SYSTEM_TABLE *ST;
@@ -215,6 +216,42 @@ next:
free(handles, sz);
}
+static EFI_GUID fdt_guid = FDT_TABLE_GUID;
+
+#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
+
+void *
+efi_makebootargs(char *bootargs)
+{
+ void *fdt = NULL;
+ char *dummy;
+ void *node;
+ size_t len;
+ int i;
+
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
+ if (efi_guidcmp(&fdt_guid,
+ &ST->ConfigurationTable[i].VendorGuid) == 0)
+ fdt = ST->ConfigurationTable[i].VendorTable;
+ }
+
+ if (!fdt_init(fdt))
+ return;
+
+ node = fdt_find_node("/chosen");
+ if (!node)
+ return;
+
+ len = strlen(bootargs) + 1;
+ if (fdt_node_property(node, "bootargs", &bootargs))
+ fdt_node_set_property(node, "bootargs", bootargs, len);
+ else
+ fdt_node_add_property(node, "bootargs", bootargs, len);
+ fdt_finalize();
+
+ return fdt;
+}
+
u_long efi_loadaddr;
void
diff --git a/sys/arch/armv7/stand/efiboot/efiboot.h b/sys/arch/armv7/stand/efiboot/efiboot.h
index 3683af505ee..9d9d7bf3b8f 100644
--- a/sys/arch/armv7/stand/efiboot/efiboot.h
+++ b/sys/arch/armv7/stand/efiboot/efiboot.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: efiboot.h,v 1.1 2016/05/14 17:55:15 kettenis Exp $ */
+/* $OpenBSD: efiboot.h,v 1.2 2016/05/17 21:26:32 kettenis Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -16,12 +16,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-void efi_cleanup(void);
-void efi_cons_probe (struct consdev *);
-void efi_memprobe (void);
-void efi_hardprobe (void);
-void efi_diskprobe (void);
-void efi_cons_init (struct consdev *);
-int efi_cons_getc (dev_t);
-void efi_cons_putc (dev_t, int);
-int efi_cons_getshifts(dev_t dev);
+void efi_cleanup(void);
+void efi_diskprobe(void);
+void *efi_makebootargs(char *);
+void efi_cons_probe(struct consdev *);
+void efi_cons_init(struct consdev *);
+int efi_cons_getc(dev_t);
+void efi_cons_putc(dev_t, int);
diff --git a/sys/arch/armv7/stand/efiboot/exec.c b/sys/arch/armv7/stand/efiboot/exec.c
index 5abf40c6e3c..1d16b271e8d 100644
--- a/sys/arch/armv7/stand/efiboot/exec.c
+++ b/sys/arch/armv7/stand/efiboot/exec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec.c,v 1.4 2016/05/14 21:22:56 kettenis Exp $ */
+/* $OpenBSD: exec.c,v 1.5 2016/05/17 21:26:32 kettenis Exp $ */
/*
* Copyright (c) 2006, 2016 Mark Kettenis
@@ -17,20 +17,19 @@
*/
#include <sys/param.h>
+#include <sys/reboot.h>
+#include <machine/bootconfig.h>
+#include <dev/cons.h>
#include <lib/libsa/loadfile.h>
-
-#ifdef BOOT_ELF
#include <sys/exec_elf.h>
-#endif
-#include <sys/reboot.h>
+#include <efi.h>
#include <stand/boot/cmd.h>
-#include <machine/bootconfig.h>
-#include <efi.h>
+#include "efiboot.h"
-extern EFI_BOOT_SERVICES *BS;
+extern void *fdt;
typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn));
@@ -86,6 +85,7 @@ run_loadfile(u_long *marks, int howto)
u_long offset = 0;
char args[256];
char *cp;
+ void *fdt;
int i;
/*
@@ -121,20 +121,24 @@ run_loadfile(u_long *marks, int howto)
else
*++cp = 0;
- tags[0].hdr.tag = ATAG_MEM;
- tags[0].hdr.size = sizeof(struct uboot_tag) / sizeof(uint32_t);
- tags[0].u.mem.start = 0x10000000;
- tags[0].u.mem.size = 0x80000000;
- tags[1].hdr.tag = ATAG_CMDLINE;
- tags[1].hdr.size = sizeof(struct uboot_tag) / sizeof(uint32_t);
- strlcpy(tags[1].u.cmdline.cmdline, args,
- sizeof(tags[1].u.cmdline.cmdline));
-
- memcpy((void *)0x10000000, tags, sizeof(tags));
+ fdt = efi_makebootargs(args);
+ if (fdt == 0) {
+ tags[0].hdr.tag = ATAG_MEM;
+ tags[0].hdr.size = sizeof(struct uboot_tag) / sizeof(uint32_t);
+ tags[0].u.mem.start = 0x10000000;
+ tags[0].u.mem.size = 0x80000000;
+ tags[1].hdr.tag = ATAG_CMDLINE;
+ tags[1].hdr.size = sizeof(struct uboot_tag) / sizeof(uint32_t);
+ strlcpy(tags[1].u.cmdline.cmdline, args,
+ sizeof(tags[1].u.cmdline.cmdline));
+
+ memcpy((void *)0x10000000, tags, sizeof(tags));
+ fdt = (void *)0x10000000;
+ }
efi_cleanup();
- (*(startfuncp)(marks[MARK_ENTRY]))(NULL, (void *)4821, (void *)0x10000000);
+ (*(startfuncp)(marks[MARK_ENTRY]))(NULL, (void *)4821, fdt);
/* NOTREACHED */
}
diff --git a/sys/arch/armv7/stand/efiboot/fdt.c b/sys/arch/armv7/stand/efiboot/fdt.c
new file mode 100644
index 00000000000..a0ceca48a66
--- /dev/null
+++ b/sys/arch/armv7/stand/efiboot/fdt.c
@@ -0,0 +1,553 @@
+/* $OpenBSD: fdt.c,v 1.1 2016/05/17 21:26:32 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net>
+ * Copyright (c) 2009, 2016 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include "fdt.h"
+
+unsigned int fdt_check_head(void *);
+char *fdt_get_str(uint32_t);
+void *skip_property(uint32_t *);
+void *skip_props(uint32_t *);
+void *skip_node_name(uint32_t *);
+void *skip_node(void *);
+void *fdt_parent_node_recurse(void *, void *);
+
+static int tree_inited = 0;
+static struct fdt tree;
+
+unsigned int
+fdt_check_head(void *fdt)
+{
+ struct fdt_head *fh;
+ uint32_t *ptr;
+
+ fh = fdt;
+ ptr = (uint32_t *)fdt;
+
+ if (betoh32(fh->fh_magic) != FDT_MAGIC)
+ return 0;
+
+ if (betoh32(fh->fh_version) > FDT_CODE_VERSION)
+ return 0;
+
+ if (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4))) !=
+ FDT_NODE_BEGIN)
+ return 0;
+
+ /* check for end signature on version 17 blob */
+ if ((betoh32(fh->fh_version) >= 17) &&
+ (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4) +
+ (betoh32(fh->fh_struct_size) / 4) - 1)) != FDT_END))
+ return 0;
+
+ return betoh32(fh->fh_version);
+}
+
+/*
+ * Initializes internal structures of module.
+ * Has to be called once.
+ */
+int
+fdt_init(void *fdt)
+{
+ int version;
+
+ memset(&tree, 0, sizeof(struct fdt));
+ tree_inited = 0;
+
+ if (!fdt)
+ return 0;
+
+ if (!(version = fdt_check_head(fdt)))
+ return 0;
+
+ tree.header = (struct fdt_head *)fdt;
+ tree.tree = (char *)fdt + betoh32(tree.header->fh_struct_off);
+ tree.strings = (char *)fdt + betoh32(tree.header->fh_strings_off);
+ tree.memory = (char *)fdt + betoh32(tree.header->fh_reserve_off);
+ tree.end = (char *)fdt + betoh32(tree.header->fh_size);
+ tree.version = version;
+ tree.strings_size = betoh32(tree.header->fh_strings_size);
+ if (tree.version >= 17)
+ tree.struct_size = betoh32(tree.header->fh_struct_size);
+ tree_inited = 1;
+
+ return version;
+}
+
+void
+fdt_finalize(void)
+{
+ char *start = (char *)tree.header;
+
+ tree.header->fh_size = htobe32(tree.end - start);
+ tree.header->fh_struct_off = htobe32(tree.tree - start);
+ tree.header->fh_strings_off = htobe32(tree.strings - start);
+ tree.header->fh_reserve_off = htobe32(tree.memory - start);
+ tree.header->fh_strings_size = htobe32(tree.strings_size);
+ if (tree.version >= 17)
+ tree.header->fh_struct_size = htobe32(tree.struct_size);
+}
+
+/*
+ * Return the size of the FDT.
+ */
+size_t
+fdt_get_size(void *fdt)
+{
+ if (!fdt)
+ return 0;
+
+ if (!fdt_check_head(fdt))
+ return 0;
+
+ return betoh32(((struct fdt_head *)fdt)->fh_size);
+}
+
+/*
+ * Retrieve string pointer from strings table.
+ */
+char *
+fdt_get_str(uint32_t num)
+{
+ if (num > tree.strings_size)
+ return NULL;
+ return (tree.strings) ? (tree.strings + num) : NULL;
+}
+
+int
+fdt_add_str(char *name)
+{
+ size_t len = roundup(strlen(name) + 1, sizeof(uint32_t));
+ char *end = tree.strings + tree.strings_size;
+
+ memmove(end + len, end, tree.end - end);
+ tree.strings_size += len;
+ if (tree.tree > tree.strings)
+ tree.tree += len;
+ if (tree.memory > tree.strings)
+ tree.memory += len;
+ tree.end += len;
+ memcpy(end, name, len);
+
+ return (end - tree.strings);
+}
+
+/*
+ * Utility functions for skipping parts of tree.
+ */
+void *
+skip_property(uint32_t *ptr)
+{
+ uint32_t size;
+
+ size = betoh32(*(ptr + 1));
+ /* move forward by magic + size + nameid + rounded up property size */
+ ptr += 3 + roundup(size, sizeof(uint32_t)) / sizeof(uint32_t);
+
+ return ptr;
+}
+
+void *
+skip_props(uint32_t *ptr)
+{
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ ptr = skip_property(ptr);
+ }
+ return ptr;
+}
+
+void *
+skip_node_name(uint32_t *ptr)
+{
+ /* skip name, aligned to 4 bytes, this is NULL term., so must add 1 */
+ return ptr + roundup(strlen((char *)ptr) + 1,
+ sizeof(uint32_t)) / sizeof(uint32_t);
+}
+
+/*
+ * Retrieves node property, the returned pointer is inside the fdt tree,
+ * so we should not modify content pointed by it directly.
+ */
+int
+fdt_node_property(void *node, char *name, char **out)
+{
+ uint32_t *ptr;
+ uint32_t nameid;
+ char *tmp;
+
+ if (!tree_inited)
+ return 0;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
+ tmp = fdt_get_str(nameid);
+ if (!strcmp(name, tmp)) {
+ *out = (char *)(ptr + 3); /* beginning of the value */
+ return betoh32(*(ptr + 1)); /* size of value */
+ }
+ ptr = skip_property(ptr);
+ }
+ return 0;
+}
+
+int
+fdt_node_set_property(void *node, char *name, char *data, int len)
+{
+ uint32_t *ptr, *next;
+ uint32_t nameid;
+ uint32_t curlen;
+ size_t delta;
+ char *tmp;
+
+ if (!tree_inited)
+ return 0;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
+ tmp = fdt_get_str(nameid);
+ next = skip_property(ptr);
+ if (!strcmp(name, tmp)) {
+ curlen = betoh32(*(ptr + 1));
+ delta = roundup(len, sizeof(uint32_t)) -
+ roundup(curlen, sizeof(uint32_t));
+ memmove((char *)next + delta, next,
+ tree.end - (char *)next);
+ tree.struct_size += delta;
+ if (tree.strings > tree.tree)
+ tree.strings += delta;
+ if (tree.memory > tree.tree)
+ tree.memory += delta;
+ tree.end += delta;
+ *(ptr + 1) = htobe32(len);
+ memcpy(ptr + 3, data, len);
+ return;
+ }
+ ptr = next;
+ }
+ return 0;
+}
+
+int
+fdt_node_add_property(void *node, char *name, char *data, int len)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return 0;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ memmove(ptr + 3, ptr, tree.end - (char *)ptr);
+ tree.struct_size += 3 * sizeof(uint32_t);
+ if (tree.strings > tree.tree)
+ tree.strings += 3 * sizeof(uint32_t);
+ if (tree.memory > tree.tree)
+ tree.memory += 3 * sizeof(uint32_t);
+ tree.end += 3 * sizeof(uint32_t);
+ *ptr++ = htobe32(FDT_PROPERTY);
+ *ptr++ = htobe32(0);
+ *ptr++ = htobe32(fdt_add_str(name));
+
+ return fdt_node_set_property(node, name, data, len);
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node,
+ * returns pointer to next node, no matter if it exists or not.
+ */
+void *
+skip_node(void *node)
+{
+ uint32_t *ptr = node;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+
+ /* skip children */
+ while (betoh32(*ptr) == FDT_NODE_BEGIN)
+ ptr = skip_node(ptr);
+
+ return (ptr + 1);
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node,
+ * returns pointer to next node if exists, otherwise returns NULL.
+ * If passed 0 will return first node of the tree (root).
+ */
+void *
+fdt_next_node(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (node == NULL) {
+ ptr = (uint32_t *)tree.tree;
+ return (betoh32(*ptr) == FDT_NODE_BEGIN) ? ptr : NULL;
+ }
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+
+ /* skip children */
+ while (betoh32(*ptr) == FDT_NODE_BEGIN)
+ ptr = skip_node(ptr);
+
+ if (betoh32(*ptr) != FDT_NODE_END)
+ return NULL;
+
+ if (betoh32(*(ptr + 1)) != FDT_NODE_BEGIN)
+ return NULL;
+
+ return (ptr + 1);
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node
+ */
+void *
+fdt_child_node(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+ /* check if there is a child node */
+ return (betoh32(*ptr) == FDT_NODE_BEGIN) ? (ptr) : NULL;
+}
+
+/*
+ * Retrieves node name.
+ */
+char *
+fdt_node_name(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ return (char *)(ptr + 1);
+}
+
+void *
+fdt_find_node(char *name)
+{
+ void *node = fdt_next_node(0);
+ const char *p = name;
+
+ if (!tree_inited)
+ return NULL;
+
+ if (*p != '/')
+ return NULL;
+
+ while (*p) {
+ void *child;
+ const char *q;
+
+ while (*p == '/')
+ p++;
+ if (*p == 0)
+ return node;
+ q = strchr(p, '/');
+ if (q == NULL)
+ q = p + strlen(p);
+
+ for (child = fdt_child_node(node); child;
+ child = fdt_next_node(child)) {
+ if (strncmp(p, fdt_node_name(child), q - p) == 0) {
+ node = child;
+ break;
+ }
+ }
+
+ p = q;
+ }
+
+ return node;
+}
+
+void *
+fdt_parent_node_recurse(void *pnode, void *child)
+{
+ void *node = fdt_child_node(pnode);
+ void *tmp;
+
+ while (node && (node != child)) {
+ if ((tmp = fdt_parent_node_recurse(node, child)))
+ return tmp;
+ node = fdt_next_node(node);
+ }
+ return (node) ? pnode : NULL;
+}
+
+void *
+fdt_parent_node(void *node)
+{
+ void *pnode = fdt_next_node(0);
+
+ if (!tree_inited)
+ return NULL;
+
+ if (node == pnode)
+ return NULL;
+
+ return fdt_parent_node_recurse(pnode, node);
+}
+
+#ifdef DEBUG
+/*
+ * Debug methods for printing whole tree, particular odes and properies
+ */
+void *
+fdt_print_property(void *node, int level)
+{
+ uint32_t *ptr;
+ char *tmp, *value;
+ int cnt;
+ uint32_t nameid, size;
+
+ ptr = (uint32_t *)node;
+
+ if (!tree_inited)
+ return NULL;
+
+ if (betoh32(*ptr) != FDT_PROPERTY)
+ return ptr; /* should never happen */
+
+ /* extract property name_id and size */
+ size = betoh32(*++ptr);
+ nameid = betoh32(*++ptr);
+
+ for (cnt = 0; cnt < level; cnt++)
+ printf("\t");
+
+ tmp = fdt_get_str(nameid);
+ printf("\t%s : ", tmp ? tmp : "NO_NAME");
+
+ ptr++;
+ value = (char *)ptr;
+
+ if (!strcmp(tmp, "device_type") || !strcmp(tmp, "compatible") ||
+ !strcmp(tmp, "model") || !strcmp(tmp, "bootargs") ||
+ !strcmp(tmp, "linux,stdout-path")) {
+ printf("%s", value);
+ } else if (!strcmp(tmp, "clock-frequency") ||
+ !strcmp(tmp, "timebase-frequency")) {
+ printf("%d", betoh32(*((unsigned int *)value)));
+ } else {
+ for (cnt = 0; cnt < size; cnt++) {
+ if ((cnt % sizeof(uint32_t)) == 0)
+ printf(" ");
+ printf("%x%x", value[cnt] >> 4, value[cnt] & 0xf);
+ }
+ }
+ ptr += roundup(size, sizeof(uint32_t)) / sizeof(uint32_t);
+ printf("\n");
+
+ return ptr;
+}
+
+void
+fdt_print_node(void *node, int level)
+{
+ uint32_t *ptr;
+ int cnt;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return;
+
+ ptr++;
+
+ for (cnt = 0; cnt < level; cnt++)
+ printf("\t");
+ printf("%s :\n", fdt_node_name(node));
+ ptr = skip_node_name(ptr);
+
+ while (betoh32(*ptr) == FDT_PROPERTY)
+ ptr = fdt_print_property(ptr, level);
+}
+
+void
+fdt_print_node_recurse(void *node, int level)
+{
+ void *child;
+
+ fdt_print_node(node, level);
+ for (child = fdt_child_node(node); child; child = fdt_next_node(child))
+ fdt_print_node_recurse(child, level + 1);
+}
+
+void
+fdt_print_tree(void)
+{
+ fdt_print_node_recurse(fdt_next_node(0), 0);
+}
+#endif
diff --git a/sys/arch/armv7/stand/efiboot/fdt.h b/sys/arch/armv7/stand/efiboot/fdt.h
new file mode 100644
index 00000000000..2fc4e6f3047
--- /dev/null
+++ b/sys/arch/armv7/stand/efiboot/fdt.h
@@ -0,0 +1,67 @@
+/* $OpenBSD: fdt.h,v 1.1 2016/05/17 21:26:32 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct fdt_head {
+ uint32_t fh_magic;
+ uint32_t fh_size;
+ uint32_t fh_struct_off;
+ uint32_t fh_strings_off;
+ uint32_t fh_reserve_off;
+ uint32_t fh_version;
+ uint32_t fh_comp_ver; /* last compatible version */
+ uint32_t fh_boot_cpu_id; /* fh_version >=2 */
+ uint32_t fh_strings_size; /* fh_version >=3 */
+ uint32_t fh_struct_size; /* fh_version >=17 */
+};
+
+struct fdt {
+ struct fdt_head *header;
+ char *tree;
+ char *strings;
+ char *memory;
+ char *end;
+ int version;
+ int strings_size;
+ int struct_size;
+};
+
+#define FDT_MAGIC 0xd00dfeed
+#define FDT_NODE_BEGIN 0x01
+#define FDT_NODE_END 0x02
+#define FDT_PROPERTY 0x03
+#define FDT_NOP 0x04
+#define FDT_END 0x09
+
+#define FDT_CODE_VERSION 0x11
+
+int fdt_init(void *);
+void fdt_finalize(void);
+size_t fdt_get_size(void *);
+void *fdt_next_node(void *);
+void *fdt_child_node(void *);
+char *fdt_node_name(void *);
+void *fdt_find_node(char *);
+int fdt_node_property(void *, char *, char **);
+int fdt_set_node_property(void *, char *, char *, int);
+int fdt_add_node_property(void *, char *, char *, int);
+void *fdt_parent_node(void *);
+#ifdef DEBUG
+void *fdt_print_property(void *, int);
+void fdt_print_node(void *, int);
+void fdt_print_tree(void);
+#endif