Browse Source

First cut at a "libdt" set of routines for extracting things from the

flattened tree.  Could be used in firmware.
main
David Gibson 20 years ago
parent
commit
ab870cadb4
  1. 2
      Makefile
  2. 44
      flat_dt.h
  3. 34
      flattree.c
  4. 213
      libdt.c

2
Makefile

@ -21,7 +21,7 @@ lex.yy.c: dtc-lexer.l @@ -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

44
flat_dt.h

@ -0,0 +1,44 @@ @@ -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_ */

34
flattree.c

@ -19,39 +19,7 @@ @@ -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

213
libdt.c

@ -0,0 +1,213 @@ @@ -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);
}
Loading…
Cancel
Save