Browse Source

libfdt - library for manipulating device trees in flattened format

Initial revision, read-only and "in-place" (no memmove() required)
write operations only.
main
David Gibson 18 years ago
commit
3da0f9a10d
  1. 5
      .gitignore
  2. 88
      Makefile
  3. 94
      fdt.c
  4. 58
      fdt.h
  5. 243
      fdt_ro.c
  6. 108
      fdt_wip.c
  7. 107
      libfdt.h
  8. 19
      libfdt_env.h
  9. 39
      libfdt_internal.h
  10. 0
      tests/.gitignore
  11. 50
      tests/Makefile
  12. 41
      tests/getprop.c
  13. 96
      tests/nop_node.c
  14. 70
      tests/nop_property.c
  15. 75
      tests/notfound.c
  16. 97
      tests/path_offset.c
  17. 40
      tests/property_offset.c
  18. 51
      tests/root_node.c
  19. 55
      tests/run_tests.sh
  20. 69
      tests/setprop_inplace.c
  21. 82
      tests/subnode_offset.c
  22. 8
      tests/testdata.h
  23. 126
      tests/tests.h
  24. 163
      tests/testutils.c
  25. 84
      tests/trees.S

5
.gitignore vendored

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
*.d
*.o
*.a
*.so
*~

88
Makefile

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
PREFIX = /usr/local
TARGETLIBS = libfdt.a
LIBOBJS = fdt.o fdt_ro.o fdt_wip.o #fdt_sw.o

SOURCE = $(shell find . -maxdepth 1 ! -name version.h -a -name '*.[h]')
SOURCE += *.c Makefile
NODEPTARGETS=<clean>

CPPFLAGS = -I.
CFLAGS = -Wall -g

LIBDIR = $(PREFIX)/$(LIB32)

EXTRA_DIST = \
README \
HOWTO \
LGPL-2.1

ifdef V
VECHO = :
else
VECHO = echo " "
ARFLAGS = rc
.SILENT:
endif

DEPFILES = $(LIBOBJS:%.o=%.d)

all: libs tests

.PHONY: tests libs

libs: $(TARGETLIBS)

tests: tests/all

tests/%: libs
$(MAKE) -C tests $*

check: all
cd tests; ./run_tests.sh

checkv: all
cd tests; ./run_tests.sh -v

func: all
cd tests; ./run_tests.sh -t func

funcv: all
cd tests; ./run_tests.sh -t func -v

stress: all
cd tests; ./run_tests.sh -t stress

stressv: all
cd tests; ./run_tests.sh -t stress -v

%.o: %.c
@$(VECHO) CC $@
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<

libfdt.a: $(LIBOBJS)
@$(VECHO) AR $@
$(AR) $(ARFLAGS) $@ $^

%.i: %.c
@$(VECHO) CPP $@
$(CC) $(CPPFLAGS) -E $< > $@

%.s: %.c
@$(VECHO) CC -S $@
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -S $<

clean:
@$(VECHO) CLEAN
rm -f *~ *.o *.so *.a *.d *.i *.s core a.out $(VERSION)
$(MAKE) -C tests clean

%.d: %.c
@$(CC) $(CPPFLAGS) -MM -MT "$*.o $@" $< > $@

# Workaround: Don't build dependencies for certain targets
# When the include below is executed, make will use the %.d target above to
# generate missing files. For certain targets (clean, version.h, etc) we don't
# need or want these dependency files, so don't include them in this case.
ifeq (,$(findstring <$(MAKECMDGOALS)>,$(NODEPTARGETS)))
-include $(DEPFILES)
endif

94
fdt.c

@ -0,0 +1,94 @@ @@ -0,0 +1,94 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libfdt_env.h"

#include <fdt.h>
#include <libfdt.h>

#include "libfdt_internal.h"

void *fdt_offset_ptr(const struct fdt_header *fdt, int offset, int len)
{
void *p;

p = (void *)fdt + fdt32_to_cpu(fdt->off_dt_struct) + offset;

if (p + len < p)
return NULL;
return p;
}

char *fdt_string(const struct fdt_header *fdt, int stroffset)
{
return (char *)fdt + fdt32_to_cpu(fdt->off_dt_strings) + stroffset;
}

int fdt_string_cmp(const struct fdt_header *fdt, int stroffset, const char *s2)
{
const char *s1 = fdt_string(fdt, stroffset);
int len = strlen(s2) + 1;

if (! s1)
return 0;

if ((stroffset + len < stroffset)
|| (stroffset + len > fdt32_to_cpu(fdt->size_dt_strings)))
return -2;

return strcmp(s1, s2);
}

uint32_t _fdt_next_tag(const struct fdt_header *fdt, int offset, int *nextoffset)
{
const uint32_t *tagp, *lenp;
uint32_t tag;
const char *p;

if (offset % FDT_TAGSIZE)
return -1;

tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (! tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;

switch (tag) {
case FDT_BEGIN_NODE:
/* skip name */
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (! p)
return FDT_END;
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, sizeof(*lenp));
if (! lenp)
return FDT_END;
/* skip name offset, length and value */
offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
break;
}

if (nextoffset)
*nextoffset = ALIGN(offset, FDT_TAGSIZE);

return tag;
}

58
fdt.h

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
#ifndef _FDT_H
#define _FDT_H

#ifndef __ASSEMBLY__

#include <stdint.h>

struct fdt_header {
uint32_t magic; /* magic word FDT_MAGIC */
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 */
};

struct fdt_reserve_entry {
uint64_t address;
uint64_t size;
};

