[Crosstoolchain-logs] [device-tree-compiler] 05/357: First cut at a "libdt" set of routines for extracting things from the flattened tree. Could be used in firmware.
Hector Oron
zumbi at moszumanska.debian.org
Thu Dec 8 17:05:41 UTC 2016
This is an automated email from the git hooks/post-receive script.
zumbi pushed a commit to branch upstream/1.3.x
in repository device-tree-compiler.
commit ab870cadb4e0933e3fa6958c2b64f423c478c225
Author: David Gibson <dgibson at sneetch.(none)>
Date: Thu Jun 23 15:45:13 2005 +1000
First cut at a "libdt" set of routines for extracting things from the
flattened tree. Could be used in firmware.
---
Makefile | 2 +-
flat_dt.h | 44 +++++++++++++
flattree.c | 34 +---------
libdt.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 259 insertions(+), 34 deletions(-)
diff --git a/Makefile b/Makefile
index f9a1050..8cd8a12 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ lex.yy.c: dtc-lexer.l
lex.yy.o: lex.yy.c dtc-parser.tab.h
-dtc-parser.c: dtc-lexer.c
+livetree.o: flat_dt.h
check: all
cd tests && $(MAKE) check
diff --git a/flat_dt.h b/flat_dt.h
new file mode 100644
index 0000000..28b4d03
--- /dev/null
+++ b/flat_dt.h
@@ -0,0 +1,44 @@
+#ifndef _FLAT_DT_H_
+#define _FLAT_DT_H_
+
+
+#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */
+
+#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */
+#define OF_DT_END_NODE 0x2 /* End node */
+#define OF_DT_PROP 0x3 /* Property: name off,
+ size, content */
+#define OF_DT_END 0x9
+
+struct boot_param_header {
+ uint32_t magic; /* magic word OF_DT_HEADER */
+ uint32_t totalsize; /* total size of DT block */
+ uint32_t off_dt_struct; /* offset to structure */
+ uint32_t off_dt_strings; /* offset to strings */
+ uint32_t off_mem_rsvmap; /* offset to memory reserve map */
+ uint32_t version; /* format version */
+ uint32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ uint32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ uint32_t size_dt_strings; /* size of the strings block */
+};
+
+#define BPH_V1_SIZE (7*sizeof(uint32_t))
+#define BPH_V2_SIZE (BPH_V1_SIZE + sizeof(uint32_t))
+#define BPH_V3_SIZE (BPH_V2_SIZE + sizeof(uint32_t))
+
+struct reserve_entry {
+ uint64_t address;
+ uint64_t size;
+};
+
+struct flat_dt_property {
+ uint32_t nameoff;
+ uint32_t len;
+ char data[0];
+};
+
+#endif /* _FLAT_DT_H_ */
diff --git a/flattree.c b/flattree.c
index 28427ab..2b8efdd 100644
--- a/flattree.c
+++ b/flattree.c
@@ -19,39 +19,7 @@
*/
#include "dtc.h"
-
-#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */
-
-#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */
-#define OF_DT_END_NODE 0x2 /* End node */
-#define OF_DT_PROP 0x3 /* Property: name off,
- size, content */
-#define OF_DT_END 0x9
-
-struct boot_param_header {
- u32 magic; /* magic word OF_DT_HEADER */
- u32 totalsize; /* total size of DT block */
- u32 off_dt_struct; /* offset to structure */
- u32 off_dt_strings; /* offset to strings */
- u32 off_mem_rsvmap; /* offset to memory reserve map */
- u32 version; /* format version */
- u32 last_comp_version; /* last compatible version */
-
- /* version 2 fields below */
- u32 boot_cpuid_phys; /* Which physical CPU id we're
- booting on */
- /* version 3 fields below */
- u32 size_dt_strings; /* size of the strings block */
-};
-
-#define BPH_V1_SIZE (7*sizeof(u32))
-#define BPH_V2_SIZE (BPH_V1_SIZE + sizeof(u32))
-#define BPH_V3_SIZE (BPH_V2_SIZE + sizeof(u32))
-
-struct reserve_entry {
- u64 address;
- u64 size;
-};
+#include "flat_dt.h"
#define FTF_FULLPATH 0x1
#define FTF_VARALIGN 0x2
diff --git a/libdt.c b/libdt.c
new file mode 100644
index 0000000..df50402
--- /dev/null
+++ b/libdt.c
@@ -0,0 +1,213 @@
+#include <stdint.h>
+#include <string.h>
+
+#include "flat_dt.h"
+
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ((a) - 1))
+#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
+
+#define GET_CELL(p) (p += 4, *((u32 *)(p-4)))
+
+static char *skip_name(char *p)
+{
+ while (*p != '\0')
+ p++;
+
+ return PALIGN(p, sizeof(u32));
+}
+
+static char *skip_prop(void *blob, char *p)
+{
+ struct boot_param_header *bph = blob;
+ u32 len, nameoff;
+
+ len = GET_CELL(p);
+ nameoff = GET_CELL(p);
+ if ((bph->version < 0x10) && (len >= sizeof(u64)))
+ p = PALIGN(p, sizeof(u64));
+ return PALIGN(p + len, sizeof(u32));
+}
+
+static char *get_unit(char *dtpath)
+{
+ char *p;
+
+ if (dtpath[0] != '/')
+ return dtpath;
+
+ p = dtpath + strlen(dtpath);
+ while (*p != '/')
+ p--;
+
+ return p+1;
+}
+
+static int first_seg_len(char *dtpath)
+{
+ int len = 0;
+
+ while ((dtpath[len] != '/') && (dtpath[len] != '\0'))
+ len++;
+
+ return len;
+}
+
+char *flat_dt_get_string(void *blob, u32 offset)
+{
+ struct boot_param_header *bph = blob;
+
+ return (char *)blob + bph->off_dt_strings + offset;
+}
+
+void *flat_dt_get_subnode(void *blob, void *node, char *uname, int unamelen)
+{
+ struct boot_param_header *bph = blob;
+ char *p = node;
+ u32 tag;
+ int depth = 0;
+ char *nuname;
+
+ if (! unamelen)
+ unamelen = strlen(uname);
+
+ do {
+ tag = GET_CELL(p);
+
+ switch (tag) {
+ case OF_DT_PROP:
+ p = skip_prop(blob, p);
+ break;
+
+ case OF_DT_BEGIN_NODE:
+ if (depth == 0) {
+ nuname = p;
+
+ if (bph->version < 0x10)
+ nuname = get_unit(nuname);
+
+ p = skip_name(p);
+
+ if (strncmp(nuname, uname, unamelen) == 0)
+ return p;
+ }
+ depth++;
+ break;
+
+ case OF_DT_END_NODE:
+ depth--;
+ break;
+
+ case OF_DT_END:
+ /* looks like a malformed tree */
+ return NULL;
+ break;
+
+ default:
+ /* FIXME: throw some sort of error */
+ return NULL;
+ }
+ } while (depth >= 0);
+
+ return NULL;
+}
+
+void *flat_dt_get_node(void *blob, char *path)
+{
+ struct boot_param_header *bph = blob;
+ char *node;
+ int seglen;
+
+ node = blob + bph->off_dt_struct;
+ node += sizeof(u32); /* skip initial OF_DT_BEGIN_NODE */
+ node = skip_name(node); /* skip root node name */
+
+ while (node && (*path)) {
+ if (path[0] == '/')
+ path++;
+
+ seglen = first_seg_len(path);
+
+ node = flat_dt_get_subnode(blob, node, path, seglen);
+
+ path += seglen;
+ }
+
+ return node;
+}
+
+void flat_dt_traverse(void *blob, int (*fn)(void *blob, void *node, void *priv),
+ void *private)
+{
+ struct boot_param_header *bph = blob;
+ char *p;
+ u32 tag;
+ int depth = 0;
+ char *uname;
+
+ p = (char *)blob + bph->off_dt_struct;
+
+ tag = GET_CELL(p);
+ while (tag != OF_DT_END) {
+ switch (tag) {
+ case OF_DT_BEGIN_NODE:
+ uname = p;
+
+ if (bph->version < 0x10)
+ uname = get_unit(uname);
+
+ p = skip_name(p);
+
+ (*fn)(blob, p, private);
+ depth++;
+ break;
+
+ case OF_DT_END_NODE:
+ depth--;
+ break;
+
+ case OF_DT_PROP:
+ p = skip_prop(blob, p);
+ break;
+
+ default:
+ /* FIXME: badly formed tree */
+ return;
+ }
+ }
+}
+
+void *flat_dt_get_prop(void *blob, void *node, char *name, u32 *len)
+{
+ struct boot_param_header *bph = blob;
+ char *p = node;
+
+ do {
+ u32 tag = GET_CELL(p);
+ u32 sz, noff;
+ const char *nstr;
+
+ if (tag != OF_DT_PROP)
+ return NULL;
+
+ sz = GET_CELL(p);
+ noff = GET_CELL(p);
+
+ /* Old versions have variable alignment of the
+ * property value */
+ if ((bph->version < 0x10) && (sz >= 8))
+ p = PALIGN(p, 8);
+
+ nstr = flat_dt_get_string(blob, noff);
+
+ if (strcmp(name, nstr) == 0) {
+ if (len)
+ *len = sz;
+ return (void *)p;
+ }
+
+ p = PALIGN(p + sz, sizeof(u32));
+ } while(1);
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/crosstoolchain/device-tree-compiler.git
More information about the Crosstoolchain-logs
mailing list