diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-17 21:26:33 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-17 21:26:33 +0000 |
commit | 116b6fec4cd7bb90f26b8168f0faabdfe0a5e7e7 (patch) | |
tree | 5ee632f7805c0a99c02d8405d58ab718b38dd4aa /sys | |
parent | e51d0f8eaab5b95a9c2ba99f5bfa0f7445b3f410 (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/Makefile | 10 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/efiboot.c | 39 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/efiboot.h | 18 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/exec.c | 42 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/fdt.c | 553 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/fdt.h | 67 |
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 |