struct fdt_node_header {
uint32_t tag;
char name[0];
};

struct fdt_property {
uint32_t tag;
uint32_t nameoff;
uint32_t len;
char data[0];
};

#endif /* !__ASSEMBLY */

#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
#define FDT_TAGSIZE sizeof(uint32_t)

#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
#define FDT_END_NODE 0x2 /* End node */
#define FDT_PROP 0x3 /* Property: name off,
size, content */
#define FDT_NOP 0x4 /* nop */
#define FDT_END 0x9

#define FDT_V1_SIZE (7*sizeof(uint32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t))
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t))


#endif /* _FDT_H */

243
fdt_ro.c

@ -0,0 +1,243 @@ @@ -0,0 +1,243 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libfdt_env.h"

#include <fdt.h>
#include <libfdt.h>

#include "libfdt_internal.h"

static int check_header(const struct fdt_header *fdt)
{
if (fdt32_to_cpu(fdt->magic) != FDT_MAGIC)
return FDT_ERR_BADMAGIC;
if (fdt32_to_cpu(fdt->version) < FDT_FIRST_SUPPORTED_VERSION)
return FDT_ERR_BADVERSION;
if (fdt32_to_cpu(fdt->last_comp_version) > FDT_LAST_SUPPORTED_VERSION)
return FDT_ERR_BADVERSION;
return 0;
}

#define OFFSET_CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = check_header(fdt)) != 0) \
return OFFSET_ERROR(err); \
}

static int offset_streq(const struct fdt_header *fdt, int offset,
const char *s, int len)
{
const char *p = fdt_offset_ptr(fdt, offset, len+1);

if (! p)
/* short match */
return 0;

if (memcmp(p, s, len) != 0)
return 0;

if (p[len] != '\0')
return 0;

return 1;
}

int fdt_property_offset(const struct fdt_header *fdt, int nodeoffset,
const char *name)
{
int level = 0;
uint32_t tag;
struct fdt_property *prop;
int namestroff;
int offset, nextoffset;

OFFSET_CHECK_HEADER(fdt);

if (nodeoffset % FDT_TAGSIZE)
return OFFSET_ERROR(FDT_ERR_BADOFFSET);

tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return OFFSET_ERROR(FDT_ERR_BADOFFSET);

do {
offset = nextoffset;
if (offset % FDT_TAGSIZE)
return OFFSET_ERROR(FDT_ERR_INTERNAL);

tag = _fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
return OFFSET_ERROR(FDT_ERR_TRUNCATED);

case FDT_BEGIN_NODE:
level++;
break;

case FDT_END_NODE:
level--;
break;

case FDT_PROP:
if (level != 0)
continue;

prop = fdt_offset_ptr_typed(fdt, offset, prop);
if (! prop)
return OFFSET_ERROR(FDT_ERR_BADSTRUCTURE);
namestroff = fdt32_to_cpu(prop->nameoff);
if (fdt_string_cmp(fdt, namestroff, name) == 0)
/* Found it! */
return offset;
break;

case FDT_NOP:
break;

default:
return OFFSET_ERROR(FDT_ERR_BADSTRUCTURE);
}
} while (level >= 0);

return OFFSET_ERROR(FDT_ERR_NOTFOUND);
}

int fdt_subnode_offset_namelen(const struct fdt_header *fdt, int parentoffset,
const char *name, int namelen)
{
int level = 0;
uint32_t tag;
int offset, nextoffset;

OFFSET_CHECK_HEADER(fdt);

tag = _fdt_next_tag(fdt, parentoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return OFFSET_ERROR(FDT_ERR_BADOFFSET);

do {
offset = nextoffset;
tag = _fdt_next_tag(fdt, offset, &nextoffset);

switch (tag) {
case FDT_END:
return OFFSET_ERROR(FDT_ERR_TRUNCATED);

case FDT_BEGIN_NODE:
level++;
if (level != 1)
continue;
if (offset_streq(fdt, offset+FDT_TAGSIZE, name, namelen))
/* Found it! */
return offset;
break;

case FDT_END_NODE:
level--;
break;

case FDT_PROP:
case FDT_NOP:
break;

default:
return OFFSET_ERROR(FDT_ERR_BADSTRUCTURE);
}
} while (level >= 0);

return OFFSET_ERROR(FDT_ERR_NOTFOUND);
}

int fdt_subnode_offset(const struct fdt_header *fdt, int parentoffset,
const char *name)
{
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
}

int fdt_path_offset(const struct fdt_header *fdt, const char *path)
{
const char *end = path + strlen(path);
const char *p = path;
int offset = 0;

OFFSET_CHECK_HEADER(fdt);

if (*path != '/')
return OFFSET_ERROR(FDT_ERR_BADPATH);

while (*p) {
const char *q;

while (*p == '/')
p++;
if (! *p)
return OFFSET_ERROR(FDT_ERR_BADPATH);
q = strchr(p, '/');
if (! q)
q = end;

offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
if (fdt_offset_error(offset))
return offset;

p = q;
}

return offset;
}

struct fdt_property *_fdt_getprop(const struct fdt_header *fdt, int nodeoffset,
const char *name, int *lenp)
{
int propoffset;
struct fdt_property *prop;
int err;
int len;

propoffset = fdt_property_offset(fdt, nodeoffset, name);
if ((err = fdt_offset_error(propoffset)))
return PTR_ERROR(err);

prop = fdt_offset_ptr(fdt, propoffset, sizeof(prop));
if (! prop)
return PTR_ERROR(FDT_ERR_BADSTRUCTURE);
len = fdt32_to_cpu(prop->len);
prop = fdt_offset_ptr(fdt, propoffset, sizeof(prop) + len);
if (! prop)
return PTR_ERROR(FDT_ERR_BADSTRUCTURE);

if (lenp)
*lenp = len;

return prop;
}

void *fdt_getprop(const struct fdt_header *fdt, int nodeoffset,
const char *name, int *lenp)
{
const struct fdt_property *prop;
int err;

prop = _fdt_getprop(fdt, nodeoffset, name, lenp);
if ((err = fdt_ptr_error(prop)))
return PTR_ERROR(err);

return prop->data;
}

108
fdt_wip.c

@ -0,0 +1,108 @@ @@ -0,0 +1,108 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libfdt_env.h"

#include <fdt.h>
#include <libfdt.h>

#include "libfdt_internal.h"

int fdt_setprop_inplace(struct fdt_header *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
void *propval;
int proplen;
int err;

propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if ((err = fdt_ptr_error(propval)))
return err;

if (proplen != len)
return FDT_ERR_SIZE_MISMATCH;

memcpy(propval, val, len);
return 0;
}

static void nop_region(void *start, int len)
{
uint32_t *p;

for (p = start; (void *)p < (start + len); p++)
*p = FDT_NOP;
}

int fdt_nop_property(struct fdt_header *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len;
int err;

prop = _fdt_getprop(fdt, nodeoffset, name, &len);
if ((err = fdt_ptr_error(prop)))
return err;

nop_region(prop, len + sizeof(*prop));

return 0;
}

int fdt_nop_node(struct fdt_header *fdt, int nodeoffset)
{
int level = 0;
int err = 0;
uint32_t tag;
int offset, nextoffset;

tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return FDT_ERR_BADOFFSET;

do {
offset = nextoffset;
tag = _fdt_next_tag(fdt, offset, &nextoffset);

switch (tag) {
case FDT_END:
level = -1;
err = FDT_ERR_TRUNCATED;
break;

case FDT_BEGIN_NODE:
level++;
break;

case FDT_END_NODE:
level--;
break;

case FDT_PROP:
case FDT_NOP:
break;

default:
return FDT_ERR_BADSTRUCTURE;
}
} while (level >= 0);

nop_region(fdt_offset_ptr(fdt, nodeoffset, 0), nextoffset - nodeoffset);

return err;
}

107
libfdt.h

@ -0,0 +1,107 @@ @@ -0,0 +1,107 @@
#ifndef _LIBFDT_H
#define _LIBFDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <fdt.h>

#define FDT_FIRST_SUPPORTED_VERSION 0x10
#define FDT_LAST_SUPPORTED_VERSION 0x10

/* Errors */
#define FDT_ERR_OK 0
#define FDT_ERR_BADMAGIC 1
#define FDT_ERR_BADVERSION 2
#define FDT_ERR_BADPOINTER 3
#define FDT_ERR_BADHEADER 4
#define FDT_ERR_BADSTRUCTURE 5
#define FDT_ERR_BADOFFSET 6
#define FDT_ERR_NOTFOUND 7
#define FDT_ERR_BADPATH 8
#define FDT_ERR_TRUNCATED 9
#define FDT_ERR_NOSPACE 10
#define FDT_ERR_BADSTATE 11
#define FDT_ERR_SIZE_MISMATCH 12
#define FDT_ERR_INTERNAL 13

#define FDT_ERR_MAX 13

/* Offset handling functions */
void *fdt_offset_ptr(const struct fdt_header *fdt, int offset, int checklen);

#define fdt_offset_ptr_typed(fdt, offset, var) \
((typeof(var))(fdt_offset_ptr((fdt), (offset), sizeof(*(var)))))

#define fdt_offset_error(offset) \
( (offset) < 0 ? -(offset) : 0 )

#define fdt_ptr_error(ptr) \
( (((long)(ptr) < 0) && ((long)(ptr) >= -FDT_ERR_MAX)) ? -(long)(ptr) : 0 )

char *fdt_string(const struct fdt_header *fdt, int stroffset);
int fdt_string_cmp(const struct fdt_header *fdt, int stroffset, const char *s2);

/* Read-only functions */
int fdt_property_offset(const struct fdt_header *fdt, int nodeoffset,
const char *name);
int fdt_subnode_offset_namelen(const struct fdt_header *fdt, int parentoffset,
const char *name, int namelen);
int fdt_subnode_offset(const struct fdt_header *fdt, int parentoffset,
const char *name);

int fdt_path_offset(const struct fdt_header *fdt, const char *path);

void *fdt_getprop(const struct fdt_header *fdt, int nodeoffset,
const char *name, int *lenp);

/* Write-in-place functions */
int fdt_setprop_inplace(struct fdt_header *fdt, int nodeoffset, const char *name,
const void *val, int len);

#define fdt_setprop_inplace_typed(fdt, nodeoffset, name, val) \
({ \
typeof(val) x = val; \
fdt_setprop_inplace(fdt, nodeoffset, name, &x, sizeof(x)); \
})

int fdt_nop_property(struct fdt_header *fdt, int nodeoffset, const char *name);
int fdt_nop_node(struct fdt_header *fdt, int nodeoffset);

#if 0
/* Sequential-write functions */
struct fdt_header *fdt_create(void *buf, int bufsize);
int fdt_add_reservemap_entry(struct fdt_header *fdt, uint64_t addr, uint64_t size);
int fdt_begin_structure(struct fdt_header *fdt);
int fdt_begin_node(struct fdt_header *fdt, const char *name);
int fdt_property(struct fdt_header *fdt, const char *name, const void *val, int len);
int fdt_end_node(struct fdt_header *fdt);
int fdt_finish_structure(struct fdt_header *fdt);

/* Read-write functions */
struct fdt_header *fdt_open(struct fdt_header *fdt, int bufsize);
int fdt_add_subnode(struct fdt_header *fdtx, void *node, const char *name);
int fdt_set_property(struct fdt_header *fdtx, void *node, const char *name,
const void *val, int len);
int fdt_del_property(struct fdt_header *fdtx, void *node, const char *name);

/* Misc functions */
struct fdt_header *fdt_move(struct fdt_header *fdt, void *buf, int bufsize);
#endif

#endif /* _LIBFDT_H */

19
libfdt_env.h

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <endian.h>
#include <byteswap.h>

#if __BYTE_ORDER == __BIG_ENDIAN
#define fdt32_to_cpu(x) (x)
#define cpu_to_fdt32(x) (x)
#define fdt64_to_cpu(x) (x)
#define cpu_to_fdt64(x) (x)
#else
#define fdt32_to_cpu(x) (bswap_32((x)))
#define cpu_to_fdt32(x) (bswap_32((x)))
#define fdt64_to_cpu(x) (bswap_64((x)))
#define cpu_to_fdt64(x) (bswap_64((x)))
#endif

#include "libfdt.h"

39
libfdt_internal.h

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
#ifndef _LIBFDT_INTERNAL_H
#define _LIBFDT_INTERNAL_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <fdt.h>

#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))

#define memeq(p, q, n) (memcmp((p), (q), (n)) == 0)
#define streq(p, q) (strcmp((p), (q)) == 0)

uint32_t _fdt_next_tag(const struct fdt_header *fdt, int startoffset, int *nextoffset);
struct fdt_property *_fdt_getprop(const struct fdt_header *fdt, int nodeoffset,
const char *name, int *lenp);


#define OFFSET_ERROR(code) -(code)
#define PTR_ERROR(code) (void *)(-(code))

#define SW_OFFSET(fdt) ((fdt)->version)

#endif /* _LIBFDT_INTERNAL_H */

0
tests/.gitignore vendored

50
tests/Makefile

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
PREFIX = /usr/local

LIB_TESTS =
LIBTREE_TESTS = root_node property_offset subnode_offset path_offset getprop \
notfound \
setprop_inplace nop_property nop_node
TESTS = $(LIB_TESTS) $(LIBTREE_TESTS)

CFLAGS = -Wall -g
CPPFLAGS = -I..
LDFLAGS = -L..

LIBFDT = ../libfdt.a

ifdef V
VECHO = :
else
VECHO = echo " "
.SILENT:
endif

DEPFILES = $(TESTS:%=%.d) testutils.d

all: $(TESTS)

%.o: %.c
@$(VECHO) CC $@
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<

%.o: %.S
@$(VECHO) AS $@
$(CC) -D__ASSEMBLY__ $(CPPFLAGS) -o $@ -c $<

$(LIB_TESTS): %: %.o testutils.o $(LIBFDT)
@$(VECHO) LD "(testcase)" $@
$(CC) $(LDFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)

$(LIBTREE_TESTS): %: %.o testutils.o trees.o $(LIBFDT)
@$(VECHO) LD "(testcase + trees)" $@
$(CC) $(LDFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)

clean:
@$(VECHO) CLEAN "(tests)"
rm -f *~ *.o *.so *.a *.d *.s core a.out
rm -f $(TESTS)

%.d: %.c
@$(CC) $(CPPFLAGS) -MM -MT "$*.o $@" $< > $@

-include $(DEPFILES)

41
tests/getprop.c

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_getprop()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;

test_init(argc, argv);

check_getprop_typed(fdt, 0, "prop-int", TEST_VALUE_1);
check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, TEST_STRING_1);

PASS();
}

96
tests/nop_node.c

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_nop_node()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;
int subnode1_offset, subnode2_offset, subsubnode2_offset;
int err;

test_init(argc, argv);

subnode1_offset = fdt_path_offset(fdt, "/subnode1");
if ((err = fdt_offset_error(subnode1_offset)))
FAIL("Couldn't find \"/subnode1\": %s", fdt_strerror(err));
check_getprop_typed(fdt, subnode1_offset, "prop-int", TEST_VALUE_1);

subnode2_offset = fdt_path_offset(fdt, "/subnode2");
if ((err = fdt_offset_error(subnode2_offset)))
FAIL("Couldn't find \"/subnode2\": %s", fdt_strerror(err));
check_getprop_typed(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
subsubnode2_offset = fdt_path_offset(fdt, "/subnode2/subsubnode");
if ((err = fdt_offset_error(subsubnode2_offset)))
FAIL("Couldn't find \"/subnode2/subsubnode\": %s",
fdt_strerror(err));
check_getprop_typed(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);

err = fdt_nop_node(fdt, subnode1_offset);
if (err)
FAIL("fdt_nop_node(subnode1): %s", fdt_strerror(err));

subnode1_offset = fdt_path_offset(fdt, "/subnode1");
if ((err = fdt_offset_error(subnode1_offset)) != FDT_ERR_NOTFOUND)
FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"",
fdt_strerror(err), fdt_strerror(FDT_ERR_NOTFOUND));

subnode2_offset = fdt_path_offset(fdt, "/subnode2");
if ((err = fdt_offset_error(subnode2_offset)))
FAIL("Couldn't find \"/subnode2\": %s", fdt_strerror(err));
check_getprop_typed(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);
subsubnode2_offset = fdt_path_offset(fdt, "/subnode2/subsubnode");
if ((err = fdt_offset_error(subsubnode2_offset)))
FAIL("Couldn't find \"/subnode2/subsubnode\": %s",
fdt_strerror(err));
check_getprop_typed(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);

err = fdt_nop_node(fdt, subnode2_offset);
if (err)
FAIL("fdt_nop_node(subnode2): %s", fdt_strerror(err));

subnode1_offset = fdt_path_offset(fdt, "/subnode1");
if ((err = fdt_offset_error(subnode1_offset)) != FDT_ERR_NOTFOUND)
FAIL("fdt_path_offset(subnode1) returned \"%s\" instead of \"%s\"",
fdt_strerror(err), fdt_strerror(FDT_ERR_NOTFOUND));

subnode2_offset = fdt_path_offset(fdt, "/subnode2");
if ((err = fdt_offset_error(subnode2_offset)) != FDT_ERR_NOTFOUND)
FAIL("fdt_path_offset(subnode2) returned \"%s\" instead of \"%s\"",
fdt_strerror(err), fdt_strerror(FDT_ERR_NOTFOUND));
subsubnode2_offset = fdt_path_offset(fdt, "/subnode2/subsubnode");
if ((err = fdt_offset_error(subsubnode2_offset)) != FDT_ERR_NOTFOUND)
FAIL("fdt_path_offset(subsubnode2) returned \"%s\" instead of \"%s\"",
fdt_strerror(err), fdt_strerror(FDT_ERR_NOTFOUND));

PASS();
}

70
tests/nop_property.c

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_nop_property()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;
uint32_t *intp;
char *strp;
int err;

test_init(argc, argv);

intp = check_getprop_typed(fdt, 0, "prop-int", TEST_VALUE_1);
verbose_printf("int value was 0x%08x\n", *intp);

err = fdt_nop_property(fdt, 0, "prop-int");
if (err)
FAIL("Failed to nop \"prop-int\": %s", fdt_strerror(err));

intp = fdt_getprop(fdt, 0, "prop-int", NULL);
err = fdt_ptr_error(intp);
if (! err)
FAIL("prop-int still present after nopping");
if (err != FDT_ERR_NOTFOUND)
FAIL("Unexpected error on second getprop: %s", fdt_strerror(err));
strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
TEST_STRING_1);
verbose_printf("string value was \"%s\"\n", strp);
err = fdt_nop_property(fdt, 0, "prop-str");
err = fdt_ptr_error(intp);
if (! err)
FAIL("prop-str still present after nopping");
if (err != FDT_ERR_NOTFOUND)
FAIL("Unexpected error on second getprop: %s", fdt_strerror(err));

strp = fdt_getprop(fdt, 0, "prop-str", NULL);
if (fdt_ptr_error(intp) != FDT_ERR_NOTFOUND)
FAIL("prop-str still present after nopping");

PASS();
}

75
tests/notfound.c

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for behaviour on searching for a non-existent node
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

void check_error(const char *s, int err)
{
if (err != FDT_ERR_NOTFOUND)
FAIL("%s return error %s instead of FDT_ERR_NOTFOUND", s,
fdt_strerror(err));
}

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;
int offset;
int subnode1_offset;
void *val;
int err;

test_init(argc, argv);

offset = fdt_property_offset(fdt, 0, "nonexistant-property");
check_error("fdt_property_offset(\"nonexistant-property\")",
fdt_offset_error(offset));

val = fdt_getprop(fdt, 0, "nonexistant-property", NULL);
check_error("fdt_getprop(\"nonexistant-property\"",
fdt_ptr_error(val));

subnode1_offset = fdt_subnode_offset(fdt, 0, "subnode1");
if ((err = fdt_offset_error(subnode1_offset)))
FAIL("Couldn't find subnode1: %s", fdt_strerror(err));

val = fdt_getprop(fdt, subnode1_offset, "prop-str", NULL);
check_error("fdt_getprop(\"prop-str\")", fdt_ptr_error(val));

offset = fdt_subnode_offset(fdt, 0, "nonexistant-subnode");
check_error("fdt_subnode_offset(\"nonexistant-subnode\")",
fdt_offset_error(offset));

offset = fdt_subnode_offset(fdt, 0, "subsubnode");
check_error("fdt_subnode_offset(\"subsubnode\")",
fdt_offset_error(offset));

offset = fdt_path_offset(fdt, "/nonexistant-subnode");
check_error("fdt_path_offset(\"/nonexistant-subnode\")",
fdt_offset_error(offset));
PASS();
}

97
tests/path_offset.c

@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_path_offset()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int check_subnode(struct fdt_header *fdt, int parent, const char *name)
{
int offset;
int err;
struct fdt_node_header *nh;
uint32_t tag;

verbose_printf("Checking subnode \"%s\" of %d...", name, parent);
offset = fdt_subnode_offset(fdt, parent, name);
verbose_printf("offset %d...", offset);
if ((err = fdt_offset_error(offset)))
FAIL("fdt_subnode_offset(\"%s\"): %s", name, fdt_strerror(err));
nh = fdt_offset_ptr_typed(fdt, offset, nh);
verbose_printf("pointer %p\n", nh);
if (! nh)
FAIL("NULL retrieving subnode \"%s\"", name);

tag = fdt32_to_cpu(nh->tag);

if (tag != FDT_BEGIN_NODE)
FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);
if (!streq(nh->name, name))
FAIL("Subnode name mismatch \"%s\" instead of \"%s\"",
nh->name, name);

return offset;
}

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;
int subnode1_offset, subnode2_offset;
int subnode1_offset_p, subnode2_offset_p;
int subsubnode1_offset, subsubnode2_offset;
int subsubnode1_offset_p, subsubnode2_offset_p;

test_init(argc, argv);

subnode1_offset = check_subnode(fdt, 0, "subnode1");
subnode2_offset = check_subnode(fdt, 0, "subnode2");

subnode1_offset_p = fdt_path_offset(fdt, "/subnode1");
subnode2_offset_p = fdt_path_offset(fdt, "/subnode2");

if (subnode1_offset != subnode1_offset_p)
FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
subnode1_offset, subnode1_offset_p);

if (subnode2_offset != subnode2_offset_p)
FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
subnode2_offset, subnode2_offset_p);

subsubnode1_offset = check_subnode(fdt, subnode1_offset, "subsubnode");
subsubnode2_offset = check_subnode(fdt, subnode2_offset, "subsubnode");

subsubnode1_offset_p = fdt_path_offset(fdt, "/subnode1/subsubnode");
subsubnode2_offset_p = fdt_path_offset(fdt, "/subnode2/subsubnode");

if (subsubnode1_offset != subsubnode1_offset_p)
FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
subsubnode1_offset, subsubnode1_offset_p);

if (subsubnode2_offset != subsubnode2_offset_p)
FAIL("Mismatch between subnode_offset (%d) and path_offset (%d)",
subsubnode2_offset, subsubnode2_offset_p);

PASS();
}

40
tests/property_offset.c

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_property_offset()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;

test_init(argc, argv);

check_property_typed(fdt, 0, "prop-int", TEST_VALUE_1);
check_property(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, TEST_STRING_1);

PASS();
}

51
tests/root_node.c

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
/*
* libfdt - Flat Device Tree manipulation
* Basic testcase for read-only access
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;
struct fdt_node_header *nh;

test_init(argc, argv);

nh = fdt_offset_ptr_typed(fdt, 0, nh);

if (! nh)
FAIL("NULL retrieving root node");

if (nh->tag != FDT_BEGIN_NODE)
FAIL("Wrong tag on root node");

if (strlen(nh->name) != 0)
FAIL("Wrong name for root node, \"%s\" instead of empty",
nh->name);

PASS();
}

55
tests/run_tests.sh

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
#! /bin/bash

export QUIET_TEST=1

ENV=/usr/bin/env

run_test () {
echo -n "$@: "
PATH=".:$PATH" $ENV "$@"
}

functional_tests () {
# Read-only tests
run_test root_node
run_test property_offset
run_test subnode_offset
run_test path_offset
run_test getprop
run_test notfound

# Write-in-place tests
run_test setprop_inplace
run_test nop_property
run_test nop_node
}

stress_tests () {
ITERATIONS=10 # Number of iterations for looping tests
}

while getopts "vdt:" ARG ; do
case $ARG in
"v")
unset QUIET_TEST
;;
"t")
TESTSETS=$OPTARG
;;
esac
done

if [ -z "$TESTSETS" ]; then
TESTSETS="func stress"
fi

for set in $TESTSETS; do
case $set in
"func")
functional_tests
;;
"stress")
stress_tests
;;
esac
done

69
tests/setprop_inplace.c

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_setprop_inplace()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;
uint32_t *intp;
char *strp, *xstr;
int xlen, i;
int err;

test_init(argc, argv);

intp = check_getprop_typed(fdt, 0, "prop-int", TEST_VALUE_1);

verbose_printf("Old int value was 0x%08x\n", *intp);
err = fdt_setprop_inplace_typed(fdt, 0, "prop-int", ~TEST_VALUE_1);
if (err)
FAIL("Failed to set \"prop-int\" to 0x08%x: %s",
~TEST_VALUE_1, fdt_strerror(err));
intp = check_getprop_typed(fdt, 0, "prop-int", ~TEST_VALUE_1);
verbose_printf("New int value is 0x%08x\n", *intp);
strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1,
TEST_STRING_1);

verbose_printf("Old string value was \"%s\"\n", strp);
xstr = strdup(strp);
xlen = strlen(xstr);
for (i = 0; i < xlen; i++)
xstr[i] = toupper(xstr[i]);
err = fdt_setprop_inplace(fdt, 0, "prop-str", xstr, xlen+1);
if (err)
FAIL("Failed to set \"prop-str\" to \"%s\": %s",
xstr, fdt_strerror(err));

strp = check_getprop(fdt, 0, "prop-str", xlen+1, xstr);
verbose_printf("New string value is \"%s\"\n", strp);

PASS();
}

82
tests/subnode_offset.c

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase for fdt_subnode_offset()
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <fdt.h>
#include <libfdt.h>

#include "tests.h"
#include "testdata.h"

int check_subnode(struct fdt_header *fdt, int parent, const char *name)
{
int offset;
int err;
struct fdt_node_header *nh;
uint32_t tag;

verbose_printf("Checking subnode \"%s\" of %d...", name, parent);
offset = fdt_subnode_offset(fdt, parent, name);
verbose_printf("offset %d...", offset);
if ((err = fdt_offset_error(offset)))
FAIL("fdt_subnode_offset(\"%s\"): %s", name, fdt_strerror(err));
nh = fdt_offset_ptr_typed(fdt, offset, nh);
verbose_printf("pointer %p\n", nh);
if (! nh)
FAIL("NULL retrieving subnode \"%s\"", name);

tag = fdt32_to_cpu(nh->tag);

if (tag != FDT_BEGIN_NODE)
FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);
if (!streq(nh->name, name))
FAIL("Subnode name mismatch \"%s\" instead of \"%s\"",
nh->name, name);

return offset;
}

int main(int argc, char *argv[])
{
struct fdt_header *fdt = &_test_tree1;
int subnode1_offset, subnode2_offset;
int subsubnode1_offset, subsubnode2_offset;

test_init(argc, argv);

subnode1_offset = check_subnode(fdt, 0, "subnode1");
subnode2_offset = check_subnode(fdt, 0, "subnode2");

if (subnode1_offset == subnode2_offset)
FAIL("Different subnodes have same offset");

check_property_typed(fdt, subnode1_offset, "prop-int", TEST_VALUE_1);
check_property_typed(fdt, subnode2_offset, "prop-int", TEST_VALUE_2);

subsubnode1_offset = check_subnode(fdt, subnode1_offset, "subsubnode");
subsubnode2_offset = check_subnode(fdt, subnode2_offset, "subsubnode");

check_property_typed(fdt, subsubnode1_offset, "prop-int", TEST_VALUE_1);
check_property_typed(fdt, subsubnode2_offset, "prop-int", TEST_VALUE_2);

PASS();
}

8
tests/testdata.h

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
#define TEST_VALUE_1 0xdeadbeef
#define TEST_VALUE_2 0xabcd1234

#define TEST_STRING_1 "hello world"

#ifndef __ASSEMBLY__
extern struct fdt_header _test_tree1;
#endif /* ! __ASSEMBLY */

126
tests/tests.h

@ -0,0 +1,126 @@ @@ -0,0 +1,126 @@
#ifndef _TESTS_H
#define _TESTS_H
/*
* libfdt - Flat Device Tree manipulation
* Testcase definitions
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#define DEBUG

/* Test return codes */
#define RC_PASS 0
#define RC_CONFIG 1
#define RC_FAIL 2
#define RC_BUG 99

extern int verbose_test;
extern char *test_name;
void test_init(int argc, char *argv[]);

#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))

#define streq(s1, s2) (strcmp((s1),(s2)) == 0)

#if __BYTE_ORDER == __BIG_ENDIAN
#define fdt32_to_cpu(x) (x)
#define cpu_to_fdt32(x) (x)
#define fdt64_to_cpu(x) (x)
#define cpu_to_fdt64(x) (x)
#else
#define fdt32_to_cpu(x) (bswap_32((x)))
#define cpu_to_fdt32(x) (bswap_32((x)))
#define fdt64_to_cpu(x) (bswap_64((x)))
#define cpu_to_fdt64(x) (bswap_64((x)))
#endif

/* Each test case must define this function */
void cleanup(void);

#define verbose_printf(...) \
if (verbose_test) { \
printf(__VA_ARGS__); \
fflush(stdout); \
}
#define ERR "ERR: "
#define ERROR(fmt, args...) fprintf(stderr, ERR fmt, ## args)


#define PASS() \
do { \
cleanup(); \
printf("PASS\n"); \
exit(RC_PASS); \
} while (0)

#define PASS_INCONCLUSIVE() \
do { \
cleanup(); \
printf("PASS (inconclusive)\n"); \
exit(RC_PASS); \
} while (0)

#define IRRELEVANT() \
do { \
cleanup(); \
printf("PASS (irrelevant)\n"); \
exit(RC_PASS); \
} while (0)

/* Look out, gcc extension below... */
#define FAIL(fmt, ...) \
do { \
cleanup(); \
printf("FAIL\t" fmt "\n", ##__VA_ARGS__); \
exit(RC_FAIL); \
} while (0)

#define CONFIG(fmt, ...) \
do { \
cleanup(); \
printf("Bad configuration: " fmt "\n", ##__VA_ARGS__); \
exit(RC_CONFIG); \
} while (0)

#define TEST_BUG(fmt, ...) \
do { \
cleanup(); \
printf("BUG in testsuite: " fmt "\n", ##__VA_ARGS__); \
exit(RC_BUG); \
} while (0)

const char *fdt_strerror(int errval);
void check_property(struct fdt_header *fdt, int nodeoffset, const char *name,
int len, const void *val);
#define check_property_typed(fdt, nodeoffset, name, val) \
({ \
typeof(val) x = val; \
check_property(fdt, nodeoffset, name, sizeof(x), &x); \
})


void *check_getprop(struct fdt_header *fdt, int nodeoffset, const char *name,
int len, const void *val);
#define check_getprop_typed(fdt, nodeoffset, name, val) \
({ \
typeof(val) x = val; \
check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
})


#endif /* _TESTS_H */

163
tests/testutils.c

@ -0,0 +1,163 @@ @@ -0,0 +1,163 @@
/*
* libfdt - Flat Device Tree manipulation
* Testcase common utility functions
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#define _GNU_SOURCE /* for strsignal() */

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>

#include <libfdt.h>

#include "tests.h"

int verbose_test = 1;
char *test_name;

void __attribute__((weak)) cleanup(void)
{
}

static void sigint_handler(int signum, siginfo_t *si, void *uc)
{
cleanup();
fprintf(stderr, "%s: %s (pid=%d)\n", test_name,
strsignal(signum), getpid());
exit(RC_BUG);
}

void test_init(int argc, char *argv[])
{
int err;
struct sigaction sa_int = {
.sa_sigaction = sigint_handler,
};

test_name = argv[0];

err = sigaction(SIGINT, &sa_int, NULL);
if (err)
FAIL("Can't install SIGINT handler");

if (getenv("QUIET_TEST"))
verbose_test = 0;

verbose_printf("Starting testcase \"%s\", pid %d\n",
test_name, getpid());
}


struct errtabent {
const char *str;
};

#define ERRTABENT(val) \
[(val)] = { .str = #val, }

static struct errtabent errtable[] = {
ERRTABENT(FDT_ERR_OK),
ERRTABENT(FDT_ERR_BADMAGIC),
ERRTABENT(FDT_ERR_BADVERSION),
ERRTABENT(FDT_ERR_BADPOINTER),
ERRTABENT(FDT_ERR_BADHEADER),
ERRTABENT(FDT_ERR_BADSTRUCTURE),
ERRTABENT(FDT_ERR_BADOFFSET),
ERRTABENT(FDT_ERR_NOTFOUND),
ERRTABENT(FDT_ERR_BADPATH),
ERRTABENT(FDT_ERR_TRUNCATED),
ERRTABENT(FDT_ERR_NOSPACE),
ERRTABENT(FDT_ERR_BADSTATE),
ERRTABENT(FDT_ERR_SIZE_MISMATCH),
ERRTABENT(FDT_ERR_INTERNAL),
};

#define ERRTABSIZE (sizeof(errtable) / sizeof(errtable[0]))

const char *fdt_strerror(int errval)
{
if ((errval >= 0) && (errval < ERRTABSIZE))
return errtable[errval].str;
else
return "Unknown FDT error code";
}

void check_property(struct fdt_header *fdt, int nodeoffset, const char *name,
int len, const void *val)
{
int offset;
const struct fdt_property *prop;
uint32_t tag, nameoff, proplen;
const char *propname;
int err;

verbose_printf("Checking property \"%s\"...", name);
offset = fdt_property_offset(fdt, nodeoffset, name);
verbose_printf("offset %d...", offset);
if ((err = fdt_offset_error(offset)))
FAIL("fdt_property_offset(\"%s\"): %s", name,
fdt_strerror(err));

prop = fdt_offset_ptr_typed(fdt, offset, prop);
verbose_printf("pointer %p\n", prop);
if (! prop)
FAIL("NULL retreiving \"%s\" pointer", name);

tag = fdt32_to_cpu(prop->tag);
nameoff = fdt32_to_cpu(prop->nameoff);
proplen = fdt32_to_cpu(prop->len);

if (tag != FDT_PROP)
FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name);

propname = fdt_string(fdt, nameoff);
if (!propname || !streq(propname, name))
FAIL("Property name mismatch \"%s\" instead of \"%s\"",
propname, name);
if (proplen != len)
FAIL("Size mismatch on property \"%s\": %d insead of %d",
name, proplen, len);
if (memcmp(val, prop->data, len) != 0)
FAIL("Data mismatch on property \"%s\"", name);
}

void *check_getprop(struct fdt_header *fdt, int nodeoffset, const char *name,
int len, const void *val)
{
void *propval;
int proplen;
int err;

propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if ((err = fdt_ptr_error(propval)))
FAIL("fdt_getprop(\"%s\"): %s", name, fdt_strerror(err));

if (proplen != len)
FAIL("Size mismatch on property \"%s\": %d insead of %d",
name, proplen, len);
if (memcmp(val, propval, len) != 0)
FAIL("Data mismatch on property \"%s\"", name);

return propval;
}

84
tests/trees.S

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
#include <fdt.h>
#include "testdata.h"

#define TREE_HDR(tree) \
.globl _##tree ; \
_##tree: \
tree: \
.long FDT_MAGIC ; \
.long tree##_end - tree ; \
.long tree##_struct - tree ; \
.long tree##_strings - tree ; \
.long tree##_rsvmap - tree ; \
.long 0x10 ; \
.long 0x10 ; \
.long 0 ; \
.long tree##_end - tree##_strings ;

#define RSVMAP_ENTRY(addr, len) \
.quad addr ; \
.quad len ;

#define PROPHDR(tree, name, len) \
.long FDT_PROP ; \
.long tree##_##name - tree##_strings ; \
.long len ;

#define PROP_INT(tree, name, val) \
PROPHDR(tree, name, 4) \
.long val

#define PROP_STR(tree, name, str) \
PROPHDR(tree, name, 55f - 54f) \
54: \
.string str ; \
55: \
.balign 4

#define BEGIN_NODE(name) \
.long FDT_BEGIN_NODE ; \
.string name ; \
.balign 4

#define END_NODE \
.long FDT_END_NODE ;

#define STRING(tree, name, str) \
tree##_##name: \
.string str
.data

TREE_HDR(test_tree1)

test_tree1_rsvmap:
RSVMAP_ENTRY(0, 0)

test_tree1_struct:
BEGIN_NODE("")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
PROP_STR(test_tree1, prop_str, TEST_STRING_1)
BEGIN_NODE("subnode1")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)

BEGIN_NODE("subsubnode")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
END_NODE
END_NODE

BEGIN_NODE("subnode2")
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)

BEGIN_NODE("subsubnode")
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
END_NODE
END_NODE

END_NODE
.long FDT_END

test_tree1_strings:
STRING(test_tree1, prop_int, "prop-int")
STRING(test_tree1, prop_str, "prop-str")
test_tree1_end:
Loading…
Cancel
Save