Import dtc 1.4.6

This commit is contained in:
Kyle Evans 2018-01-12 21:44:53 +00:00
parent f059bd1ebf
commit 2f36e4ecd0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/dtc/dist/; revision=327893
svn path=/vendor/dtc/1.4.6/; revision=327894; tag=vendor/dtc/1.4.6
78 changed files with 3140 additions and 435 deletions

View File

@ -674,4 +674,22 @@ The fdtdump program prints a readable version of a flat device tree file.
The syntax of the fdtdump command line is:
fdtdump <DTB-file-name>
fdtdump [options] <DTB-file-name>
Where options are:
-d,--debug Dump debug information while decoding the file
-s,--scan Scan for an embedded fdt in given file
3) fdtoverlay -- Flat Device Tree overlay applicator
The fdtoverlay applies an arbitrary number of FDT overlays to a base FDT blob
to a given output file.
The syntax of the fdtoverlay command line is:
fdtoverlay -i <base-blob> -o <output-blob> <overlay-blob0> [<overlay-blob1> ...]
Where options are:
-i, --input Input base DT blob
-o, --output Output DT blob
-v, --verbose Verbose message output

View File

@ -10,7 +10,7 @@
#
VERSION = 1
PATCHLEVEL = 4
SUBLEVEL = 3
SUBLEVEL = 6
EXTRAVERSION =
LOCAL_VERSION =
CONFIG_LOCALVERSION =
@ -18,10 +18,12 @@ CONFIG_LOCALVERSION =
CPPFLAGS = -I libfdt -I .
WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow
CFLAGS = -g -Os -fPIC -Werror $(WARNINGS)
CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS)
BISON = bison
LEX = flex
SWIG = swig
PKG_CONFIG ?= pkg-config
INSTALL = /usr/bin/install
DESTDIR =
@ -31,14 +33,20 @@ LIBDIR = $(PREFIX)/lib
INCLUDEDIR = $(PREFIX)/include
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')
sed -e 's/\(cygwin\|msys\).*/\1/')
ifeq ($(HOSTOS),darwin)
SHAREDLIB_EXT=dylib
SHAREDLIB_LINK_OPTIONS=-dynamiclib -Wl,-install_name -Wl,
SHAREDLIB_EXT = dylib
SHAREDLIB_CFLAGS = -fPIC
SHAREDLIB_LDFLAGS = -fPIC -dynamiclib -Wl,-install_name -Wl,
else ifeq ($(HOSTOS),$(filter $(HOSTOS),msys cygwin))
SHAREDLIB_EXT = so
SHAREDLIB_CFLAGS =
SHAREDLIB_LDFLAGS = -shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
else
SHAREDLIB_EXT=so
SHAREDLIB_LINK_OPTIONS=-shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
SHAREDLIB_EXT = so
SHAREDLIB_CFLAGS = -fPIC
SHAREDLIB_LDFLAGS = -fPIC -shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
endif
#
@ -112,11 +120,30 @@ BIN += dtc
BIN += fdtdump
BIN += fdtget
BIN += fdtput
BIN += fdtoverlay
SCRIPTS = dtdiff
all: $(BIN) libfdt
# We need both Python and swig to build pylibfdt.
.PHONY: maybe_pylibfdt
maybe_pylibfdt: FORCE
if $(PKG_CONFIG) --cflags python2 >/dev/null 2>&1; then \
if which swig >/dev/null 2>&1; then \
can_build=yes; \
fi; \
fi; \
if [ "$$can_build" = "yes" ]; then \
$(MAKE) pylibfdt; \
else \
echo "## Skipping pylibfdt (install python dev and swig to build)"; \
fi
ifeq ($(NO_PYTHON),)
all: maybe_pylibfdt
endif
ifneq ($(DEPTARGETS),)
-include $(DTC_OBJS:%.o=%.d)
@ -124,6 +151,7 @@ ifneq ($(DEPTARGETS),)
-include $(FDTDUMP_OBJS:%.o=%.d)
-include $(FDTGET_OBJS:%.o=%.d)
-include $(FDTPUT_OBJS:%.o=%.d)
-include $(FDTOVERLAY_OBJS:%.o=%.d)
endif
@ -180,6 +208,10 @@ install-includes:
install: install-bin install-lib install-includes
ifeq ($(NO_PYTHON),)
install: install_pylibfdt
endif
$(VERSION_FILE): Makefile FORCE
$(call filechk,version)
@ -196,12 +228,30 @@ fdtget: $(FDTGET_OBJS) $(LIBFDT_archive)
fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive)
fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_archive)
dist:
git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \
> ../dtc-$(dtc_version).tar
cat ../dtc-$(dtc_version).tar | \
gzip -9 > ../dtc-$(dtc_version).tar.gz
#
# Rules for pylibfdt
#
PYLIBFDT_srcdir = pylibfdt
PYLIBFDT_objdir = pylibfdt
include $(PYLIBFDT_srcdir)/Makefile.pylibfdt
.PHONY: pylibfdt
pylibfdt: $(PYLIBFDT_objdir)/_libfdt.so
pylibfdt_clean:
@$(VECHO) CLEAN "(pylibfdt)"
rm -f $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles))
#
# Release signing and uploading
# This is for maintainer convenience, don't try this at home.
@ -234,6 +284,10 @@ TESTS_BIN += convert-dtsv0
TESTS_BIN += fdtput
TESTS_BIN += fdtget
TESTS_BIN += fdtdump
TESTS_BIN += fdtoverlay
ifeq ($(NO_PYTHON),)
TESTS_PYLIBFDT += maybe_pylibfdt
endif
include tests/Makefile.tests
@ -243,7 +297,7 @@ include tests/Makefile.tests
STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \
*.tab.[ch] *.lex.c *.output
clean: libfdt_clean tests_clean
clean: libfdt_clean pylibfdt_clean tests_clean
@$(VECHO) CLEAN
rm -f $(STD_CLEANFILES)
rm -f $(VERSION_FILE)
@ -287,7 +341,7 @@ clean: libfdt_clean tests_clean
$(LIBFDT_lib):
@$(VECHO) LD $@
$(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
$(CC) $(LDFLAGS) $(SHAREDLIB_LDFLAGS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
%.lex.c: %.l
@$(VECHO) LEX $@

View File

@ -22,3 +22,9 @@ FDTPUT_SRCS = \
util.c
FDTPUT_OBJS = $(FDTPUT_SRCS:%.c=%.o)
FDTOVERLAY_SRCS = \
fdtoverlay.c \
util.c
FDTOVERLAY_OBJS = $(FDTOVERLAY_SRCS:%.c=%.o)

77
README
View File

@ -7,6 +7,83 @@ DTC and LIBFDT are maintained by:
David Gibson <david@gibson.dropbear.id.au>
Jon Loeliger <jdl@jdl.com>
Python library
--------------
A Python library is also available. To build this you will need to install
swig and Python development files. On Debian distributions:
sudo apt-get install swig python-dev
The library provides an Fdt class which you can use like this:
$ PYTHONPATH=../pylibfdt python
>>> import libfdt
>>> fdt = libfdt.Fdt(open('test_tree1.dtb').read())
>>> node = fdt.path_offset('/subnode@1')
>>> print node
124
>>> prop_offset = fdt.first_property_offset(node)
>>> prop = fdt.get_property_by_offset(prop_offset)
>>> print '%s=%r' % (prop.name, prop.value)
compatible=bytearray(b'subnode1\x00')
>>> print '%s=%s' % (prop.name, prop.value)
compatible=subnode1
>>> node2 = fdt.path_offset('/')
>>> print fdt.getprop(node2, 'compatible')
test_tree1
You will find tests in tests/pylibfdt_tests.py showing how to use each
method. Help is available using the Python help command, e.g.:
$ cd pylibfdt
$ python -c "import libfdt; help(libfdt)"
If you add new features, please check code coverage:
$ sudo apt-get install python-pip python-pytest
$ sudo pip install coverage
$ cd tests
$ coverage run pylibfdt_tests.py
$ coverage html
# Open 'htmlcov/index.html' in your browser
To install the library via the normal setup.py method, use:
./pylibfdt/setup.py [--prefix=/path/to/install_dir]
If --prefix is not provided, the default prefix is used, typically '/usr'
or '/usr/local'. See Python's distutils documentation for details. You can
also install via the Makefile if you like, but the above is more common.
To install both libfdt and pylibfdt you can use:
make install [SETUP_PREFIX=/path/to/install_dir] \
[PREFIX=/path/to/install_dir]
To disable building the python library, even if swig and Python are available,
use:
make NO_PYTHON=1
More work remains to support all of libfdt, including access to numeric
values.
Tests
-----
Test files are kept in the tests/ directory. Use 'make check' to build and run
all tests.
If you want to adjust a test file, be aware that tree_tree1.dts is compiled
and checked against a binary tree from assembler macros in trees.S. So
if you change that file you must change tree.S also.
Mailing list
------------
The following list is for discussion about dtc and libfdt implementation

717
checks.c
View File

@ -53,31 +53,27 @@ struct check {
struct check **prereq;
};
#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \
static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \
static struct check _nm = { \
.name = #_nm, \
.fn = (_fn), \
.data = (_d), \
.warn = (_w), \
.error = (_e), \
#define CHECK_ENTRY(nm_, fn_, d_, w_, e_, ...) \
static struct check *nm_##_prereqs[] = { __VA_ARGS__ }; \
static struct check nm_ = { \
.name = #nm_, \
.fn = (fn_), \
.data = (d_), \
.warn = (w_), \
.error = (e_), \
.status = UNCHECKED, \
.num_prereqs = ARRAY_SIZE(_nm##_prereqs), \
.prereq = _nm##_prereqs, \
.num_prereqs = ARRAY_SIZE(nm_##_prereqs), \
.prereq = nm_##_prereqs, \
};
#define WARNING(_nm, _fn, _d, ...) \
CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__)
#define ERROR(_nm, _fn, _d, ...) \
CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__)
#define CHECK(_nm, _fn, _d, ...) \
CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__)
#define WARNING(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, true, false, __VA_ARGS__)
#define ERROR(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, false, true, __VA_ARGS__)
#define CHECK(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, false, false, __VA_ARGS__)
#ifdef __GNUC__
static inline void check_msg(struct check *c, struct dt_info *dti,
const char *fmt, ...) __attribute__((format (printf, 3, 4)));
#endif
static inline void check_msg(struct check *c, struct dt_info *dti,
const char *fmt, ...)
static inline void PRINTF(3, 4) check_msg(struct check *c, struct dt_info *dti,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
@ -183,6 +179,36 @@ static void check_is_string(struct check *c, struct dt_info *dti,
#define ERROR_IF_NOT_STRING(nm, propname) \
ERROR(nm, check_is_string, (propname))
static void check_is_string_list(struct check *c, struct dt_info *dti,
struct node *node)
{
int rem, l;
struct property *prop;
char *propname = c->data;
char *str;
prop = get_property(node, propname);
if (!prop)
return; /* Not present, assumed ok */
str = prop->val.val;
rem = prop->val.len;
while (rem > 0) {
l = strnlen(str, rem);
if (l == rem) {
FAIL(c, dti, "\"%s\" property in %s is not a string list",
propname, node->fullpath);
break;
}
rem -= l + 1;
str += l + 1;
}
}
#define WARNING_IF_NOT_STRING_LIST(nm, propname) \
WARNING(nm, check_is_string_list, (propname))
#define ERROR_IF_NOT_STRING_LIST(nm, propname) \
ERROR(nm, check_is_string_list, (propname))
static void check_is_cell(struct check *c, struct dt_info *dti,
struct node *node)
{
@ -538,13 +564,13 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
FAIL(c, dti, "Reference to non-existent node or "
"label \"%s\"\n", m->ref);
else /* mark the entry as unresolved */
*((cell_t *)(prop->val.val + m->offset)) =
*((fdt32_t *)(prop->val.val + m->offset)) =
cpu_to_fdt32(0xffffffff);
continue;
}
phandle = get_node_phandle(dt, refnode);
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
*((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
}
}
}
@ -590,6 +616,47 @@ WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
WARNING_IF_NOT_STRING(model_is_string, "model");
WARNING_IF_NOT_STRING(status_is_string, "status");
WARNING_IF_NOT_STRING(label_is_string, "label");
WARNING_IF_NOT_STRING_LIST(compatible_is_string_list, "compatible");
static void check_names_is_string_list(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
for_each_property(node, prop) {
const char *s = strrchr(prop->name, '-');
if (!s || !streq(s, "-names"))
continue;
c->data = prop->name;
check_is_string_list(c, dti, node);
}
}
WARNING(names_is_string_list, check_names_is_string_list, NULL);
static void check_alias_paths(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
if (!streq(node->name, "aliases"))
return;
for_each_property(node, prop) {
if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) {
FAIL(c, dti, "aliases property '%s' is not a valid node (%s)",
prop->name, prop->val.val);
continue;
}
if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name))
FAIL(c, dti, "aliases property name '%s' is not valid",
prop->name);
}
}
WARNING(alias_paths, check_alias_paths, NULL);
static void fixup_addr_size_cells(struct check *c, struct dt_info *dti,
struct node *node)
@ -685,6 +752,229 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
}
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
static const struct bus_type pci_bus = {
.name = "PCI",
};
static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node *node)
{
struct property *prop;
cell_t *cells;
prop = get_property(node, "device_type");
if (!prop || !streq(prop->val.val, "pci"))
return;
node->bus = &pci_bus;
if (!strprefixeq(node->name, node->basenamelen, "pci") &&
!strprefixeq(node->name, node->basenamelen, "pcie"))
FAIL(c, dti, "Node %s node name is not \"pci\" or \"pcie\"",
node->fullpath);
prop = get_property(node, "ranges");
if (!prop)
FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)",
node->fullpath);
if (node_addr_cells(node) != 3)
FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge",
node->fullpath);
if (node_size_cells(node) != 2)
FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge",
node->fullpath);
prop = get_property(node, "bus-range");
if (!prop) {
FAIL(c, dti, "Node %s missing bus-range for PCI bridge",
node->fullpath);
return;
}
if (prop->val.len != (sizeof(cell_t) * 2)) {
FAIL(c, dti, "Node %s bus-range must be 2 cells",
node->fullpath);
return;
}
cells = (cell_t *)prop->val.val;
if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1]))
FAIL(c, dti, "Node %s bus-range 1st cell must be less than or equal to 2nd cell",
node->fullpath);
if (fdt32_to_cpu(cells[1]) > 0xff)
FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256",
node->fullpath);
}
WARNING(pci_bridge, check_pci_bridge, NULL,
&device_type_is_string, &addr_size_cells);
static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node)
{
struct property *prop;
unsigned int bus_num, min_bus, max_bus;
cell_t *cells;
if (!node->parent || (node->parent->bus != &pci_bus))
return;
prop = get_property(node, "reg");
if (!prop)
return;
cells = (cell_t *)prop->val.val;
bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16;
prop = get_property(node->parent, "bus-range");
if (!prop) {
min_bus = max_bus = 0;
} else {
cells = (cell_t *)prop->val.val;
min_bus = fdt32_to_cpu(cells[0]);
max_bus = fdt32_to_cpu(cells[0]);
}
if ((bus_num < min_bus) || (bus_num > max_bus))
FAIL(c, dti, "Node %s PCI bus number %d out of range, expected (%d - %d)",
node->fullpath, bus_num, min_bus, max_bus);
}
WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, &reg_format, &pci_bridge);
static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node)
{
struct property *prop;
const char *unitname = get_unitname(node);
char unit_addr[5];
unsigned int dev, func, reg;
cell_t *cells;
if (!node->parent || (node->parent->bus != &pci_bus))
return;
prop = get_property(node, "reg");
if (!prop) {
FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath);
return;
}
cells = (cell_t *)prop->val.val;
if (cells[1] || cells[2])
FAIL(c, dti, "Node %s PCI reg config space address cells 2 and 3 must be 0",
node->fullpath);
reg = fdt32_to_cpu(cells[0]);
dev = (reg & 0xf800) >> 11;
func = (reg & 0x700) >> 8;
if (reg & 0xff000000)
FAIL(c, dti, "Node %s PCI reg address is not configuration space",
node->fullpath);
if (reg & 0x000000ff)
FAIL(c, dti, "Node %s PCI reg config space address register number must be 0",
node->fullpath);
if (func == 0) {
snprintf(unit_addr, sizeof(unit_addr), "%x", dev);
if (streq(unitname, unit_addr))
return;
}
snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func);
if (streq(unitname, unit_addr))
return;
FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"",
node->fullpath, unit_addr);
}
WARNING(pci_device_reg, check_pci_device_reg, NULL, &reg_format, &pci_bridge);
static const struct bus_type simple_bus = {
.name = "simple-bus",
};
static bool node_is_compatible(struct node *node, const char *compat)
{
struct property *prop;
const char *str, *end;
prop = get_property(node, "compatible");
if (!prop)
return false;
for (str = prop->val.val, end = str + prop->val.len; str < end;
str += strnlen(str, end - str) + 1) {
if (strprefixeq(str, end - str, compat))
return true;
}
return false;
}
static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
{
if (node_is_compatible(node, "simple-bus"))
node->bus = &simple_bus;
}
WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
{
struct property *prop;
const char *unitname = get_unitname(node);
char unit_addr[17];
unsigned int size;
uint64_t reg = 0;
cell_t *cells = NULL;
if (!node->parent || (node->parent->bus != &simple_bus))
return;
prop = get_property(node, "reg");
if (prop)
cells = (cell_t *)prop->val.val;
else {
prop = get_property(node, "ranges");
if (prop && prop->val.len)
/* skip of child address */
cells = ((cell_t *)prop->val.val) + node_addr_cells(node);
}
if (!cells) {
if (node->parent->parent && !(node->bus == &simple_bus))
FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath);
return;
}
size = node_addr_cells(node->parent);
while (size--)
reg = (reg << 32) | fdt32_to_cpu(*(cells++));
snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg);
if (!streq(unitname, unit_addr))
FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"",
node->fullpath, unit_addr);
}
WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_format, &simple_bus_bridge);
static void check_unit_address_format(struct check *c, struct dt_info *dti,
struct node *node)
{
const char *unitname = get_unitname(node);
if (node->parent && node->parent->bus)
return;
if (!unitname[0])
return;
if (!strncmp(unitname, "0x", 2)) {
FAIL(c, dti, "Node %s unit name should not have leading \"0x\"",
node->fullpath);
/* skip over 0x for next test */
unitname += 2;
}
if (unitname[0] == '0' && isxdigit(unitname[1]))
FAIL(c, dti, "Node %s unit name should not have leading 0s",
node->fullpath);
}
WARNING(unit_address_format, check_unit_address_format, NULL,
&node_name_format, &pci_bridge, &simple_bus_bridge);
/*
* Style checks
*/
@ -713,6 +1003,31 @@ static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti,
WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
&addr_size_cells);
static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
struct node *child;
bool has_reg = false;
if (!node->parent || node->addr_cells < 0 || node->size_cells < 0)
return;
if (get_property(node, "ranges") || !node->children)
return;
for_each_child(node, child) {
prop = get_property(child, "reg");
if (prop)
has_reg = true;
}
if (!has_reg)
FAIL(c, dti, "unnecessary #address-cells/#size-cells without \"ranges\" or child \"reg\" property in %s",
node->fullpath);
}
WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size);
static void check_obsolete_chosen_interrupt_controller(struct check *c,
struct dt_info *dti,
struct node *node)
@ -737,6 +1052,324 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
WARNING(obsolete_chosen_interrupt_controller,
check_obsolete_chosen_interrupt_controller, NULL);
static void check_chosen_node_is_root(struct check *c, struct dt_info *dti,
struct node *node)
{
if (!streq(node->name, "chosen"))
return;
if (node->parent != dti->dt)
FAIL(c, dti, "chosen node '%s' must be at root node",
node->fullpath);
}
WARNING(chosen_node_is_root, check_chosen_node_is_root, NULL);
static void check_chosen_node_bootargs(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
if (!streq(node->name, "chosen"))
return;
prop = get_property(node, "bootargs");
if (!prop)
return;
c->data = prop->name;
check_is_string(c, dti, node);
}
WARNING(chosen_node_bootargs, check_chosen_node_bootargs, NULL);
static void check_chosen_node_stdout_path(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
if (!streq(node->name, "chosen"))
return;
prop = get_property(node, "stdout-path");
if (!prop) {
prop = get_property(node, "linux,stdout-path");
if (!prop)
return;
FAIL(c, dti, "Use 'stdout-path' instead of 'linux,stdout-path'");
}
c->data = prop->name;
check_is_string(c, dti, node);
}
WARNING(chosen_node_stdout_path, check_chosen_node_stdout_path, NULL);
struct provider {
const char *prop_name;
const char *cell_name;
bool optional;
};
static void check_property_phandle_args(struct check *c,
struct dt_info *dti,
struct node *node,
struct property *prop,
const struct provider *provider)
{
struct node *root = dti->dt;
int cell, cellsize = 0;
if (prop->val.len % sizeof(cell_t)) {
FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s",
prop->name, prop->val.len, sizeof(cell_t), node->fullpath);
return;
}
for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) {
struct node *provider_node;
struct property *cellprop;
int phandle;
phandle = propval_cell_n(prop, cell);
/*
* Some bindings use a cell value 0 or -1 to skip over optional
* entries when each index position has a specific definition.
*/
if (phandle == 0 || phandle == -1) {
/* Give up if this is an overlay with external references */
if (dti->dtsflags & DTSF_PLUGIN)
break;
cellsize = 0;
continue;
}
/* If we have markers, verify the current cell is a phandle */
if (prop->val.markers) {
struct marker *m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
if (m->offset == (cell * sizeof(cell_t)))
break;
}
if (!m)
FAIL(c, dti, "Property '%s', cell %d is not a phandle reference in %s",
prop->name, cell, node->fullpath);
}
provider_node = get_node_by_phandle(root, phandle);
if (!provider_node) {
FAIL(c, dti, "Could not get phandle node for %s:%s(cell %d)",
node->fullpath, prop->name, cell);
break;
}
cellprop = get_property(provider_node, provider->cell_name);
if (cellprop) {
cellsize = propval_cell(cellprop);
} else if (provider->optional) {
cellsize = 0;
} else {
FAIL(c, dti, "Missing property '%s' in node %s or bad phandle (referred from %s:%s[%d])",
provider->cell_name,
provider_node->fullpath,
node->fullpath, prop->name, cell);
break;
}
if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) {
FAIL(c, dti, "%s property size (%d) too small for cell size %d in %s",
prop->name, prop->val.len, cellsize, node->fullpath);
}
}
}
static void check_provider_cells_property(struct check *c,
struct dt_info *dti,
struct node *node)
{
struct provider *provider = c->data;
struct property *prop;
prop = get_property(node, provider->prop_name);
if (!prop)
return;
check_property_phandle_args(c, dti, node, prop, provider);
}
#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references);
WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells");
WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells");
WARNING_PROPERTY_PHANDLE_CELLS(dmas, "dmas", "#dma-cells");
WARNING_PROPERTY_PHANDLE_CELLS(hwlocks, "hwlocks", "#hwlock-cells");
WARNING_PROPERTY_PHANDLE_CELLS(interrupts_extended, "interrupts-extended", "#interrupt-cells");
WARNING_PROPERTY_PHANDLE_CELLS(io_channels, "io-channels", "#io-channel-cells");
WARNING_PROPERTY_PHANDLE_CELLS(iommus, "iommus", "#iommu-cells");
WARNING_PROPERTY_PHANDLE_CELLS(mboxes, "mboxes", "#mbox-cells");
WARNING_PROPERTY_PHANDLE_CELLS(msi_parent, "msi-parent", "#msi-cells", true);
WARNING_PROPERTY_PHANDLE_CELLS(mux_controls, "mux-controls", "#mux-control-cells");
WARNING_PROPERTY_PHANDLE_CELLS(phys, "phys", "#phy-cells");
WARNING_PROPERTY_PHANDLE_CELLS(power_domains, "power-domains", "#power-domain-cells");
WARNING_PROPERTY_PHANDLE_CELLS(pwms, "pwms", "#pwm-cells");
WARNING_PROPERTY_PHANDLE_CELLS(resets, "resets", "#reset-cells");
WARNING_PROPERTY_PHANDLE_CELLS(sound_dai, "sound-dai", "#sound-dai-cells");
WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sensor-cells");
static bool prop_is_gpio(struct property *prop)
{
char *str;
/*
* *-gpios and *-gpio can appear in property names,
* so skip over any false matches (only one known ATM)
*/
if (strstr(prop->name, "nr-gpio"))
return false;
str = strrchr(prop->name, '-');
if (str)
str++;
else
str = prop->name;
if (!(streq(str, "gpios") || streq(str, "gpio")))
return false;
return true;
}
static void check_gpios_property(struct check *c,
struct dt_info *dti,
struct node *node)
{
struct property *prop;
/* Skip GPIO hog nodes which have 'gpios' property */
if (get_property(node, "gpio-hog"))
return;
for_each_property(node, prop) {
struct provider provider;
if (!prop_is_gpio(prop))
continue;
provider.prop_name = prop->name;
provider.cell_name = "#gpio-cells";
provider.optional = false;
check_property_phandle_args(c, dti, node, prop, &provider);
}
}
WARNING(gpios_property, check_gpios_property, NULL, &phandle_references);
static void check_deprecated_gpio_property(struct check *c,
struct dt_info *dti,
struct node *node)
{
struct property *prop;
for_each_property(node, prop) {
char *str;
if (!prop_is_gpio(prop))
continue;
str = strstr(prop->name, "gpio");
if (!streq(str, "gpio"))
continue;
FAIL(c, dti, "'[*-]gpio' is deprecated, use '[*-]gpios' instead for %s:%s",
node->fullpath, prop->name);
}
}
CHECK(deprecated_gpio_property, check_deprecated_gpio_property, NULL);
static bool node_is_interrupt_provider(struct node *node)
{
struct property *prop;
prop = get_property(node, "interrupt-controller");
if (prop)
return true;
prop = get_property(node, "interrupt-map");
if (prop)
return true;
return false;
}
static void check_interrupts_property(struct check *c,
struct dt_info *dti,
struct node *node)
{
struct node *root = dti->dt;
struct node *irq_node = NULL, *parent = node;
struct property *irq_prop, *prop = NULL;
int irq_cells, phandle;
irq_prop = get_property(node, "interrupts");
if (!irq_prop)
return;
if (irq_prop->val.len % sizeof(cell_t))
FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s",
irq_prop->name, irq_prop->val.len, sizeof(cell_t),
node->fullpath);
while (parent && !prop) {
if (parent != node && node_is_interrupt_provider(parent)) {
irq_node = parent;
break;
}
prop = get_property(parent, "interrupt-parent");
if (prop) {
phandle = propval_cell(prop);
/* Give up if this is an overlay with external references */
if ((phandle == 0 || phandle == -1) &&
(dti->dtsflags & DTSF_PLUGIN))
return;
irq_node = get_node_by_phandle(root, phandle);
if (!irq_node) {
FAIL(c, dti, "Bad interrupt-parent phandle for %s",
node->fullpath);
return;
}
if (!node_is_interrupt_provider(irq_node))
FAIL(c, dti,
"Missing interrupt-controller or interrupt-map property in %s",
irq_node->fullpath);
break;
}
parent = parent->parent;
}
if (!irq_node) {
FAIL(c, dti, "Missing interrupt-parent for %s", node->fullpath);
return;
}
prop = get_property(irq_node, "#interrupt-cells");
if (!prop) {
FAIL(c, dti, "Missing #interrupt-cells in interrupt-parent %s",
irq_node->fullpath);
return;
}
irq_cells = propval_cell(prop);
if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) {
FAIL(c, dti,
"interrupts size is (%d), expected multiple of %d in %s",
irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)),
node->fullpath);
}
}
WARNING(interrupts_property, check_interrupts_property, &phandle_references);
static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
&node_name_chars, &node_name_format, &property_name_chars,
@ -749,6 +1382,9 @@ static struct check *check_table[] = {
&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
&device_type_is_string, &model_is_string, &status_is_string,
&label_is_string,
&compatible_is_string_list, &names_is_string_list,
&property_name_chars_strict,
&node_name_chars_strict,
@ -756,9 +1392,42 @@ static struct check *check_table[] = {
&addr_size_cells, &reg_format, &ranges_format,
&unit_address_vs_reg,
&unit_address_format,
&pci_bridge,
&pci_device_reg,
&pci_device_bus_num,
&simple_bus_bridge,
&simple_bus_reg,
&avoid_default_addr_size,
&avoid_unnecessary_addr_size,
&obsolete_chosen_interrupt_controller,
&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
&clocks_property,
&cooling_device_property,
&dmas_property,
&hwlocks_property,
&interrupts_extended_property,
&io_channels_property,
&iommus_property,
&mboxes_property,
&msi_parent_property,
&mux_controls_property,
&phys_property,
&power_domains_property,
&pwms_property,
&resets_property,
&sound_dai_property,
&thermal_sensors_property,
&deprecated_gpio_property,
&gpios_property,
&interrupts_property,
&alias_paths,
&always_fail,
};

View File

@ -49,7 +49,7 @@ static int saw_hyphen; /* = 0 */
static unsigned long long last_val;
static char *last_name; /* = NULL */
const struct {
static const struct {
const char *pattern;
int obase, width;
} guess_table[] = {

16
data.c
View File

@ -171,9 +171,9 @@ struct data data_merge(struct data d1, struct data d2)
struct data data_append_integer(struct data d, uint64_t value, int bits)
{
uint8_t value_8;
uint16_t value_16;
uint32_t value_32;
uint64_t value_64;
fdt16_t value_16;
fdt32_t value_32;
fdt64_t value_64;
switch (bits) {
case 8:
@ -197,14 +197,14 @@ struct data data_append_integer(struct data d, uint64_t value, int bits)
}
}
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
struct data data_append_re(struct data d, uint64_t address, uint64_t size)
{
struct fdt_reserve_entry bere;
struct fdt_reserve_entry re;
bere.address = cpu_to_fdt64(re->address);
bere.size = cpu_to_fdt64(re->size);
re.address = cpu_to_fdt64(address);
re.size = cpu_to_fdt64(size);
return data_append_data(d, &bere, sizeof(bere));
return data_append_data(d, &re, sizeof(re));
}
struct data data_append_cell(struct data d, cell_t word)

View File

@ -62,12 +62,7 @@ static int dts_version = 1;
static void push_input_file(const char *filename);
static bool pop_input_file(void);
#ifdef __GNUC__
static void lexical_error(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
#else
static void lexical_error(const char *fmt, ...);
#endif
static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
%}

View File

@ -166,7 +166,17 @@ devicetree:
{
$$ = merge_nodes($1, $3);
}
| DT_REF nodedef
{
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if (!($<flags>-1 & DTSF_PLUGIN))
ERROR(&@2, "Label or path %s not found", $1);
$$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
}
| devicetree DT_LABEL DT_REF nodedef
{
struct node *target = get_node_by_ref($1, $3);
@ -182,10 +192,19 @@ devicetree:
{
struct node *target = get_node_by_ref($1, $2);
if (target)
if (target) {
merge_nodes(target, $3);
else
ERROR(&@2, "Label or path %s not found", $2);
} else {
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if ($<flags>-1 & DTSF_PLUGIN)
add_orphan_node($1, $3, $2);
else
ERROR(&@2, "Label or path %s not found", $2);
}
$$ = $1;
}
| devicetree DT_DEL_NODE DT_REF ';'

14
dtc.c
View File

@ -31,7 +31,7 @@ int reservenum; /* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob accroding to the alignsize */
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */
int generate_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */
@ -59,8 +59,6 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
}
/* Usage related data. */
#define FDT_VERSION(version) _FDT_VERSION(version)
#define _FDT_VERSION(version) #version
static const char usage_synopsis[] = "dtc [options] <input file>";
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
static struct option const usage_long_opts[] = {
@ -98,7 +96,7 @@ static const char * const usage_opts_help[] = {
"\t\tdts - device tree source text\n"
"\t\tdtb - device tree blob\n"
"\t\tasm - assembler source",
"\n\tBlob version to produce, defaults to "FDT_VERSION(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tOutput dependency file",
"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
"\n\tMake the blob at least <bytes> long (extra space)",
@ -138,7 +136,7 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
static const char *guess_input_format(const char *fname, const char *fallback)
{
struct stat statbuf;
uint32_t magic;
fdt32_t magic;
FILE *f;
if (stat(fname, &statbuf) != 0)
@ -159,8 +157,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
}
fclose(f);
magic = fdt32_to_cpu(magic);
if (magic == FDT_MAGIC)
if (fdt32_to_cpu(magic) == FDT_MAGIC)
return "dtb";
return guess_type_by_name(fname, fallback);
@ -320,13 +317,14 @@ int main(int argc, char *argv[])
dti->boot_cpuid_phys = cmdline_boot_cpuid;
fill_fullpaths(dti->dt, "");
process_checks(force, dti);
/* on a plugin, generate by default */
if (dti->dtsflags & DTSF_PLUGIN) {
generate_fixups = 1;
}
process_checks(force, dti);
if (auto_label_aliases)
generate_label_tree(dti, "aliases", false);

22
dtc.h
View File

@ -1,5 +1,5 @@
#ifndef _DTC_H
#define _DTC_H
#ifndef DTC_H
#define DTC_H
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
@ -31,6 +31,7 @@
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#include <libfdt_env.h>
#include <fdt.h>
@ -43,7 +44,6 @@
#define debug(...)
#endif
#define DEFAULT_FDT_VERSION 17
/*
@ -67,7 +67,8 @@ typedef uint32_t cell_t;
#define streq(a, b) (strcmp((a), (b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
#define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0))
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
@ -114,7 +115,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
struct data data_merge(struct data d1, struct data d2);
struct data data_append_cell(struct data d, cell_t word);
struct data data_append_integer(struct data d, uint64_t word, int bits);
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
struct data data_append_re(struct data d, uint64_t address, uint64_t size);
struct data data_append_addr(struct data d, uint64_t addr);
struct data data_append_byte(struct data d, uint8_t byte);
struct data data_append_zeroes(struct data d, int len);
@ -136,6 +137,10 @@ struct label {
struct label *next;
};
struct bus_type {
const char *name;
};
struct property {
bool deleted;
char *name;
@ -162,6 +167,7 @@ struct node {
int addr_cells, size_cells;
struct label *labels;
const struct bus_type *bus;
};
#define for_each_label_withdel(l0, l) \
@ -198,6 +204,7 @@ struct node *build_node_delete(void);
struct node *name_node(struct node *node, char *name);
struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);
struct node *add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
void add_property(struct node *node, struct property *prop);
void delete_property_by_name(struct node *node, char *name);
@ -211,6 +218,7 @@ void append_to_property(struct node *node,
const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
cell_t propval_cell(struct property *prop);
cell_t propval_cell_n(struct property *prop, int n);
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node);
struct marker *get_marker_label(struct node *tree, const char *label,
@ -227,7 +235,7 @@ uint32_t guess_boot_cpuid(struct node *tree);
/* Boot info (tree plus memreserve information */
struct reserve_info {
struct fdt_reserve_entry re;
uint64_t address, size;
struct reserve_info *next;
@ -282,4 +290,4 @@ struct dt_info *dt_from_source(const char *f);
struct dt_info *dt_from_fs(const char *dirname);
#endif /* _DTC_H */
#endif /* DTC_H */

View File

@ -20,7 +20,7 @@
#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, *((const uint32_t *)(p-4)))
#define GET_CELL(p) (p += 4, *((const fdt32_t *)(p-4)))
static const char *tagname(uint32_t tag)
{
@ -165,7 +165,7 @@ static bool valid_header(char *p, off_t len)
if (len < sizeof(struct fdt_header) ||
fdt_magic(p) != FDT_MAGIC ||
fdt_version(p) > MAX_VERSION ||
fdt_last_comp_version(p) >= MAX_VERSION ||
fdt_last_comp_version(p) > MAX_VERSION ||
fdt_totalsize(p) >= len ||
fdt_off_dt_struct(p) >= len ||
fdt_off_dt_strings(p) >= len)
@ -183,6 +183,11 @@ int main(int argc, char *argv[])
bool scan = false;
off_t len;
fprintf(stderr, "\n"
"**** fdtdump is a low-level debugging tool, not meant for general use.\n"
"**** If you want to decompile a dtb, you probably want\n"
"**** dtc -I dtb -O dts <filename>\n\n"
);
while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
case_USAGE_COMMON_FLAGS

View File

@ -53,6 +53,37 @@ static void report_error(const char *where, int err)
fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
}
/**
* Shows a list of cells in the requested format
*
* @param disp Display information / options
* @param data Data to display
* @param len Maximum length of buffer
* @param size Data size to use for display (e.g. 4 for 32-bit)
* @return 0 if ok, -1 on error
*/
static int show_cell_list(struct display_info *disp, const char *data, int len,
int size)
{
const uint8_t *p = (const uint8_t *)data;
char fmt[3];
int value;
int i;
fmt[0] = '%';
fmt[1] = disp->type ? disp->type : 'd';
fmt[2] = '\0';
for (i = 0; i < len; i += size, p += size) {
if (i)
printf(" ");
value = size == 4 ? fdt32_to_cpu(*(const fdt32_t *)p) :
size == 2 ? (*p << 8) | p[1] : *p;
printf(fmt, value);
}
return 0;
}
/**
* Displays data of a given length according to selected options
*
@ -66,12 +97,9 @@ static void report_error(const char *where, int err)
*/
static int show_data(struct display_info *disp, const char *data, int len)
{
int i, size;
const uint8_t *p = (const uint8_t *)data;
int size;
const char *s;
int value;
int is_string;
char fmt[3];
/* no data, don't print */
if (len == 0)
@ -99,17 +127,8 @@ static int show_data(struct display_info *disp, const char *data, int len)
"selected data size\n");
return -1;
}
fmt[0] = '%';
fmt[1] = disp->type ? disp->type : 'd';
fmt[2] = '\0';
for (i = 0; i < len; i += size, p += size) {
if (i)
printf(" ");
value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
size == 2 ? (*p << 8) | p[1] : *p;
printf(fmt, value);
}
return 0;
return show_cell_list(disp, data, len, size);
}
/**
@ -245,7 +264,7 @@ static int show_data_for_item(const void *blob, struct display_info *disp,
* @param filename Filename of blob file
* @param arg List of arguments to process
* @param arg_count Number of arguments
* @param return 0 if ok, -ve on error
* @return 0 if ok, -ve on error
*/
static int do_fdtget(struct display_info *disp, const char *filename,
char **arg, int arg_count, int args_per_step)

175
fdtoverlay.c Normal file
View File

@ -0,0 +1,175 @@
/*
* Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
*
* Author:
* Pantelis Antoniou <pantelis.antoniou@konsulko.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <assert.h>
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <libfdt.h>
#include "util.h"
/* Usage related data. */
static const char usage_synopsis[] =
"apply a number of overlays to a base blob\n"
" fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]\n"
"\n"
USAGE_TYPE_MSG;
static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
static struct option const usage_long_opts[] = {
{"input", required_argument, NULL, 'i'},
{"output", required_argument, NULL, 'o'},
{"verbose", no_argument, NULL, 'v'},
USAGE_COMMON_LONG_OPTS,
};
static const char * const usage_opts_help[] = {
"Input base DT blob",
"Output DT blob",
"Verbose messages",
USAGE_COMMON_OPTS_HELP
};
int verbose = 0;
static int do_fdtoverlay(const char *input_filename,
const char *output_filename,
int argc, char *argv[])
{
char *blob = NULL;
char **ovblob = NULL;
off_t blob_len, ov_len, total_len;
int i, ret = -1;
blob = utilfdt_read_len(input_filename, &blob_len);
if (!blob) {
fprintf(stderr, "\nFailed to read base blob %s\n",
input_filename);
goto out_err;
}
if (fdt_totalsize(blob) > blob_len) {
fprintf(stderr,
"\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
(unsigned long)blob_len, fdt_totalsize(blob));
goto out_err;
}
ret = 0;
/* allocate blob pointer array */
ovblob = malloc(sizeof(*ovblob) * argc);
memset(ovblob, 0, sizeof(*ovblob) * argc);
/* read and keep track of the overlay blobs */
total_len = 0;
for (i = 0; i < argc; i++) {
ovblob[i] = utilfdt_read_len(argv[i], &ov_len);
if (!ovblob[i]) {
fprintf(stderr, "\nFailed to read overlay %s\n",
argv[i]);
goto out_err;
}
total_len += ov_len;
}
/* grow the blob to worst case */
blob_len = fdt_totalsize(blob) + total_len;
blob = xrealloc(blob, blob_len);
fdt_open_into(blob, blob, blob_len);
/* apply the overlays in sequence */
for (i = 0; i < argc; i++) {
ret = fdt_overlay_apply(blob, ovblob[i]);
if (ret) {
fprintf(stderr, "\nFailed to apply %s (%d)\n",
argv[i], ret);
goto out_err;
}
}
fdt_pack(blob);
ret = utilfdt_write(output_filename, blob);
if (ret)
fprintf(stderr, "\nFailed to write output blob %s\n",
output_filename);
out_err:
if (ovblob) {
for (i = 0; i < argc; i++) {
if (ovblob[i])
free(ovblob[i]);
}
free(ovblob);
}
free(blob);
return ret;
}
int main(int argc, char *argv[])
{
int opt, i;
char *input_filename = NULL;
char *output_filename = NULL;
while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
case_USAGE_COMMON_FLAGS
case 'i':
input_filename = optarg;
break;
case 'o':
output_filename = optarg;
break;
case 'v':
verbose = 1;
break;
}
}
if (!input_filename)
usage("missing input file");
if (!output_filename)
usage("missing output file");
argv += optind;
argc -= optind;
if (argc <= 0)
usage("missing overlay file(s)");
if (verbose) {
printf("input = %s\n", input_filename);
printf("output = %s\n", output_filename);
for (i = 0; i < argc; i++)
printf("overlay[%d] = %s\n", i, argv[i]);
}
if (do_fdtoverlay(input_filename, output_filename, argc, argv))
return 1;
return 0;
}

View File

@ -67,7 +67,7 @@ static void report_error(const char *name, int namelen, int err)
* @param arg List of arguments from command line
* @param arg_count Number of arguments (may be 0)
* @param valuep Returns buffer containing value
* @param *value_len Returns length of value encoded
* @param value_len Returns length of value encoded
*/
static int encode_value(struct display_info *disp, char **arg, int arg_count,
char **valuep, int *value_len)
@ -107,7 +107,7 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count,
if (disp->verbose)
fprintf(stderr, "\tstring: '%s'\n", ptr);
} else {
int *iptr = (int *)ptr;
fdt32_t *iptr = (fdt32_t *)ptr;
sscanf(*arg, fmt, &ival);
if (len == 4)
*iptr = cpu_to_fdt32(ival);
@ -130,7 +130,7 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count,
#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))
static char *_realloc_fdt(char *fdt, int delta)
static char *realloc_fdt(char *fdt, int delta)
{
int new_sz = fdt_totalsize(fdt) + delta;
fdt = xrealloc(fdt, new_sz);
@ -144,7 +144,7 @@ static char *realloc_node(char *fdt, const char *name)
/* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
+ FDT_TAGSIZE;
return _realloc_fdt(fdt, delta);
return realloc_fdt(fdt, delta);
}
static char *realloc_property(char *fdt, int nodeoffset,
@ -161,7 +161,7 @@ static char *realloc_property(char *fdt, int nodeoffset,
/* actual value in off_struct */
delta += ALIGN(newlen) - ALIGN(oldlen);
return _realloc_fdt(fdt, delta);
return realloc_fdt(fdt, delta);
}
static int store_key_value(char **blob, const char *node_name,

View File

@ -49,7 +49,7 @@ static struct version_info {
struct emitter {
void (*cell)(void *, cell_t);
void (*string)(void *, char *, int);
void (*string)(void *, const char *, int);
void (*align)(void *, int);
void (*data)(void *, struct data);
void (*beginnode)(void *, struct label *labels);
@ -64,7 +64,7 @@ static void bin_emit_cell(void *e, cell_t val)
*dtbuf = data_append_cell(*dtbuf, val);
}
static void bin_emit_string(void *e, char *str, int len)
static void bin_emit_string(void *e, const char *str, int len)
{
struct data *dtbuf = e;
@ -144,22 +144,14 @@ static void asm_emit_cell(void *e, cell_t val)
(val >> 8) & 0xff, val & 0xff);
}
static void asm_emit_string(void *e, char *str, int len)
static void asm_emit_string(void *e, const char *str, int len)
{
FILE *f = e;
char c = 0;
if (len != 0) {
/* XXX: ewww */
c = str[len];
str[len] = '\0';
}
fprintf(f, "\t.string\t\"%s\"\n", str);
if (len != 0) {
str[len] = c;
}
if (len != 0)
fprintf(f, "\t.string\t\"%.*s\"\n", len, str);
else
fprintf(f, "\t.string\t\"%s\"\n", str);
}
static void asm_emit_align(void *e, int a)
@ -179,7 +171,7 @@ static void asm_emit_data(void *e, struct data d)
emit_offset_label(f, m->ref, m->offset);
while ((d.len - off) >= sizeof(uint32_t)) {
asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off))));
off += sizeof(uint32_t);
}
@ -318,17 +310,16 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
{
struct reserve_info *re;
struct data d = empty_data;
static struct fdt_reserve_entry null_re = {0,0};
int j;
for (re = reservelist; re; re = re->next) {
d = data_append_re(d, &re->re);
d = data_append_re(d, re->address, re->size);
}
/*
* Add additional reserved slots if the user asked for them.
*/
for (j = 0; j < reservenum; j++) {
d = data_append_re(d, &null_re);
d = data_append_re(d, 0, 0);
}
return d;
@ -544,11 +535,11 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
fprintf(f, "\t.globl\t%s\n", l->label);
fprintf(f, "%s:\n", l->label);
}
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->address >> 32));
ASM_EMIT_BELONG(f, "0x%08x",
(unsigned int)(re->re.address & 0xffffffff));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
(unsigned int)(re->address & 0xffffffff));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size >> 32));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size & 0xffffffff));
}
for (i = 0; i < reservenum; i++) {
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
@ -609,7 +600,7 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)
static uint32_t flat_read_word(struct inbuf *inb)
{
uint32_t val;
fdt32_t val;
assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
@ -718,13 +709,15 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
* First pass, count entries.
*/
while (1) {
uint64_t address, size;
flat_read_chunk(inb, &re, sizeof(re));
re.address = fdt64_to_cpu(re.address);
re.size = fdt64_to_cpu(re.size);
if (re.size == 0)
address = fdt64_to_cpu(re.address);
size = fdt64_to_cpu(re.size);
if (size == 0)
break;
new = build_reserve_entry(re.address, re.size);
new = build_reserve_entry(address, size);
reservelist = add_reserve_entry(reservelist, new);
}
@ -738,7 +731,7 @@ static char *nodename_from_path(const char *ppath, const char *cpath)
plen = strlen(ppath);
if (!strneq(ppath, cpath, plen))
if (!strstarts(cpath, ppath))
die("Path \"%s\" is not valid as a child of \"%s\"\n",
cpath, ppath);
@ -817,6 +810,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
struct dt_info *dt_from_blob(const char *fname)
{
FILE *f;
fdt32_t magic_buf, totalsize_buf;
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
uint32_t off_dt, off_str, off_mem_rsvmap;
int rc;
@ -833,7 +827,7 @@ struct dt_info *dt_from_blob(const char *fname)
f = srcfile_relative_open(fname, NULL);
rc = fread(&magic, sizeof(magic), 1, f);
rc = fread(&magic_buf, sizeof(magic_buf), 1, f);
if (ferror(f))
die("Error reading DT blob magic number: %s\n",
strerror(errno));
@ -844,11 +838,11 @@ struct dt_info *dt_from_blob(const char *fname)
die("Mysterious short read reading magic number\n");
}
magic = fdt32_to_cpu(magic);
magic = fdt32_to_cpu(magic_buf);
if (magic != FDT_MAGIC)
die("Blob has incorrect magic number\n");
rc = fread(&totalsize, sizeof(totalsize), 1, f);
rc = fread(&totalsize_buf, sizeof(totalsize_buf), 1, f);
if (ferror(f))
die("Error reading DT blob size: %s\n", strerror(errno));
if (rc < 1) {
@ -858,7 +852,7 @@ struct dt_info *dt_from_blob(const char *fname)
die("Mysterious short read reading blob size\n");
}
totalsize = fdt32_to_cpu(totalsize);
totalsize = fdt32_to_cpu(totalsize_buf);
if (totalsize < FDT_V1_SIZE)
die("DT blob size (%d) is too small\n", totalsize);

View File

@ -88,7 +88,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
return _fdt_offset_ptr(fdt, offset);
return fdt_offset_ptr_(fdt, offset);
}
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
@ -141,7 +141,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
return tag;
}
int _fdt_check_node_offset(const void *fdt, int offset)
int fdt_check_node_offset_(const void *fdt, int offset)
{
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
@ -150,7 +150,7 @@ int _fdt_check_node_offset(const void *fdt, int offset)
return offset;
}
int _fdt_check_prop_offset(const void *fdt, int offset)
int fdt_check_prop_offset_(const void *fdt, int offset)
{
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
@ -165,7 +165,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth)
uint32_t tag;
if (offset >= 0)
if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
return nextoffset;
do {
@ -227,7 +227,7 @@ int fdt_next_subnode(const void *fdt, int offset)
return offset;
}
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;
const char *last = strtab + tabsize - len;

View File

@ -1,5 +1,5 @@
#ifndef _FDT_H
#define _FDT_H
#ifndef FDT_H
#define FDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
@ -108,4 +108,4 @@ struct fdt_property {
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
#endif /* _FDT_H */
#endif /* FDT_H */

View File

@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize)
return fdt_open_into(buf, buf, bufsize);
}

View File

@ -21,14 +21,14 @@
*/
static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
{
const uint32_t *val;
const fdt32_t *val;
int len;
val = fdt_getprop(fdto, fragment, "target", &len);
if (!val)
return 0;
if ((len != sizeof(*val)) || (*val == (uint32_t)-1))
if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
return (uint32_t)-1;
return fdt32_to_cpu(*val);
@ -39,6 +39,7 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
* @fdt: Base device tree blob
* @fdto: Device tree overlay blob
* @fragment: node offset of the fragment in the overlay
* @pathp: pointer which receives the path of the target (or NULL)
*
* overlay_get_target() retrieves the target offset in the base
* device tree of a fragment, no matter how the actual targetting is
@ -49,37 +50,47 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
* Negative error code on error
*/
static int overlay_get_target(const void *fdt, const void *fdto,
int fragment)
int fragment, char const **pathp)
{
uint32_t phandle;
const char *path;
int path_len;
const char *path = NULL;
int path_len = 0, ret;
/* Try first to do a phandle based lookup */
phandle = overlay_get_target_phandle(fdto, fragment);
if (phandle == (uint32_t)-1)
return -FDT_ERR_BADPHANDLE;
if (phandle)
return fdt_node_offset_by_phandle(fdt, phandle);
/* no phandle, try path */
if (!phandle) {
/* And then a path based lookup */
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
if (path)
ret = fdt_path_offset(fdt, path);
else
ret = path_len;
} else
ret = fdt_node_offset_by_phandle(fdt, phandle);
/* And then a path based lookup */
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
if (!path) {
/*
* If we haven't found either a target or a
* target-path property in a node that contains a
* __overlay__ subnode (we wouldn't be called
* otherwise), consider it a improperly written
* overlay
*/
if (path_len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
/*
* If we haven't found either a target or a
* target-path property in a node that contains a
* __overlay__ subnode (we wouldn't be called
* otherwise), consider it a improperly written
* overlay
*/
if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
ret = -FDT_ERR_BADOVERLAY;
return path_len;
}
/* return on error */
if (ret < 0)
return ret;
return fdt_path_offset(fdt, path);
/* return pointer to path (if available) */
if (pathp)
*pathp = path ? path : NULL;
return ret;
}
/**
@ -99,7 +110,7 @@ static int overlay_get_target(const void *fdt, const void *fdto,
static int overlay_phandle_add_offset(void *fdt, int node,
const char *name, uint32_t delta)
{
const uint32_t *val;
const fdt32_t *val;
uint32_t adj_val;
int len;
@ -210,7 +221,7 @@ static int overlay_update_local_node_references(void *fdto,
int ret;
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
const uint32_t *fixup_val;
const fdt32_t *fixup_val;
const char *tree_val;
const char *name;
int fixup_len;
@ -234,7 +245,8 @@ static int overlay_update_local_node_references(void *fdto,
}
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
uint32_t adj_val, poffset;
fdt32_t adj_val;
uint32_t poffset;
poffset = fdt32_to_cpu(fixup_val[i]);
@ -246,9 +258,7 @@ static int overlay_update_local_node_references(void *fdto,
*/
memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
adj_val = fdt32_to_cpu(adj_val);
adj_val += delta;
adj_val = cpu_to_fdt32(adj_val);
adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
ret = fdt_setprop_inplace_namelen_partial(fdto,
tree_node,
@ -272,7 +282,7 @@ static int overlay_update_local_node_references(void *fdto,
tree_child = fdt_subnode_offset(fdto, tree_node,
fixup_child_name);
if (ret == -FDT_ERR_NOTFOUND)
if (tree_child == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
if (tree_child < 0)
return tree_child;
@ -356,6 +366,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto,
{
const char *symbol_path;
uint32_t phandle;
fdt32_t phandle_prop;
int symbol_off, fixup_off;
int prop_len;
@ -381,10 +392,11 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto,
if (fixup_off < 0)
return fixup_off;
phandle = cpu_to_fdt32(phandle);
phandle_prop = cpu_to_fdt32(phandle);
return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
name, name_len, poffset,
&phandle, sizeof(phandle));
&phandle_prop,
sizeof(phandle_prop));
};
/**
@ -589,7 +601,7 @@ static int overlay_apply_node(void *fdt, int target,
*
* overlay_merge() merges an overlay into its base device tree.
*
* This is the final step in the device tree overlay application
* This is the next to last step in the device tree overlay application
* process, when all the phandles have been adjusted and resolved and
* you just have to merge overlay into the base device tree.
*
@ -617,7 +629,7 @@ static int overlay_merge(void *fdt, void *fdto)
if (overlay < 0)
return overlay;
target = overlay_get_target(fdt, fdto, fragment);
target = overlay_get_target(fdt, fdto, fragment, NULL);
if (target < 0)
return target;
@ -629,6 +641,175 @@ static int overlay_merge(void *fdt, void *fdto)
return 0;
}
static int get_path_len(const void *fdt, int nodeoffset)
{
int len = 0, namelen;
const char *name;
FDT_CHECK_HEADER(fdt);
for (;;) {
name = fdt_get_name(fdt, nodeoffset, &namelen);
if (!name)
return namelen;
/* root? we're done */
if (namelen == 0)
break;
nodeoffset = fdt_parent_offset(fdt, nodeoffset);
if (nodeoffset < 0)
return nodeoffset;
len += namelen + 1;
}
/* in case of root pretend it's "/" */
if (len == 0)
len++;
return len;
}
/**
* overlay_symbol_update - Update the symbols of base tree after a merge
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
*
* overlay_symbol_update() updates the symbols of the base tree with the
* symbols of the applied overlay
*
* This is the last step in the device tree overlay application
* process, allowing the reference of overlay symbols by subsequent
* overlay operations.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_symbol_update(void *fdt, void *fdto)
{
int root_sym, ov_sym, prop, path_len, fragment, target;
int len, frag_name_len, ret, rel_path_len;
const char *s, *e;
const char *path;
const char *name;
const char *frag_name;
const char *rel_path;
const char *target_path;
char *buf;
void *p;
ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
/* if no overlay symbols exist no problem */
if (ov_sym < 0)
return 0;
root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
/* it no root symbols exist we should create them */
if (root_sym == -FDT_ERR_NOTFOUND)
root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
/* any error is fatal now */
if (root_sym < 0)
return root_sym;
/* iterate over each overlay symbol */
fdt_for_each_property_offset(prop, fdto, ov_sym) {
path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
if (!path)
return path_len;
/* verify it's a string property (terminated by a single \0) */
if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
return -FDT_ERR_BADVALUE;
/* keep end marker to avoid strlen() */
e = path + path_len;
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
if (*path != '/')
return -FDT_ERR_BADVALUE;
/* get fragment name first */
s = strchr(path + 1, '/');
if (!s)
return -FDT_ERR_BADOVERLAY;
frag_name = path + 1;
frag_name_len = s - path - 1;
/* verify format; safe since "s" lies in \0 terminated prop */
len = sizeof("/__overlay__/") - 1;
if ((e - s) < len || memcmp(s, "/__overlay__/", len))
return -FDT_ERR_BADOVERLAY;
rel_path = s + len;
rel_path_len = e - rel_path;
/* find the fragment index in which the symbol lies */
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
frag_name_len);
/* not found? */
if (ret < 0)
return -FDT_ERR_BADOVERLAY;
fragment = ret;
/* an __overlay__ subnode must exist */
ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
if (ret < 0)
return -FDT_ERR_BADOVERLAY;
/* get the target of the fragment */
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
if (ret < 0)
return ret;
target = ret;
/* if we have a target path use */
if (!target_path) {
ret = get_path_len(fdt, target);
if (ret < 0)
return ret;
len = ret;
} else {
len = strlen(target_path);
}
ret = fdt_setprop_placeholder(fdt, root_sym, name,
len + (len > 1) + rel_path_len + 1, &p);
if (ret < 0)
return ret;
if (!target_path) {
/* again in case setprop_placeholder changed it */
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
if (ret < 0)
return ret;
target = ret;
}
buf = p;
if (len > 1) { /* target is not root */
if (!target_path) {
ret = fdt_get_path(fdt, target, buf, len + 1);
if (ret < 0)
return ret;
} else
memcpy(buf, target_path, len + 1);
} else
len--;
buf[len] = '/';
memcpy(buf + len + 1, rel_path, rel_path_len);
buf[len + 1 + rel_path_len] = '\0';
}
return 0;
}
int fdt_overlay_apply(void *fdt, void *fdto)
{
uint32_t delta = fdt_get_max_phandle(fdt);
@ -653,6 +834,10 @@ int fdt_overlay_apply(void *fdt, void *fdto)
if (ret)
goto err;
ret = overlay_symbol_update(fdt, fdto);
if (ret)
goto err;
/*
* The overlay has been damaged, erase its magic.
*/

View File

@ -55,12 +55,12 @@
#include "libfdt_internal.h"
static int _fdt_nodename_eq(const void *fdt, int offset,
static int fdt_nodename_eq_(const void *fdt, int offset,
const char *s, int len)
{
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
if (! p)
if (!p)
/* short match */
return 0;
@ -80,7 +80,7 @@ const char *fdt_string(const void *fdt, int stroffset)
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
}
static int _fdt_string_eq(const void *fdt, int stroffset,
static int fdt_string_eq_(const void *fdt, int stroffset,
const char *s, int len)
{
const char *p = fdt_string(fdt, stroffset);
@ -117,8 +117,8 @@ uint32_t fdt_get_max_phandle(const void *fdt)
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
FDT_CHECK_HEADER(fdt);
*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
return 0;
}
@ -126,12 +126,12 @@ int fdt_num_mem_rsv(const void *fdt)
{
int i = 0;
while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
i++;
return i;
}
static int _nextprop(const void *fdt, int offset)
static int nextprop_(const void *fdt, int offset)
{
uint32_t tag;
int nextoffset;
@ -166,7 +166,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
(offset >= 0) && (depth >= 0);
offset = fdt_next_node(fdt, offset, &depth))
if ((depth == 1)
&& _fdt_nodename_eq(fdt, offset, name, namelen))
&& fdt_nodename_eq_(fdt, offset, name, namelen))
return offset;
if (depth < 0)
@ -232,11 +232,11 @@ int fdt_path_offset(const void *fdt, const char *path)
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
int err;
if (((err = fdt_check_header(fdt)) != 0)
|| ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
goto fail;
if (len)
@ -254,18 +254,18 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset)
{
int offset;
if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return offset;
return _nextprop(fdt, offset);
return nextprop_(fdt, offset);
}
int fdt_next_property_offset(const void *fdt, int offset)
{
if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
return offset;
return _nextprop(fdt, offset);
return nextprop_(fdt, offset);
}
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
@ -275,13 +275,13 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int err;
const struct fdt_property *prop;
if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
}
prop = _fdt_offset_ptr(fdt, offset);
prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
*lenp = fdt32_to_cpu(prop->len);
@ -303,7 +303,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
offset = -FDT_ERR_INTERNAL;
break;
}
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
name, namelen))
return prop;
}
@ -327,7 +327,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const struct fdt_property *prop;
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
if (! prop)
if (!prop)
return NULL;
return prop->data;

View File

@ -55,8 +55,8 @@
#include "libfdt_internal.h"
static int _fdt_blocks_misordered(const void *fdt,
int mem_rsv_size, int struct_size)
static int fdt_blocks_misordered_(const void *fdt,
int mem_rsv_size, int struct_size)
{
return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|| (fdt_off_dt_struct(fdt) <
@ -67,13 +67,13 @@ static int _fdt_blocks_misordered(const void *fdt,
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
static int _fdt_rw_check_header(void *fdt)
static int fdt_rw_check_header_(void *fdt)
{
FDT_CHECK_HEADER(fdt);
if (fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17)
@ -84,20 +84,20 @@ static int _fdt_rw_check_header(void *fdt)
#define FDT_RW_CHECK_HEADER(fdt) \
{ \
int __err; \
if ((__err = _fdt_rw_check_header(fdt)) != 0) \
return __err; \
int err_; \
if ((err_ = fdt_rw_check_header_(fdt)) != 0) \
return err_; \
}
static inline int _fdt_data_size(void *fdt)
static inline int fdt_data_size_(void *fdt)
{
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}
static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{
char *p = splicepoint;
char *end = (char *)fdt + _fdt_data_size(fdt);
char *end = (char *)fdt + fdt_data_size_(fdt);
if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET;
@ -109,12 +109,12 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
return 0;
}
static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
int oldn, int newn)
{
int delta = (newn - oldn) * sizeof(*p);
int err;
err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err)
return err;
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
@ -122,13 +122,13 @@ static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
return 0;
}
static int _fdt_splice_struct(void *fdt, void *p,
static int fdt_splice_struct_(void *fdt, void *p,
int oldlen, int newlen)
{
int delta = newlen - oldlen;
int err;
if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
return err;
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
@ -136,20 +136,20 @@ static int _fdt_splice_struct(void *fdt, void *p,
return 0;
}
static int _fdt_splice_string(void *fdt, int newlen)
static int fdt_splice_string_(void *fdt, int newlen)
{
void *p = (char *)fdt
+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
int err;
if ((err = _fdt_splice(fdt, p, 0, newlen)))
if ((err = fdt_splice_(fdt, p, 0, newlen)))
return err;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0;
}
static int _fdt_find_add_string(void *fdt, const char *s)
static int fdt_find_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
@ -157,13 +157,13 @@ static int _fdt_find_add_string(void *fdt, const char *s)
int len = strlen(s) + 1;
int err;
p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p)
/* found it */
return (p - strtab);
new = strtab + fdt_size_dt_strings(fdt);
err = _fdt_splice_string(fdt, len);
err = fdt_splice_string_(fdt, len);
if (err)
return err;
@ -178,8 +178,8 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
FDT_RW_CHECK_HEADER(fdt);
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
if (err)
return err;
@ -190,27 +190,27 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
FDT_RW_CHECK_HEADER(fdt);
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
return _fdt_splice_mem_rsv(fdt, re, 1, 0);
return fdt_splice_mem_rsv_(fdt, re, 1, 0);
}
static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int oldlen;
int err;
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (! (*prop))
if (!*prop)
return oldlen;
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(len))))
return err;
@ -218,7 +218,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
return 0;
}
static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int proplen;
@ -226,17 +226,17 @@ static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
int namestroff;
int err;
if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return nextoffset;
namestroff = _fdt_find_add_string(fdt, name);
namestroff = fdt_find_add_string_(fdt, name);
if (namestroff < 0)
return namestroff;
*prop = _fdt_offset_ptr_w(fdt, nextoffset);
*prop = fdt_offset_ptr_w_(fdt, nextoffset);
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
err = _fdt_splice_struct(fdt, *prop, 0, proplen);
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err)
return err;
@ -260,7 +260,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
newlen = strlen(name);
err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
FDT_TAGALIGN(newlen+1));
if (err)
return err;
@ -269,22 +269,36 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
return 0;
}
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
int len, void **prop_data)
{
struct fdt_property *prop;
int err;
FDT_RW_CHECK_HEADER(fdt);
err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
*prop_data = prop->data;
return 0;
}
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
void *prop_data;
int err;
err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
if (err)
return err;
if (len)
memcpy(prop->data, val, len);
memcpy(prop_data, val, len);
return 0;
}
@ -299,7 +313,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) {
newlen = len + oldlen;
err = _fdt_splice_struct(fdt, prop->data,
err = fdt_splice_struct_(fdt, prop->data,
FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(newlen));
if (err)
@ -307,7 +321,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len);
} else {
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
@ -323,11 +337,11 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
FDT_RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
if (!prop)
return len;
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
return _fdt_splice_struct(fdt, prop, proplen, 0);
return fdt_splice_struct_(fdt, prop, proplen, 0);
}
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
@ -355,10 +369,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
tag = fdt_next_tag(fdt, offset, &nextoffset);
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
nh = _fdt_offset_ptr_w(fdt, offset);
nh = fdt_offset_ptr_w_(fdt, offset);
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
err = _fdt_splice_struct(fdt, nh, 0, nodelen);
err = fdt_splice_struct_(fdt, nh, 0, nodelen);
if (err)
return err;
@ -382,15 +396,15 @@ int fdt_del_node(void *fdt, int nodeoffset)
FDT_RW_CHECK_HEADER(fdt);
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
endoffset - nodeoffset, 0);
}
static void _fdt_packblocks(const char *old, char *new,
static void fdt_packblocks_(const char *old, char *new,
int mem_rsv_size, int struct_size)
{
int mem_rsv_off, struct_off, strings_off;
@ -436,7 +450,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return struct_size;
}
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
@ -464,7 +478,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return -FDT_ERR_NOSPACE;
}
_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
@ -484,8 +498,8 @@ int fdt_pack(void *fdt)
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
fdt_set_totalsize(fdt, _fdt_data_size(fdt));
fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
fdt_set_totalsize(fdt, fdt_data_size_(fdt));
return 0;
}

View File

@ -55,7 +55,7 @@
#include "libfdt_internal.h"
static int _fdt_sw_check_header(void *fdt)
static int fdt_sw_check_header_(void *fdt)
{
if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
@ -66,11 +66,11 @@ static int _fdt_sw_check_header(void *fdt)
#define FDT_SW_CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = _fdt_sw_check_header(fdt)) != 0) \
if ((err = fdt_sw_check_header_(fdt)) != 0) \
return err; \
}
static void *_fdt_grab_space(void *fdt, size_t len)
static void *fdt_grab_space_(void *fdt, size_t len)
{
int offset = fdt_size_dt_struct(fdt);
int spaceleft;
@ -82,7 +82,7 @@ static void *_fdt_grab_space(void *fdt, size_t len)
return NULL;
fdt_set_size_dt_struct(fdt, offset + len);
return _fdt_offset_ptr_w(fdt, offset);
return fdt_offset_ptr_w_(fdt, offset);
}
int fdt_create(void *buf, int bufsize)
@ -174,7 +174,7 @@ int fdt_begin_node(void *fdt, const char *name)
FDT_SW_CHECK_HEADER(fdt);
nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh)
return -FDT_ERR_NOSPACE;
@ -189,7 +189,7 @@ int fdt_end_node(void *fdt)
FDT_SW_CHECK_HEADER(fdt);
en = _fdt_grab_space(fdt, FDT_TAGSIZE);
en = fdt_grab_space_(fdt, FDT_TAGSIZE);
if (! en)
return -FDT_ERR_NOSPACE;
@ -197,7 +197,7 @@ int fdt_end_node(void *fdt)
return 0;
}
static int _fdt_find_add_string(void *fdt, const char *s)
static int fdt_find_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
@ -205,7 +205,7 @@ static int _fdt_find_add_string(void *fdt, const char *s)
int len = strlen(s) + 1;
int struct_top, offset;
p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
@ -220,25 +220,37 @@ static int _fdt_find_add_string(void *fdt, const char *s)
return offset;
}
int fdt_property(void *fdt, const char *name, const void *val, int len)
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
{
struct fdt_property *prop;
int nameoff;
FDT_SW_CHECK_HEADER(fdt);
nameoff = _fdt_find_add_string(fdt, name);
nameoff = fdt_find_add_string_(fdt, name);
if (nameoff == 0)
return -FDT_ERR_NOSPACE;
prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
if (! prop)
return -FDT_ERR_NOSPACE;
prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
prop->len = cpu_to_fdt32(len);
memcpy(prop->data, val, len);
*valp = prop->data;
return 0;
}
int fdt_property(void *fdt, const char *name, const void *val, int len)
{
void *ptr;
int ret;
ret = fdt_property_placeholder(fdt, name, len, &ptr);
if (ret)
return ret;
memcpy(ptr, val, len);
return 0;
}
@ -253,7 +265,7 @@ int fdt_finish(void *fdt)
FDT_SW_CHECK_HEADER(fdt);
/* Add terminator */
end = _fdt_grab_space(fdt, sizeof(*end));
end = fdt_grab_space_(fdt, sizeof(*end));
if (! end)
return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END);
@ -269,7 +281,7 @@ int fdt_finish(void *fdt)
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop =
_fdt_offset_ptr_w(fdt, offset);
fdt_offset_ptr_w_(fdt, offset);
int nameoff;
nameoff = fdt32_to_cpu(prop->nameoff);

View File

@ -82,7 +82,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
int proplen;
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if (! propval)
if (!propval)
return proplen;
if (proplen != len)
@ -93,7 +93,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
val, len);
}
static void _fdt_nop_region(void *start, int len)
static void fdt_nop_region_(void *start, int len)
{
fdt32_t *p;
@ -107,15 +107,15 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
int len;
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
if (!prop)
return len;
_fdt_nop_region(prop, len + sizeof(*prop));
fdt_nop_region_(prop, len + sizeof(*prop));
return 0;
}
int _fdt_node_end_offset(void *fdt, int offset)
int fdt_node_end_offset_(void *fdt, int offset)
{
int depth = 0;
@ -129,11 +129,11 @@ int fdt_nop_node(void *fdt, int nodeoffset)
{
int endoffset;
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0),
endoffset - nodeoffset);
return 0;
}

View File

@ -1,5 +1,5 @@
#ifndef _LIBFDT_H
#define _LIBFDT_H
#ifndef LIBFDT_H
#define LIBFDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
@ -143,7 +143,9 @@
/* Low-level functions (you probably don't need these) */
/**********************************************************************/
#ifndef SWIG /* This function is not useful in Python */
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
#endif
static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
{
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
@ -210,7 +212,6 @@ int fdt_next_subnode(const void *fdt, int offset);
/**********************************************************************/
/* General functions */
/**********************************************************************/
#define fdt_get_header(fdt, field) \
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
@ -224,23 +225,23 @@ int fdt_next_subnode(const void *fdt, int offset);
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
#define __fdt_set_hdr(name) \
#define fdt_set_hdr_(name) \
static inline void fdt_set_##name(void *fdt, uint32_t val) \
{ \
struct fdt_header *fdth = (struct fdt_header *)fdt; \
fdth->name = cpu_to_fdt32(val); \
}
__fdt_set_hdr(magic);
__fdt_set_hdr(totalsize);
__fdt_set_hdr(off_dt_struct);
__fdt_set_hdr(off_dt_strings);
__fdt_set_hdr(off_mem_rsvmap);
__fdt_set_hdr(version);
__fdt_set_hdr(last_comp_version);
__fdt_set_hdr(boot_cpuid_phys);
__fdt_set_hdr(size_dt_strings);
__fdt_set_hdr(size_dt_struct);
#undef __fdt_set_hdr
fdt_set_hdr_(magic);
fdt_set_hdr_(totalsize);
fdt_set_hdr_(off_dt_struct);
fdt_set_hdr_(off_dt_strings);
fdt_set_hdr_(off_mem_rsvmap);
fdt_set_hdr_(version);
fdt_set_hdr_(last_comp_version);
fdt_set_hdr_(boot_cpuid_phys);
fdt_set_hdr_(size_dt_strings);
fdt_set_hdr_(size_dt_struct);
#undef fdt_set_hdr_
/**
* fdt_check_header - sanity check a device tree or possible device tree
@ -354,8 +355,10 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
* useful for finding subnodes based on a portion of a larger string,
* such as a full path.
*/
#ifndef SWIG /* Not available in Python */
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
const char *name, int namelen);
#endif
/**
* fdt_subnode_offset - find a subnode of a given node
* @fdt: pointer to the device tree blob
@ -391,7 +394,9 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
* Identical to fdt_path_offset(), but only consider the first namelen
* characters of path as the path name.
*/
#ifndef SWIG /* Not available in Python */
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
#endif
/**
* fdt_path_offset - find a tree node by its full path
@ -550,10 +555,12 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
* Identical to fdt_get_property(), but only examine the first namelen
* characters of name for matching the property name.
*/
#ifndef SWIG /* Not available in Python */
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int nodeoffset,
const char *name,
int namelen, int *lenp);
#endif
/**
* fdt_get_property - find a given property in a given node
@ -624,8 +631,10 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
#ifndef SWIG /* This function is not useful in Python */
const void *fdt_getprop_by_offset(const void *fdt, int offset,
const char **namep, int *lenp);
#endif
/**
* fdt_getprop_namelen - get property value based on substring
@ -638,6 +647,7 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
* Identical to fdt_getprop(), but only examine the first namelen
* characters of name for matching the property name.
*/
#ifndef SWIG /* Not available in Python */
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp);
static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
@ -647,6 +657,7 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
namelen, lenp);
}
#endif
/**
* fdt_getprop - retrieve the value of a given property
@ -707,8 +718,10 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
* Identical to fdt_get_alias(), but only examine the first namelen
* characters of name for matching the alias name.
*/
#ifndef SWIG /* Not available in Python */
const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen);
#endif
/**
* fdt_get_alias - retrieve the path referenced by a given alias
@ -1106,10 +1119,12 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
* of the name. It is useful when you want to manipulate only one value of
* an array and you have a string that doesn't end with \0.
*/
#ifndef SWIG /* Not available in Python */
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
const char *name, int namelen,
uint32_t idx, const void *val,
int len);
#endif
/**
* fdt_setprop_inplace - change a property's value, but not its size
@ -1139,8 +1154,10 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
#ifndef SWIG /* Not available in Python */
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len);
#endif
/**
* fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
@ -1297,6 +1314,22 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
{
return fdt_property_u32(fdt, name, val);
}
/**
* fdt_property_placeholder - add a new property and return a ptr to its value
*
* @fdt: pointer to the device tree blob
* @name: name of property to add
* @len: length of property value in bytes
* @valp: returns a pointer to where where the value should be placed
*
* returns:
* 0, on success
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_NOSPACE, standard meanings
*/
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp);
#define fdt_property_string(fdt, name, str) \
fdt_property(fdt, name, str, strlen(str)+1)
int fdt_end_node(void *fdt);
@ -1415,6 +1448,37 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name);
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len);
/**
* fdt_setprop_placeholder - allocate space for a property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @len: length of the property value
* @prop_data: return pointer to property data
*
* fdt_setprop_placeholer() allocates the named property in the given node.
* If the property exists it is resized. In either case a pointer to the
* property data is returned.
*
* This function may insert or delete data from the blob, and will
* therefore change the offsets of some existing nodes.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
* contain the new property value
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
int len, void **prop_data);
/**
* fdt_setprop_u32 - set a property to a 32-bit integer
* @fdt: pointer to the device tree blob
@ -1734,8 +1798,10 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name);
* creating subnodes based on a portion of a larger string, such as a
* full path.
*/
#ifndef SWIG /* Not available in Python */
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen);
#endif
/**
* fdt_add_subnode - creates a new node
@ -1830,4 +1896,4 @@ int fdt_overlay_apply(void *fdt, void *fdto);
const char *fdt_strerror(int errval);
#endif /* _LIBFDT_H */
#endif /* LIBFDT_H */

View File

@ -1,5 +1,5 @@
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
#ifndef LIBFDT_ENV_H
#define LIBFDT_ENV_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
@ -58,16 +58,16 @@
#include <string.h>
#ifdef __CHECKER__
#define __force __attribute__((force))
#define __bitwise __attribute__((bitwise))
#define FDT_FORCE __attribute__((force))
#define FDT_BITWISE __attribute__((bitwise))
#else
#define __force
#define __bitwise
#define FDT_FORCE
#define FDT_BITWISE
#endif
typedef uint16_t __bitwise fdt16_t;
typedef uint32_t __bitwise fdt32_t;
typedef uint64_t __bitwise fdt64_t;
typedef uint16_t FDT_BITWISE fdt16_t;
typedef uint32_t FDT_BITWISE fdt32_t;
typedef uint64_t FDT_BITWISE fdt64_t;
#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
@ -80,33 +80,60 @@ typedef uint64_t __bitwise fdt64_t;
static inline uint16_t fdt16_to_cpu(fdt16_t x)
{
return (__force uint16_t)CPU_TO_FDT16(x);
return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
}
static inline fdt16_t cpu_to_fdt16(uint16_t x)
{
return (__force fdt16_t)CPU_TO_FDT16(x);
return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
}
static inline uint32_t fdt32_to_cpu(fdt32_t x)
{
return (__force uint32_t)CPU_TO_FDT32(x);
return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
}
static inline fdt32_t cpu_to_fdt32(uint32_t x)
{
return (__force fdt32_t)CPU_TO_FDT32(x);
return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
}
static inline uint64_t fdt64_to_cpu(fdt64_t x)
{
return (__force uint64_t)CPU_TO_FDT64(x);
return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
}
static inline fdt64_t cpu_to_fdt64(uint64_t x)
{
return (__force fdt64_t)CPU_TO_FDT64(x);
return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
}
#undef CPU_TO_FDT64
#undef CPU_TO_FDT32
#undef CPU_TO_FDT16
#undef EXTRACT_BYTE
#endif /* _LIBFDT_ENV_H */
#ifdef __APPLE__
#include <AvailabilityMacros.h>
/* strnlen() is not available on Mac OS < 10.7 */
# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
MAC_OS_X_VERSION_10_7)
#define strnlen fdt_strnlen
/*
* fdt_strnlen: returns the length of a string or max_count - which ever is
* smallest.
* Input 1 string: the string whose size is to be determined
* Input 2 max_count: the maximum value returned by this function
* Output: length of the string or max_count (the smallest of the two)
*/
static inline size_t fdt_strnlen(const char *string, size_t max_count)
{
const char *p = memchr(string, 0, max_count);
return p ? p - string : max_count;
}
#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
MAC_OS_X_VERSION_10_7) */
#endif /* __APPLE__ */
#endif /* LIBFDT_ENV_H */

View File

@ -1,5 +1,5 @@
#ifndef _LIBFDT_INTERNAL_H
#define _LIBFDT_INTERNAL_H
#ifndef LIBFDT_INTERNAL_H
#define LIBFDT_INTERNAL_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
@ -57,27 +57,27 @@
#define FDT_CHECK_HEADER(fdt) \
{ \
int __err; \
if ((__err = fdt_check_header(fdt)) != 0) \
return __err; \
int err_; \
if ((err_ = fdt_check_header(fdt)) != 0) \
return err_; \
}
int _fdt_check_node_offset(const void *fdt, int offset);
int _fdt_check_prop_offset(const void *fdt, int offset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset);
int fdt_check_node_offset_(const void *fdt, int offset);
int fdt_check_prop_offset_(const void *fdt, int offset);
const char *fdt_find_string_(const char *strtab, int tabsize, const char *s);
int fdt_node_end_offset_(void *fdt, int nodeoffset);
static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
static inline const void *fdt_offset_ptr_(const void *fdt, int offset)
{
return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
}
static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
{
return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset);
}
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n)
{
const struct fdt_reserve_entry *rsv_table =
(const struct fdt_reserve_entry *)
@ -85,11 +85,11 @@ static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int
return rsv_table + n;
}
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
{
return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
}
#define FDT_SW_MAGIC (~FDT_MAGIC)
#endif /* _LIBFDT_INTERNAL_H */
#endif /* LIBFDT_INTERNAL_H */

View File

@ -60,6 +60,9 @@ LIBFDT_1.2 {
fdt_address_cells;
fdt_size_cells;
fdt_stringlist_contains;
fdt_stringlist_count;
fdt_stringlist_search;
fdt_stringlist_get;
fdt_resize;
fdt_overlay_apply;

View File

@ -216,6 +216,29 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
return old_node;
}
struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
{
static unsigned int next_orphan_fragment = 0;
struct node *node;
struct property *p;
struct data d = empty_data;
char *name;
d = data_add_marker(d, REF_PHANDLE, ref);
d = data_append_integer(d, 0xffffffff, 32);
p = build_property("target", d);
xasprintf(&name, "fragment@%u",
next_orphan_fragment++);
name_node(new_node, "__overlay__");
node = build_node(p, new_node);
name_node(node, name);
add_child(dt, node);
return dt;
}
struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);
@ -319,8 +342,8 @@ struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
memset(new, 0, sizeof(*new));
new->re.address = address;
new->re.size = size;
new->address = address;
new->size = size;
return new;
}
@ -393,7 +416,13 @@ struct property *get_property(struct node *node, const char *propname)
cell_t propval_cell(struct property *prop)
{
assert(prop->val.len == sizeof(cell_t));
return fdt32_to_cpu(*((cell_t *)prop->val.val));
return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
}
cell_t propval_cell_n(struct property *prop, int n)
{
assert(prop->val.len / sizeof(cell_t) >= n);
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
}
struct property *get_property_by_label(struct node *tree, const char *label,
@ -478,7 +507,8 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/');
for_each_child(tree, child) {
if (p && strneq(path, child->name, p-path))
if (p && (strlen(child->name) == p-path) &&
strprefixeq(path, p - path, child->name))
return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name))
return child;
@ -511,7 +541,10 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
{
struct node *child, *node;
assert((phandle != 0) && (phandle != -1));
if ((phandle == 0) || (phandle == -1)) {
assert(generate_fixups);
return NULL;
}
if (tree->phandle == phandle) {
if (tree->deleted)
@ -599,13 +632,13 @@ static int cmp_reserve_info(const void *ax, const void *bx)
a = *((const struct reserve_info * const *)ax);
b = *((const struct reserve_info * const *)bx);
if (a->re.address < b->re.address)
if (a->address < b->address)
return -1;
else if (a->re.address > b->re.address)
else if (a->address > b->address)
return 1;
else if (a->re.size < b->re.size)
else if (a->size < b->size)
return -1;
else if (a->re.size > b->re.size)
else if (a->size > b->size)
return 1;
else
return 0;
@ -902,7 +935,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
struct node *refnode)
{
struct node *wn, *nwn; /* local fixup node, walk node, new */
uint32_t value_32;
fdt32_t value_32;
char **compp;
int i, depth;

View File

@ -0,0 +1,24 @@
# Makefile.pylibfdt
#
PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) \
$(PYLIBFDT_srcdir)/libfdt.i
PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so
define run_setup
SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)"
VERSION="$(dtc_version)"
$(PYLIBFDT_objdir)/setup.py --quiet $(2)
endef
$(PYMODULE): $(PYLIBFDT_srcs)
@$(VECHO) PYMOD $@
$(call run_setup, $^, build_ext --inplace)
mv _libfdt.so $@
install_pylibfdt: $(PYMODULE)
$(VECHO) INSTALL-PYLIB; \
$(call run_setup, $(PYLIBFDT_srcs), \
install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)))
PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so

493
pylibfdt/libfdt.i Normal file
View File

@ -0,0 +1,493 @@
/*
* pylibfdt - Flat Device Tree manipulation in Python
* Copyright (C) 2017 Google, Inc.
* Written by Simon Glass <sjg@chromium.org>
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU 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
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
%module libfdt
%include <stdint.i>
%{
#define SWIG_FILE_WITH_INIT
#include "libfdt.h"
%}
%pythoncode %{
import struct
# Error codes, corresponding to FDT_ERR_... in libfdt.h
(NOTFOUND,
EXISTS,
NOSPACE,
BADOFFSET,
BADPATH,
BADPHANDLE,
BADSTATE,
TRUNCATED,
BADMAGIC,
BADVERSION,
BADSTRUCTURE,
BADLAYOUT,
INTERNAL,
BADNCELLS,
BADVALUE,
BADOVERLAY,
NOPHANDLES) = QUIET_ALL = range(1, 18)
# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
# altogether. All # functions passed this value will return an error instead
# of raising an exception.
# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
# instead of raising an exception.
QUIET_NOTFOUND = (NOTFOUND,)
class FdtException(Exception):
"""An exception caused by an error such as one of the codes above"""
def __init__(self, err):
self.err = err
def __str__(self):
return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
def strerror(fdt_err):
"""Get the string for an error number
Args:
fdt_err: Error number (-ve)
Returns:
String containing the associated error
"""
return fdt_strerror(fdt_err)
def check_err(val, quiet=()):
"""Raise an error if the return value is -ve
This is used to check for errors returned by libfdt C functions.
Args:
val: Return value from a libfdt function
quiet: Errors to ignore (empty to raise on all errors)
Returns:
val if val >= 0
Raises
FdtException if val < 0
"""
if val < 0:
if -val not in quiet:
raise FdtException(val)
return val
def check_err_null(val, quiet=()):
"""Raise an error if the return value is NULL
This is used to check for a NULL return value from certain libfdt C
functions
Args:
val: Return value from a libfdt function
quiet: Errors to ignore (empty to raise on all errors)
Returns:
val if val is a list, None if not
Raises
FdtException if val indicates an error was reported and the error
is not in @quiet.
"""
# Normally a list is returned which contains the data and its length.
# If we get just an integer error code, it means the function failed.
if not isinstance(val, list):
if -val not in quiet:
raise FdtException(val)
return val
class Fdt:
"""Device tree class, supporting all operations
The Fdt object is created is created from a device tree binary file,
e.g. with something like:
fdt = Fdt(open("filename.dtb").read())
Operations can then be performed using the methods in this class. Each
method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
All methods raise an FdtException if an error occurs. To avoid this
behaviour a 'quiet' parameter is provided for some functions. This
defaults to empty, but you can pass a list of errors that you expect.
If one of these errors occurs, the function will return an error number
(e.g. -NOTFOUND).
"""
def __init__(self, data):
self._fdt = bytearray(data)
check_err(fdt_check_header(self._fdt));
def subnode_offset(self, parentoffset, name, quiet=()):
"""Get the offset of a named subnode
Args:
parentoffset: Offset of the parent node to check
name: Name of the required subnode, e.g. 'subnode@1'
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The node offset of the found node, if any
Raises
FdtException if there is no node with that name, or other error
"""
return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
quiet)
def path_offset(self, path, quiet=()):
"""Get the offset for a given path
Args:
path: Path to the required node, e.g. '/node@3/subnode@1'
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Node offset
Raises
FdtException if the path is not valid or not found
"""
return check_err(fdt_path_offset(self._fdt, path), quiet)
def first_property_offset(self, nodeoffset, quiet=()):
"""Get the offset of the first property in a node offset
Args:
nodeoffset: Offset to the node to check
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Offset of the first property
Raises
FdtException if the associated node has no properties, or some
other error occurred
"""
return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
quiet)
def next_property_offset(self, prop_offset, quiet=()):
"""Get the next property in a node
Args:
prop_offset: Offset of the previous property
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Offset of the next property
Raises:
FdtException if the associated node has no more properties, or
some other error occurred
"""
return check_err(fdt_next_property_offset(self._fdt, prop_offset),
quiet)
def get_name(self, nodeoffset):
"""Get the name of a node
Args:
nodeoffset: Offset of node to check
Returns:
Node name
Raises:
FdtException on error (e.g. nodeoffset is invalid)
"""
return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
def get_property_by_offset(self, prop_offset, quiet=()):
"""Obtains a property that can be examined
Args:
prop_offset: Offset of property (e.g. from first_property_offset())
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Property object, or None if not found
Raises:
FdtException on error (e.g. invalid prop_offset or device
tree format)
"""
pdata = check_err_null(
fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
if isinstance(pdata, (int)):
return pdata
return Property(pdata[0], pdata[1])
def first_subnode(self, nodeoffset, quiet=()):
"""Find the first subnode of a parent node
Args:
nodeoffset: Node offset of parent node
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The offset of the first subnode, if any
Raises:
FdtException if no subnode found or other error occurs
"""
return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
def next_subnode(self, nodeoffset, quiet=()):
"""Find the next subnode
Args:
nodeoffset: Node offset of previous subnode
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The offset of the next subnode, if any
Raises:
FdtException if no more subnode found or other error occurs
"""
return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
def totalsize(self):
"""Return the total size of the device tree
Returns:
Total tree size in bytes
"""
return check_err(fdt_totalsize(self._fdt))
def off_dt_struct(self):
"""Return the start of the device tree struct area
Returns:
Start offset of struct area
"""
return check_err(fdt_off_dt_struct(self._fdt))
def pack(self, quiet=()):
"""Pack the device tree to remove unused space
This adjusts the tree in place.
Args:
quiet: Errors to ignore (empty to raise on all errors)
Raises:
FdtException if any error occurs
"""
return check_err(fdt_pack(self._fdt), quiet)
def delprop(self, nodeoffset, prop_name):
"""Delete a property from a node
Args:
nodeoffset: Node offset containing property to delete
prop_name: Name of property to delete
Raises:
FdtError if the property does not exist, or another error occurs
"""
return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
def getprop(self, nodeoffset, prop_name, quiet=()):
"""Get a property from a node
Args:
nodeoffset: Node offset containing property to get
prop_name: Name of property to get
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Value of property as a bytearray, or -ve error number
Raises:
FdtError if any error occurs (e.g. the property is not found)
"""
pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
quiet)
if isinstance(pdata, (int)):
return pdata
return bytearray(pdata[0])
def get_phandle(self, nodeoffset):
"""Get the phandle of a node
Args:
nodeoffset: Node offset to check
Returns:
phandle of node, or 0 if the node has no phandle or another error
occurs
"""
return fdt_get_phandle(self._fdt, nodeoffset)
def parent_offset(self, nodeoffset, quiet=()):
"""Get the offset of a node's parent
Args:
nodeoffset: Node offset to check
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The offset of the parent node, if any
Raises:
FdtException if no parent found or other error occurs
"""
return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
def node_offset_by_phandle(self, phandle, quiet=()):
"""Get the offset of a node with the given phandle
Args:
phandle: Phandle to search for
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The offset of node with that phandle, if any
Raises:
FdtException if no node found or other error occurs
"""
return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
class Property:
"""Holds a device tree property name and value.
This holds a copy of a property taken from the device tree. It does not
reference the device tree, so if anything changes in the device tree,
a Property object will remain valid.
Properties:
name: Property name
value: Proper value as a bytearray
"""
def __init__(self, name, value):
self.name = name
self.value = value
%}
%rename(fdt_property) fdt_property_func;
typedef int fdt32_t;
%include "libfdt/fdt.h"
%include "typemaps.i"
/* Most functions don't change the device tree, so use a const void * */
%typemap(in) (const void *)(const void *fdt) {
if (!PyByteArray_Check($input)) {
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
"', argument " "$argnum"" of type '" "$type""'");
}
$1 = (void *)PyByteArray_AsString($input);
fdt = $1;
fdt = fdt; /* avoid unused variable warning */
}
/* Some functions do change the device tree, so use void * */
%typemap(in) (void *)(const void *fdt) {
if (!PyByteArray_Check($input)) {
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
"', argument " "$argnum"" of type '" "$type""'");
}
$1 = PyByteArray_AsString($input);
fdt = $1;
fdt = fdt; /* avoid unused variable warning */
}
%typemap(out) (struct fdt_property *) {
PyObject *buff;
if ($1) {
resultobj = PyString_FromString(
fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
buff = PyByteArray_FromStringAndSize(
(const char *)($1 + 1), fdt32_to_cpu($1->len));
resultobj = SWIG_Python_AppendOutput(resultobj, buff);
}
}
%apply int *OUTPUT { int *lenp };
/* typemap used for fdt_getprop() */
%typemap(out) (const void *) {
if (!$1)
$result = Py_None;
else
$result = Py_BuildValue("s#", $1, *arg4);
}
/* We have both struct fdt_property and a function fdt_property() */
%warnfilter(302) fdt_property;
/* These are macros in the header so have to be redefined here */
int fdt_magic(const void *fdt);
int fdt_totalsize(const void *fdt);
int fdt_off_dt_struct(const void *fdt);
int fdt_off_dt_strings(const void *fdt);
int fdt_off_mem_rsvmap(const void *fdt);
int fdt_version(const void *fdt);
int fdt_last_comp_version(const void *fdt);
int fdt_boot_cpuid_phys(const void *fdt);
int fdt_size_dt_strings(const void *fdt);
int fdt_size_dt_struct(const void *fdt);
%include <../libfdt/libfdt.h>

121
pylibfdt/setup.py Executable file
View File

@ -0,0 +1,121 @@
#!/usr/bin/env python2
"""
setup.py file for SWIG libfdt
Copyright (C) 2017 Google, Inc.
Written by Simon Glass <sjg@chromium.org>
Files to be built into the extension are provided in SOURCES
C flags to use are provided in CPPFLAGS
Object file directory is provided in OBJDIR
Version is provided in VERSION
If these variables are not given they are parsed from the Makefiles. This
allows this script to be run stand-alone, e.g.:
./pylibfdt/setup.py install [--prefix=...]
"""
from distutils.core import setup, Extension
import os
import re
import sys
# Decodes a Makefile assignment line into key and value (and plus for +=)
RE_KEY_VALUE = re.compile('(?P<key>\w+) *(?P<plus>[+])?= *(?P<value>.*)$')
def ParseMakefile(fname):
"""Parse a Makefile to obtain its variables.
This collects variable assigments of the form:
VAR = value
VAR += more
It does not pick out := assignments, as these are not needed here. It does
handle line continuation.
Returns a dict:
key: Variable name (e.g. 'VAR')
value: Variable value (e.g. 'value more')
"""
makevars = {}
with open(fname) as fd:
prev_text = '' # Continuation text from previous line(s)
for line in fd.read().splitlines():
if line and line[-1] == '\\': # Deal with line continuation
prev_text += line[:-1]
continue
elif prev_text:
line = prev_text + line
prev_text = '' # Continuation is now used up
m = RE_KEY_VALUE.match(line)
if m:
value = m.group('value') or ''
key = m.group('key')
# Appending to a variable inserts a space beforehand
if 'plus' in m.groupdict() and key in makevars:
makevars[key] += ' ' + value
else:
makevars[key] = value
return makevars
def GetEnvFromMakefiles():
"""Scan the Makefiles to obtain the settings we need.
This assumes that this script is being run from the top-level directory,
not the pylibfdt directory.
Returns:
Tuple with:
List of swig options
Version string
List of files to build
List of extra C preprocessor flags needed
Object directory to use (always '')
"""
basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
swig_opts = ['-I%s' % basedir]
makevars = ParseMakefile(os.path.join(basedir, 'Makefile'))
version = '%s.%s.%s' % (makevars['VERSION'], makevars['PATCHLEVEL'],
makevars['SUBLEVEL'])
makevars = ParseMakefile(os.path.join(basedir, 'libfdt', 'Makefile.libfdt'))
files = makevars['LIBFDT_SRCS'].split()
files = [os.path.join(basedir, 'libfdt', fname) for fname in files]
files.append('pylibfdt/libfdt.i')
cflags = ['-I%s' % basedir, '-I%s/libfdt' % basedir]
objdir = ''
return swig_opts, version, files, cflags, objdir
progname = sys.argv[0]
files = os.environ.get('SOURCES', '').split()
cflags = os.environ.get('CPPFLAGS', '').split()
objdir = os.environ.get('OBJDIR')
version = os.environ.get('VERSION')
swig_opts = []
# If we were called directly rather than through our Makefile (which is often
# the case with Python module installation), read the settings from the
# Makefile.
if not all((version, files, cflags, objdir)):
swig_opts, version, files, cflags, objdir = GetEnvFromMakefiles()
libfdt_module = Extension(
'_libfdt',
sources = files,
extra_compile_args = cflags,
swig_opts = swig_opts,
)
setup(
name='libfdt',
version= version,
author='Simon Glass <sjg@chromium.org>',
description='Python binding for libfdt',
ext_modules=[libfdt_module],
package_dir={'': objdir},
py_modules=['pylibfdt/libfdt'],
)

View File

@ -17,11 +17,12 @@
* USA
*/
#ifndef _SRCPOS_H_
#define _SRCPOS_H_
#ifndef SRCPOS_H
#define SRCPOS_H
#include <stdio.h>
#include <stdbool.h>
#include "util.h"
struct srcfile_state {
FILE *f;
@ -106,13 +107,11 @@ extern void srcpos_update(struct srcpos *pos, const char *text, int len);
extern struct srcpos *srcpos_copy(struct srcpos *pos);
extern char *srcpos_string(struct srcpos *pos);
extern void srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va)
__attribute__((format(printf, 3, 0)));
extern void srcpos_error(struct srcpos *pos, const char *prefix,
const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va);
extern void PRINTF(3, 4) srcpos_error(struct srcpos *pos, const char *prefix,
const char *fmt, ...);
extern void srcpos_set_line(char *f, int l);
#endif /* _SRCPOS_H_ */
#endif /* SRCPOS_H */

View File

@ -72,13 +72,13 @@ tests_clean:
rm -f $(STD_CLEANFILES:%=$(TESTS_PREFIX)%)
rm -f $(TESTS_CLEANFILES)
check: tests ${TESTS_BIN}
check: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh
checkm: tests ${TESTS_BIN}
checkm: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh -m 2>&1 | tee vglog.$$$$
checkv: tests ${TESTS_BIN}
checkv: tests ${TESTS_BIN} $(TESTS_PYLIBFDT)
cd $(TESTS_PREFIX); ./run_tests.sh -v
ifneq ($(DEPTARGETS),)

10
tests/bad-chosen.dts Normal file
View File

@ -0,0 +1,10 @@
/dts-v1/;
/ {
node2 {
chosen {
bootargs = <0xdeadbeef>;
stdout-path = <1>;
};
};
};

13
tests/bad-gpio.dts Normal file
View File

@ -0,0 +1,13 @@
/dts-v1/;
/ {
gpio: gpio-controller {
#gpio-cells = <3>;
};
node {
nr-gpios = <1>;
foo-gpios = <&gpio>;
bar-gpio = <&gpio 1 2 3>;
};
};

View File

@ -0,0 +1,12 @@
/dts-v1/;
/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
#interrupt-cells = <3>;
};
node {
interrupts = <1>;
};
};

View File

@ -0,0 +1,11 @@
/dts-v1/;
/ {
intc: interrupt-controller {
#interrupt-cells = <3>;
};
node {
interrupts-extended = <&intc>;
};
};

View File

@ -4,4 +4,11 @@
device_type = <0xdeadbeef>;
model = <0xdeadbeef>;
status = <0xdeadbeef>;
label = <0xdeadbeef>;
foobar-names = "foo", <1>;
node {
compatible = "good", <0xdeadbeef>;
};
};

View File

@ -31,7 +31,7 @@
int main(int argc, char *argv[])
{
void *fdt;
uint32_t expected_cells[5];
fdt32_t expected_cells[5];
expected_cells[0] = cpu_to_fdt32((unsigned char)TEST_CHAR1);
expected_cells[1] = cpu_to_fdt32((unsigned char)TEST_CHAR2);

View File

@ -28,7 +28,7 @@
#include "tests.h"
#include "testdata.h"
int notequal; /* = 0 */
static int notequal; /* = 0 */
#define MISMATCH(fmt, ...) \
do { \

View File

@ -29,7 +29,7 @@
#include "tests.h"
#include "testdata.h"
int notequal; /* = 0 */
static int notequal; /* = 0 */
#define MISMATCH(fmt, ...) \
do { \
@ -59,14 +59,14 @@ static int mem_rsv_cmp(const void *p1, const void *p2)
const struct fdt_reserve_entry *re1 = p1;
const struct fdt_reserve_entry *re2 = p2;
if (re1->address < re2->address)
if (fdt64_to_cpu(re1->address) < fdt64_to_cpu(re2->address))
return -1;
else if (re1->address > re2->address)
else if (fdt64_to_cpu(re1->address) > fdt64_to_cpu(re2->address))
return 1;
if (re1->size < re2->size)
if (fdt64_to_cpu(re1->size) < fdt64_to_cpu(re2->size))
return -1;
else if (re1->size > re2->size)
else if (fdt64_to_cpu(re1->size) > fdt64_to_cpu(re2->size))
return 1;
return 0;

View File

@ -29,11 +29,11 @@
#include "testdata.h"
struct {
static struct {
void *blob;
const char *filename;
} trees[] = {
#define TREE(name) { &_##name, #name ".dtb" }
#define TREE(name) { &name, #name ".dtb" }
TREE(test_tree1),
TREE(bad_node_char), TREE(bad_node_format), TREE(bad_prop_char),
TREE(ovf_size_strings),

40
tests/fdtoverlay-runtest.sh Executable file
View File

@ -0,0 +1,40 @@
#! /bin/sh
# Run script for fdtoverlay tests
# We run fdtoverlay to generate a target device tree, thn fdtget to check it
# Usage
# fdtoverlay-runtest.sh name expected_output dtb_file node property flags value
. ./tests.sh
LOG=tmp.log.$$
EXPECT=tmp.expect.$$
rm -f $LOG $EXPECT
trap "rm -f $LOG $EXPECT" 0
expect="$1"
echo $expect >$EXPECT
node="$2"
property="$3"
flags="$4"
basedtb="$5"
targetdtb="$6"
shift 6
overlays="$@"
# First run fdtoverlay
verbose_run_check $VALGRIND "$FDTOVERLAY" -i "$basedtb" -o "$targetdtb" $overlays
# Now fdtget to read the value
verbose_run_log_check "$LOG" $VALGRIND "$DTGET" "$targetdtb" "$node" "$property" $flags
if cmp $EXPECT $LOG >/dev/null; then
PASS
else
if [ -z "$QUIET_TEST" ]; then
echo "EXPECTED :-:"
cat $EXPECT
fi
FAIL "Results differ from expected"
fi

View File

@ -5,6 +5,7 @@
subsubnode {
compatible = "subsubnode1", "subsubnode";
placeholder = "this is a placeholder string", "string2";
prop-int = <0xdeadbeef>;
};

View File

@ -30,7 +30,7 @@
#include "tests.h"
#include "testdata.h"
struct test_expr {
static struct test_expr {
const char *expr;
uint32_t result;
} expr_table[] = {
@ -70,7 +70,7 @@ struct test_expr {
int main(int argc, char *argv[])
{
void *fdt;
const uint32_t *res;
const fdt32_t *res;
int reslen;
int i;

View File

@ -45,6 +45,23 @@ static void check_compatible(const void *fdt, const char *path,
FAIL("%s is not compatible with \"%s\"", path, compat);
}
static void check_not_compatible(const void *fdt, const char *path,
const char *compat)
{
int offset, err;
offset = fdt_path_offset(fdt, path);
if (offset < 0)
FAIL("fdt_path_offset(%s): %s", path, fdt_strerror(offset));
err = fdt_node_check_compatible(fdt, offset, compat);
if (err < 0)
FAIL("fdt_node_check_compatible(%s): %s", path,
fdt_strerror(err));
if (err == 0)
FAIL("%s is incorrectly compatible with \"%s\"", path, compat);
}
int main(int argc, char *argv[])
{
void *fdt;
@ -55,8 +72,10 @@ int main(int argc, char *argv[])
check_compatible(fdt, "/", "test_tree1");
check_compatible(fdt, "/subnode@1/subsubnode", "subsubnode1");
check_compatible(fdt, "/subnode@1/subsubnode", "subsubnode");
check_not_compatible(fdt, "/subnode@1/subsubnode", "subsubnode2");
check_compatible(fdt, "/subnode@2/subsubnode", "subsubnode2");
check_compatible(fdt, "/subnode@2/subsubnode", "subsubnode");
check_not_compatible(fdt, "/subnode@2/subsubnode", "subsubnode1");
PASS();
}

View File

@ -69,7 +69,7 @@ static void check_search_str(void *fdt, const char *propname,
#define check_search_cell(fdt, propname, propval, ...) \
{ \
uint32_t val = cpu_to_fdt32(propval); \
fdt32_t val = cpu_to_fdt32(propval); \
check_search((fdt), (propname), &val, sizeof(val), \
##__VA_ARGS__); \
}

View File

@ -45,7 +45,7 @@ static int nopulate_struct(char *buf, const char *fdt)
nextoffset - offset);
p += nextoffset - offset;
*((uint32_t *)p) = cpu_to_fdt32(FDT_NOP);
*((fdt32_t *)p) = cpu_to_fdt32(FDT_NOP);
p += FDT_TAGSIZE;
} while (tag != FDT_END);

View File

@ -66,7 +66,7 @@ int main(int argc, char *argv[])
void *fdt;
const char *p;
int len, multilen;
int n1, n2;
int n1, n2, n3, n4;
test_init(argc, argv);
fdt = load_blob_arg(argc, argv);
@ -92,6 +92,16 @@ int main(int argc, char *argv[])
if ((!streq(p, "/node1") || !streq(p + strlen("/node1") + 1, "/node2")))
FAIL("multiref has wrong value");
/* Check reference to nested nodes with common prefix */
n3 = fdt_path_offset(fdt, "/foo/baz");
if (n3 < 0)
FAIL("fdt_path_offset(/foo/baz): %s", fdt_strerror(n3));
n4 = fdt_path_offset(fdt, "/foobar/baz");
if (n4 < 0)
FAIL("fdt_path_offset(/foobar/baz): %s", fdt_strerror(n4));
check_ref(fdt, n3, "/foobar/baz");
check_ref(fdt, n4, "/foo/baz");
check_rref(fdt);
PASS();

View File

@ -12,4 +12,17 @@
ref = &{/node1}; /* reference after target */
lref = &n1;
};
/* Check references to nested nodes with common prefix */
foobar {
n3: baz {
ref = &{/foo/baz};
lref = &n4;
};
};
foo {
n4: baz {
ref = &{/foobar/baz};
lref = &n3;
};
};
};

16
tests/pci-bridge-bad1.dts Normal file
View File

@ -0,0 +1,16 @@
/dts-v1/;
/ {
compatible = "example,pci-bridge-ok";
#address-cells = < 2 >;
#size-cells = < 2 >;
abadname@0 {
device_type = "pci";
compatible = "example,pci-bridge";
#address-cells = < 3 >;
#size-cells = < 2 >;
reg = <0 0 0 0x1000>;
bus-range = <0 0xff>;
ranges = <0 0 0 0 0 0 0x10000>;
};
};

16
tests/pci-bridge-bad2.dts Normal file
View File

@ -0,0 +1,16 @@
/dts-v1/;
/ {
compatible = "example,pci-bridge-ok";
#address-cells = < 2 >;
#size-cells = < 2 >;
p@0 {
device_type = "pci";
compatible = "example,pci-bridge";
#address-cells = < 3 >;
#size-cells = < 2 >;
reg = <0 0 0 0x1000>;
bus-range = <0 0xff>;
ranges = <0 0 0 0 0 0 0x10000>;
};
};

25
tests/pci-bridge-ok.dts Normal file
View File

@ -0,0 +1,25 @@
/dts-v1/;
/ {
compatible = "example,pci-bridge-ok";
#address-cells = < 2 >;
#size-cells = < 2 >;
pci@0 {
device_type = "pci";
compatible = "example,pci-bridge";
#address-cells = < 3 >;
#size-cells = < 2 >;
reg = <0 0 0 0x1000>;
bus-range = <0 0xff>;
ranges = <0 0 0 0 0 0 0x10000>;
};
pcie@10000000000 {
device_type = "pci";
compatible = "example,pcie-bridge";
#address-cells = < 3 >;
#size-cells = < 2 >;
reg = <0x10 0x00000000 0 0x1000>;
bus-range = <0 0xff>;
ranges = <0 0 0 0 0 0 0x10000>;
};
};

View File

@ -33,7 +33,7 @@
static void test_node(void *fdt, int parent_offset)
{
fdt32_t properties;
uint32_t properties;
const fdt32_t *prop;
int offset, property;
int count;
@ -48,7 +48,7 @@ static void test_node(void *fdt, int parent_offset)
FAIL("Missing/invalid test-properties property at '%s'",
fdt_get_name(fdt, parent_offset, NULL));
}
properties = cpu_to_fdt32(*prop);
properties = fdt32_to_cpu(*prop);
count = 0;
offset = fdt_first_subnode(fdt, parent_offset);

334
tests/pylibfdt_tests.py Normal file
View File

@ -0,0 +1,334 @@
# pylibfdt - Tests for Flat Device Tree manipulation in Python
# Copyright (C) 2017 Google, Inc.
# Written by Simon Glass <sjg@chromium.org>
#
# libfdt is dual licensed: you can use it either under the terms of
# the GPL, or the BSD license, at your option.
#
# a) This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 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 General Public License for more details.
#
# You should have received a copy of the GNU 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
#
# Alternatively,
#
# b) Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
import sys
import types
import unittest
sys.path.insert(0, '../pylibfdt')
import libfdt
from libfdt import FdtException, QUIET_NOTFOUND, QUIET_ALL
def get_err(err_code):
"""Convert an error code into an error message
Args:
err_code: Error code value (FDT_ERR_...)
Returns:
String error code
"""
return 'pylibfdt error %d: %s' % (-err_code, libfdt.strerror(-err_code))
def _ReadFdt(fname):
"""Read a device tree file into an Fdt object, ready for use
Args:
fname: Filename to read from
Returns:
Fdt bytearray suitable for passing to libfdt functions
"""
return libfdt.Fdt(open(fname).read())
class PyLibfdtTests(unittest.TestCase):
"""Test class for pylibfdt
Properties:
fdt: Device tree file used for testing
"""
def setUp(self):
"""Read in the device tree we use for testing"""
self.fdt = _ReadFdt('test_tree1.dtb')
def GetPropList(self, node_path):
"""Read a list of properties from a node
Args:
node_path: Full path to node, e.g. '/subnode@1/subsubnode'
Returns:
List of property names for that node, e.g. ['compatible', 'reg']
"""
prop_list = []
node = self.fdt.path_offset(node_path)
poffset = self.fdt.first_property_offset(node, QUIET_NOTFOUND)
while poffset > 0:
prop = self.fdt.get_property_by_offset(poffset)
prop_list.append(prop.name)
poffset = self.fdt.next_property_offset(poffset, QUIET_NOTFOUND)
return prop_list
def testImport(self):
"""Check that we can import the library correctly"""
self.assertEquals(type(libfdt), types.ModuleType)
def testBadFdt(self):
"""Check that a filename provided accidentally is not accepted"""
with self.assertRaises(FdtException) as e:
fdt = libfdt.Fdt('a string')
self.assertEquals(e.exception.err, -libfdt.BADMAGIC)
def testSubnodeOffset(self):
"""check that we can locate a subnode by name"""
node1 = self.fdt.path_offset('/subnode@1')
self.assertEquals(self.fdt.subnode_offset(0, 'subnode@1'), node1)
with self.assertRaises(FdtException) as e:
self.fdt.subnode_offset(0, 'missing')
self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
node2 = self.fdt.path_offset('/subnode@1/subsubnode')
self.assertEquals(self.fdt.subnode_offset(node1, 'subsubnode'), node2)
def testPathOffset(self):
"""Check that we can find the offset of a node"""
self.assertEquals(self.fdt.path_offset('/'), 0)
self.assertTrue(self.fdt.path_offset('/subnode@1') > 0)
with self.assertRaises(FdtException) as e:
self.fdt.path_offset('/wibble')
self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
self.assertEquals(self.fdt.path_offset('/wibble', QUIET_NOTFOUND),
-libfdt.NOTFOUND)
def testPropertyOffset(self):
"""Walk through all the properties in the root node"""
offset = self.fdt.first_property_offset(0)
self.assertTrue(offset > 0)
for i in range(5):
next_offset = self.fdt.next_property_offset(offset)
self.assertTrue(next_offset > offset)
offset = next_offset
self.assertEquals(self.fdt.next_property_offset(offset, QUIET_NOTFOUND),
-libfdt.NOTFOUND)
def testPropertyOffsetExceptions(self):
"""Check that exceptions are raised as expected"""
with self.assertRaises(FdtException) as e:
self.fdt.first_property_offset(107)
self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
# Quieten the NOTFOUND exception and check that a BADOFFSET
# exception is still raised.
with self.assertRaises(FdtException) as e:
self.fdt.first_property_offset(107, QUIET_NOTFOUND)
self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
with self.assertRaises(FdtException) as e:
self.fdt.next_property_offset(107, QUIET_NOTFOUND)
self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
# Check that NOTFOUND can be quietened.
node = self.fdt.path_offset('/subnode@1/ss1')
self.assertEquals(self.fdt.first_property_offset(node, QUIET_NOTFOUND),
-libfdt.NOTFOUND)
with self.assertRaises(FdtException) as e:
self.fdt.first_property_offset(node)
self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
def testGetName(self):
"""Check that we can get the name of a node"""
self.assertEquals(self.fdt.get_name(0), '')
node = self.fdt.path_offset('/subnode@1/subsubnode')
self.assertEquals(self.fdt.get_name(node), 'subsubnode')
with self.assertRaises(FdtException) as e:
self.fdt.get_name(-2)
self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
def testGetPropertyByOffset(self):
"""Check that we can read the name and contents of a property"""
root = 0
poffset = self.fdt.first_property_offset(root)
prop = self.fdt.get_property_by_offset(poffset)
self.assertEquals(prop.name, 'compatible')
self.assertEquals(prop.value, 'test_tree1\0')
with self.assertRaises(FdtException) as e:
self.fdt.get_property_by_offset(-2)
self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
self.assertEquals(
-libfdt.BADOFFSET,
self.fdt.get_property_by_offset(-2, [libfdt.BADOFFSET]))
def testGetProp(self):
"""Check that we can read the contents of a property by name"""
root = self.fdt.path_offset('/')
value = self.fdt.getprop(root, "compatible")
self.assertEquals(value, 'test_tree1\0')
self.assertEquals(-libfdt.NOTFOUND, self.fdt.getprop(root, 'missing',
QUIET_NOTFOUND))
with self.assertRaises(FdtException) as e:
self.fdt.getprop(root, 'missing')
self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
node = self.fdt.path_offset('/subnode@1/subsubnode')
value = self.fdt.getprop(node, "compatible")
self.assertEquals(value, 'subsubnode1\0subsubnode\0')
def testStrError(self):
"""Check that we can get an error string"""
self.assertEquals(libfdt.strerror(-libfdt.NOTFOUND),
'FDT_ERR_NOTFOUND')
def testFirstNextSubnodeOffset(self):
"""Check that we can walk through subnodes"""
node_list = []
node = self.fdt.first_subnode(0, QUIET_NOTFOUND)
while node >= 0:
node_list.append(self.fdt.get_name(node))
node = self.fdt.next_subnode(node, QUIET_NOTFOUND)
self.assertEquals(node_list, ['subnode@1', 'subnode@2'])
def testFirstNextSubnodeOffsetExceptions(self):
"""Check except handling for first/next subnode functions"""
node = self.fdt.path_offset('/subnode@1/subsubnode', QUIET_NOTFOUND)
self.assertEquals(self.fdt.first_subnode(node, QUIET_NOTFOUND),
-libfdt.NOTFOUND)
with self.assertRaises(FdtException) as e:
self.fdt.first_subnode(node)
self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
node = self.fdt.path_offset('/subnode@1/ss1', QUIET_NOTFOUND)
self.assertEquals(self.fdt.next_subnode(node, QUIET_NOTFOUND),
-libfdt.NOTFOUND)
with self.assertRaises(FdtException) as e:
self.fdt.next_subnode(node)
self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
def testDeleteProperty(self):
"""Test that we can delete a property"""
node_name = '/subnode@1'
self.assertEquals(self.GetPropList(node_name),
['compatible', 'reg', 'prop-int'])
node = self.fdt.path_offset('/%s' % node_name)
self.assertEquals(self.fdt.delprop(node, 'reg'), 0)
self.assertEquals(self.GetPropList(node_name),
['compatible', 'prop-int'])
def testHeader(self):
"""Test that we can access the header values"""
self.assertEquals(self.fdt.totalsize(), len(self.fdt._fdt))
self.assertEquals(self.fdt.off_dt_struct(), 88)
def testPack(self):
"""Test that we can pack the tree after deleting something"""
orig_size = self.fdt.totalsize()
node = self.fdt.path_offset('/subnode@2', QUIET_NOTFOUND)
self.assertEquals(self.fdt.delprop(node, 'prop-int'), 0)
self.assertEquals(orig_size, self.fdt.totalsize())
self.assertEquals(self.fdt.pack(), 0)
self.assertTrue(self.fdt.totalsize() < orig_size)
def testBadPropertyOffset(self):
"""Test that bad property offsets are detected"""
with self.assertRaises(FdtException) as e:
self.fdt.get_property_by_offset(13)
self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
with self.assertRaises(FdtException) as e:
self.fdt.first_property_offset(3)
self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
with self.assertRaises(FdtException) as e:
self.fdt.next_property_offset(3)
self.assertEquals(e.exception.err, -libfdt.BADOFFSET)
def testBadPathOffset(self):
"""Test that bad path names are detected"""
with self.assertRaisesRegexp(FdtException, get_err(libfdt.BADPATH)):
self.fdt.path_offset('not-present')
def testQuietAll(self):
"""Check that exceptions can be masked by QUIET_ALL"""
self.assertEquals(-libfdt.NOTFOUND,
self.fdt.path_offset('/missing', QUIET_ALL))
self.assertEquals(-libfdt.BADOFFSET,
self.fdt.get_property_by_offset(13, QUIET_ALL))
self.assertEquals(-libfdt.BADPATH,
self.fdt.path_offset('missing', QUIET_ALL))
def testIntegers(self):
"""Check that integers can be passed and returned"""
self.assertEquals(0, libfdt.fdt_get_phandle(self.fdt._fdt, 0))
node2 = self.fdt.path_offset('/subnode@2')
self.assertEquals(0x2000, libfdt.fdt_get_phandle(self.fdt._fdt, node2))
def testGetPhandle(self):
"""Test for the get_phandle() method"""
self.assertEquals(0, self.fdt.get_phandle(0))
node2 = self.fdt.path_offset('/subnode@2')
self.assertEquals(0x2000, self.fdt.get_phandle(node2))
def testParentOffset(self):
"""Test for the parent_offset() method"""
self.assertEquals(-libfdt.NOTFOUND,
self.fdt.parent_offset(0, QUIET_NOTFOUND))
with self.assertRaises(FdtException) as e:
self.fdt.parent_offset(0)
self.assertEquals(e.exception.err, -libfdt.NOTFOUND)
node1 = self.fdt.path_offset('/subnode@2')
self.assertEquals(0, self.fdt.parent_offset(node1))
node2 = self.fdt.path_offset('/subnode@2/subsubnode@0')
self.assertEquals(node1, self.fdt.parent_offset(node2))
def testNodeOffsetByPhandle(self):
"""Test for the node_offset_by_phandle() method"""
self.assertEquals(-libfdt.NOTFOUND,
self.fdt.node_offset_by_phandle(1, QUIET_NOTFOUND))
node1 = self.fdt.path_offset('/subnode@2')
self.assertEquals(node1, self.fdt.node_offset_by_phandle(0x2000))
node2 = self.fdt.path_offset('/subnode@2/subsubnode@0')
self.assertEquals(node2, self.fdt.node_offset_by_phandle(0x2001))
if __name__ == "__main__":
unittest.main()

View File

@ -29,7 +29,7 @@
static void check_ref(const void *fdt, int node, uint32_t checkref)
{
const uint32_t *p;
const fdt32_t *p;
uint32_t ref;
int len;
@ -58,7 +58,7 @@ static void check_ref(const void *fdt, int node, uint32_t checkref)
static void check_rref(const void *fdt)
{
const uint32_t *p;
const fdt32_t *p;
uint32_t ref;
int len;

View File

@ -6,6 +6,11 @@ if [ -z "$CC" ]; then
CC=gcc
fi
# stat differs between platforms
if [ -z "$STATSZ" ]; then
STATSZ="stat -c %s"
fi
export QUIET_TEST=1
STOP_ON_FAIL=0
@ -114,7 +119,7 @@ run_wrap_error_test () {
# $2: align base
check_align () {
shorten_echo "check_align $@: "
local size=$(stat -c %s "$1")
local size=$($STATSZ "$1")
local align="$2"
(
if [ $(($size % $align)) -eq 0 ] ;then
@ -157,7 +162,15 @@ run_fdtdump_test() {
file="$1"
shorten_echo fdtdump-runtest.sh "$file"
printf ": "
base_run_test sh fdtdump-runtest.sh "$file"
base_run_test sh fdtdump-runtest.sh "$file" 2>/dev/null
}
run_fdtoverlay_test() {
expect="$1"
shift
shorten_echo fdtoverlay-runtest.sh "$expect" "$@"
printf ": "
base_run_test sh fdtoverlay-runtest.sh "$expect" "$@"
}
BAD_FIXUP_TREES="bad_index \
@ -197,6 +210,12 @@ libfdt_overlay_tests () {
run_test overlay overlay_base_manual_symbols.test.dtb overlay_overlay_manual_fixups.test.dtb
# test simplified plugin syntax
run_dtc_test -@ -I dts -O dtb -o overlay_overlay_simple.dtb overlay_overlay_simple.dts
# verify non-generation of local fixups
run_test check_path overlay_overlay_simple.dtb not-exists "/__local_fixups__"
# Bad fixup tests
for test in $BAD_FIXUP_TREES; do
tree="overlay_bad_fixup_$test"
@ -420,7 +439,7 @@ dtc_tests () {
run_dtc_test -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts
run_test path-references dtc_path-references.test.dtb
run_test phandle_format dtc_references.test.dtb both
run_test phandle_format dtc_references.test.dtb epapr
for f in legacy epapr both; do
run_dtc_test -I dts -O dtb -H $f -o dtc_references.test.$f.dtb references.dts
run_test phandle_format dtc_references.test.$f.dtb $f
@ -532,7 +551,10 @@ dtc_tests () {
check_tests bad-name-property.dts name_properties
check_tests bad-ncells.dts address_cells_is_cell size_cells_is_cell interrupt_cells_is_cell
check_tests bad-string-props.dts device_type_is_string model_is_string status_is_string
check_tests bad-string-props.dts device_type_is_string model_is_string status_is_string label_is_string compatible_is_string_list names_is_string_list
check_tests bad-chosen.dts chosen_node_is_root
check_tests bad-chosen.dts chosen_node_bootargs
check_tests bad-chosen.dts chosen_node_stdout_path
check_tests bad-reg-ranges.dts reg_format ranges_format
check_tests bad-empty-ranges.dts ranges_format
check_tests reg-ranges-root.dts reg_format ranges_format
@ -540,6 +562,12 @@ dtc_tests () {
check_tests obsolete-chosen-interrupt-controller.dts obsolete_chosen_interrupt_controller
check_tests reg-without-unit-addr.dts unit_address_vs_reg
check_tests unit-addr-without-reg.dts unit_address_vs_reg
check_tests unit-addr-leading-0x.dts unit_address_format
check_tests unit-addr-leading-0s.dts unit_address_format
check_tests bad-phandle-cells.dts interrupts_extended_property
check_tests bad-gpio.dts gpios_property
run_sh_test dtc-checkfails.sh deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb bad-gpio.dts
check_tests bad-interrupt-cells.dts interrupts_property
run_sh_test dtc-checkfails.sh node_name_chars -- -I dtb -O dtb bad_node_char.dtb
run_sh_test dtc-checkfails.sh node_name_format -- -I dtb -O dtb bad_node_format.dtb
run_sh_test dtc-checkfails.sh prop_name_chars -- -I dtb -O dtb bad_prop_char.dtb
@ -554,6 +582,10 @@ dtc_tests () {
run_test check_path test_tree1.dtb exists "/subnode@1"
run_test check_path test_tree1.dtb not-exists "/subnode@10"
check_tests pci-bridge-ok.dts -n pci_bridge
check_tests pci-bridge-bad1.dts pci_bridge
check_tests pci-bridge-bad2.dts pci_bridge
# Check warning options
run_sh_test dtc-checkfails.sh address_cells_is_cell interrupt_cells_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb bad-ncells.dts
run_sh_test dtc-fails.sh -n test-warn-output.test.dtb -I dts -O dtb bad-ncells.dts
@ -690,7 +722,7 @@ fdtput_tests () {
text=lorem.txt
# Allow just enough space for $text
run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb $dts
# run_fdtput_test <expected-result> <file> <node> <property> <flags> <value>
run_fdtput_test "a_model" $dtb / model -ts "a_model"
@ -709,7 +741,7 @@ fdtput_tests () {
run_fdtput_test "$(cat $text $text)" $dtb /randomnode blob -ts "$(cat $text $text)"
# Start again with a fresh dtb
run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb $dts
# Node creation
run_wrap_error_test $DTPUT $dtb -c /baldrick sod
@ -737,7 +769,7 @@ fdtput_tests () {
run_wrap_test $DTPUT $dtb -cp /chosen/son
# Start again with a fresh dtb
run_dtc_test -O dtb -p $(stat -c %s $text) -o $dtb $dts
run_dtc_test -O dtb -p $($STATSZ $text) -o $dtb $dts
# Node delete
run_wrap_test $DTPUT $dtb -c /chosen/node1 /chosen/node2 /chosen/node3
@ -769,6 +801,55 @@ fdtdump_tests () {
run_fdtdump_test fdtdump.dts
}
fdtoverlay_tests() {
base=overlay_base.dts
basedtb=overlay_base.fdoverlay.test.dtb
overlay=overlay_overlay_manual_fixups.dts
overlaydtb=overlay_overlay_manual_fixups.fdoverlay.test.dtb
targetdtb=target.fdoverlay.test.dtb
run_dtc_test -@ -I dts -O dtb -o $basedtb $base
run_dtc_test -@ -I dts -O dtb -o $overlaydtb $overlay
# test that the new property is installed
run_fdtoverlay_test foobar "/test-node" "test-str-property" "-ts" ${basedtb} ${targetdtb} ${overlaydtb}
stacked_base=stacked_overlay_base.dts
stacked_basedtb=stacked_overlay_base.fdtoverlay.test.dtb
stacked_bar=stacked_overlay_bar.dts
stacked_bardtb=stacked_overlay_bar.fdtoverlay.test.dtb
stacked_baz=stacked_overlay_baz.dts
stacked_bazdtb=stacked_overlay_baz.fdtoverlay.test.dtb
stacked_targetdtb=stacked_overlay_target.fdtoverlay.test.dtb
run_dtc_test -@ -I dts -O dtb -o $stacked_basedtb $stacked_base
run_dtc_test -@ -I dts -O dtb -o $stacked_bardtb $stacked_bar
run_dtc_test -@ -I dts -O dtb -o $stacked_bazdtb $stacked_baz
# test that baz correctly inserted the property
run_fdtoverlay_test baz "/foonode/barnode/baznode" "baz-property" "-ts" ${stacked_basedtb} ${stacked_targetdtb} ${stacked_bardtb} ${stacked_bazdtb}
}
pylibfdt_tests () {
TMP=/tmp/tests.stderr.$$
python pylibfdt_tests.py -v 2> $TMP
# Use the 'ok' message meaning the test passed, 'ERROR' meaning it failed
# and the summary line for total tests (e.g. 'Ran 17 tests in 0.002s').
# We could add pass + fail to get total tests, but this provides a useful
# sanity check.
pass_count=$(grep "\.\.\. ok$" $TMP | wc -l)
fail_count=$(grep "^ERROR: " $TMP | wc -l)
total_tests=$(sed -n 's/^Ran \([0-9]*\) tests.*$/\1/p' $TMP)
cat $TMP
rm $TMP
# Extract the test results and add them to our totals
tot_fail=$((tot_fail + $fail_count))
tot_pass=$((tot_pass + $pass_count))
tot_tests=$((tot_tests + $total_tests))
}
while getopts "vt:me" ARG ; do
case $ARG in
"v")
@ -787,7 +868,12 @@ while getopts "vt:me" ARG ; do
done
if [ -z "$TESTSETS" ]; then
TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump"
TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump fdtoverlay"
# Test pylibfdt if the libfdt Python module is available.
if [ -f ../pylibfdt/_libfdt.so ]; then
TESTSETS="$TESTSETS pylibfdt"
fi
fi
# Make sure we don't have stale blobs lying around
@ -816,6 +902,12 @@ for set in $TESTSETS; do
"fdtdump")
fdtdump_tests
;;
"pylibfdt")
pylibfdt_tests
;;
"fdtoverlay")
fdtoverlay_tests
;;
esac
done
@ -830,3 +922,4 @@ fi
echo "* Strange test result: $tot_strange"
echo "**********"
[ "$tot_tests" -eq "$tot_pass" ] || exit 1

View File

@ -54,9 +54,9 @@ int main(int argc, char *argv[])
TEST_CHAR4,
TEST_CHAR5,
TEST_VALUE_1 >> 24};
uint16_t expected_16[6];
uint32_t expected_32[6];
uint64_t expected_64[6];
fdt16_t expected_16[6];
fdt32_t expected_32[6];
fdt64_t expected_64[6];
int i;
for (i = 0; i < 5; ++i) {

View File

@ -0,0 +1,13 @@
/dts-v1/;
/plugin/;
/ {
fragment@1 {
target = <&foo>;
__overlay__ {
overlay-1-property;
bar: barnode {
bar-property = "bar";
};
};
};
};

View File

@ -0,0 +1,6 @@
/dts-v1/;
/ {
foo: foonode {
foo-property = "foo";
};
};

View File

@ -0,0 +1,13 @@
/dts-v1/;
/plugin/;
/ {
fragment@1 {
target = <&bar>;
__overlay__ {
overlay-2-property;
baz: baznode {
baz-property = "baz";
};
};
};
};

View File

@ -60,10 +60,11 @@ static void check_expected_failure(const void *fdt, const char *path,
FAIL("empty string not found in #address-cells: %d\n", err);
/*
* fdt_get_string() can successfully extract strings from non-string
* properties. This is because it doesn't necessarily parse the whole
* property value, which would be necessary for it to determine if a
* valid string or string list is present.
* fdt_getprop_string() can successfully extract strings from
* non-string properties. This is because it doesn't
* necessarily parse the whole property value, which would be
* necessary for it to determine if a valid string or string
* list is present.
*/
}

View File

@ -33,7 +33,7 @@
static void test_node(void *fdt, int parent_offset)
{
fdt32_t subnodes;
uint32_t subnodes;
const fdt32_t *prop;
int offset;
int count;
@ -45,7 +45,7 @@ static void test_node(void *fdt, int parent_offset)
FAIL("Missing/invalid subnodes property at '%s'",
fdt_get_name(fdt, parent_offset, NULL));
}
subnodes = cpu_to_fdt32(*prop);
subnodes = fdt32_to_cpu(*prop);
count = 0;
fdt_for_each_subnode(offset, fdt, parent_offset)

View File

@ -42,14 +42,14 @@ static void realloc_fdt(void **fdt, size_t *size, bool created)
switch (alloc_mode) {
case FIXED:
if (!(*fdt))
fdt = xmalloc(*size);
*fdt = xmalloc(*size);
else
FAIL("Ran out of space");
return;
case RESIZE:
if (!(*fdt)) {
fdt = xmalloc(SPACE);
*fdt = xmalloc(SPACE);
} else if (*size < SPACE) {
*size += 1;
fdt_resize(*fdt, *fdt, *size);
@ -85,6 +85,9 @@ int main(int argc, char *argv[])
size_t size;
int err;
bool created = false;
void *place;
const char place_str[] = "this is a placeholder string\0string2";
int place_len = sizeof(place_str);
test_init(argc, argv);
@ -108,6 +111,8 @@ int main(int argc, char *argv[])
CONFIG("Bad allocation mode \"%s\" specified",
argv[1]);
}
} else {
CONFIG("sw_tree1 <dtb file> [<allocation mode>]");
}
fdt = xmalloc(size);
@ -135,6 +140,8 @@ int main(int argc, char *argv[])
CHECK(fdt_begin_node(fdt, "subsubnode"));
CHECK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode",
23));
CHECK(fdt_property_placeholder(fdt, "placeholder", place_len, &place));
memcpy(place, place_str, place_len);
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_end_node(fdt));
CHECK(fdt_begin_node(fdt, "ss1"));

View File

@ -18,6 +18,7 @@
subsubnode {
compatible = "subsubnode1", "subsubnode";
placeholder = "this is a placeholder string", "string2";
prop-int = <0xdeadbeef>;
};

View File

@ -18,6 +18,7 @@
subsubnode {
compatible = "subsubnode1", "subsubnode";
placeholder = "this is a placeholder string", "string2";
prop-int = <0xdeadbeef>;
};

View File

@ -4,15 +4,25 @@
#define ASM_CONST_LL(x) (x##ULL)
#endif
#define TEST_ADDR_1 ASM_CONST_LL(0xdeadbeef00000000)
#define TEST_SIZE_1 ASM_CONST_LL(0x100000)
#define TEST_ADDR_2 ASM_CONST_LL(123456789)
#define TEST_SIZE_2 ASM_CONST_LL(010000)
#define TEST_ADDR_1H ASM_CONST_LL(0xdeadbeef)
#define TEST_ADDR_1L ASM_CONST_LL(0x00000000)
#define TEST_ADDR_1 ((TEST_ADDR_1H << 32) | TEST_ADDR_1L)
#define TEST_SIZE_1H ASM_CONST_LL(0x00000000)
#define TEST_SIZE_1L ASM_CONST_LL(0x00100000)
#define TEST_SIZE_1 ((TEST_SIZE_1H << 32) | TEST_SIZE_1L)
#define TEST_ADDR_2H ASM_CONST_LL(0)
#define TEST_ADDR_2L ASM_CONST_LL(123456789)
#define TEST_ADDR_2 ((TEST_ADDR_2H << 32) | TEST_ADDR_2L)
#define TEST_SIZE_2H ASM_CONST_LL(0)
#define TEST_SIZE_2L ASM_CONST_LL(010000)
#define TEST_SIZE_2 ((TEST_SIZE_2H << 32) | TEST_SIZE_2L)
#define TEST_VALUE_1 0xdeadbeef
#define TEST_VALUE_2 123456789
#define TEST_VALUE64_1 ASM_CONST_LL(0xdeadbeef01abcdef)
#define TEST_VALUE64_1H ASM_CONST_LL(0xdeadbeef)
#define TEST_VALUE64_1L ASM_CONST_LL(0x01abcdef)
#define TEST_VALUE64_1 ((TEST_VALUE64_1H << 32) | TEST_VALUE64_1L)
#define PHANDLE_1 0x2000
#define PHANDLE_2 0x2001
@ -31,10 +41,10 @@
#define TEST_CHAR5 '\xff'
#ifndef __ASSEMBLY__
extern struct fdt_header _test_tree1;
extern struct fdt_header _truncated_property;
extern struct fdt_header _bad_node_char;
extern struct fdt_header _bad_node_format;
extern struct fdt_header _bad_prop_char;
extern struct fdt_header _ovf_size_strings;
extern struct fdt_header test_tree1;
extern struct fdt_header truncated_property;
extern struct fdt_header bad_node_char;
extern struct fdt_header bad_node_format;
extern struct fdt_header bad_prop_char;
extern struct fdt_header ovf_size_strings;
#endif /* ! __ASSEMBLY */

View File

@ -1,5 +1,5 @@
#ifndef _TESTS_H
#define _TESTS_H
#ifndef TESTS_H
#define TESTS_H
/*
* libfdt - Flat Device Tree manipulation
* Testcase definitions
@ -99,7 +99,7 @@ void check_property(void *fdt, int nodeoffset, const char *name,
int len, const void *val);
#define check_property_cell(fdt, nodeoffset, name, val) \
({ \
uint32_t x = cpu_to_fdt32(val); \
fdt32_t x = cpu_to_fdt32(val); \
check_property(fdt, nodeoffset, name, sizeof(x), &x); \
})
@ -108,12 +108,12 @@ const void *check_getprop(void *fdt, int nodeoffset, const char *name,
int len, const void *val);
#define check_getprop_cell(fdt, nodeoffset, name, val) \
({ \
uint32_t x = cpu_to_fdt32(val); \
fdt32_t x = cpu_to_fdt32(val); \
check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
})
#define check_getprop_64(fdt, nodeoffset, name, val) \
({ \
uint64_t x = cpu_to_fdt64(val); \
fdt64_t x = cpu_to_fdt64(val); \
check_getprop(fdt, nodeoffset, name, sizeof(x), &x); \
})
#define check_getprop_string(fdt, nodeoffset, name, s) \
@ -126,4 +126,4 @@ void *open_blob_rw(void *blob);
#include "util.h"
#endif /* _TESTS_H */
#endif /* TESTS_H */

View File

@ -22,6 +22,7 @@ DTC=../dtc
DTGET=../fdtget
DTPUT=../fdtput
FDTDUMP=../fdtdump
FDTOVERLAY=../fdtoverlay
verbose_run () {
if [ -z "$QUIET_TEST" ]; then

View File

@ -7,20 +7,9 @@
.byte ((val) >> 8) & 0xff ; \
.byte (val) & 0xff ;
#define FDTQUAD(val) \
.byte ((val) >> 56) & 0xff ; \
.byte ((val) >> 48) & 0xff ; \
.byte ((val) >> 40) & 0xff ; \
.byte ((val) >> 32) & 0xff ; \
.byte ((val) >> 24) & 0xff ; \
.byte ((val) >> 16) & 0xff ; \
.byte ((val) >> 8) & 0xff ; \
.byte (val) & 0xff ;
#define TREE_HDR(tree) \
.balign 8 ; \
.globl _##tree ; \
_##tree: \
.globl tree ; \
tree: \
FDTLONG(FDT_MAGIC) ; \
FDTLONG(tree##_end - tree) ; \
@ -33,14 +22,16 @@ tree: \
FDTLONG(tree##_strings_end - tree##_strings) ; \
FDTLONG(tree##_struct_end - tree##_struct) ;
#define RSVMAP_ENTRY(addr, len) \
FDTQUAD(addr) ; \
FDTQUAD(len) ; \
#define RSVMAP_ENTRY(addrh, addrl, lenh, lenl) \
FDTLONG(addrh) ; \
FDTLONG(addrl) ; \
FDTLONG(lenh) ; \
FDTLONG(lenl)
#define EMPTY_RSVMAP(tree) \
.balign 8 ; \
tree##_rsvmap: ; \
RSVMAP_ENTRY(0, 0) \
RSVMAP_ENTRY(0, 0, 0, 0) \
tree##_rsvmap_end: ;
#define PROPHDR(tree, name, len) \
@ -52,9 +43,10 @@ tree##_rsvmap_end: ;
PROPHDR(tree, name, 4) \
FDTLONG(val) ;
#define PROP_INT64(tree, name, val) \
#define PROP_INT64(tree, name, valh, vall) \
PROPHDR(tree, name, 8) \
FDTQUAD(val) ;
FDTLONG(valh) ; \
FDTLONG(vall) ;
#define PROP_STR(tree, name, str) \
PROPHDR(tree, name, 55f - 54f) \
@ -81,16 +73,16 @@ tree##_##name: ; \
.balign 8
test_tree1_rsvmap:
RSVMAP_ENTRY(TEST_ADDR_1, TEST_SIZE_1)
RSVMAP_ENTRY(TEST_ADDR_2, TEST_SIZE_2)
RSVMAP_ENTRY(0, 0)
RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L)
RSVMAP_ENTRY(TEST_ADDR_2H, TEST_ADDR_2L, TEST_SIZE_2H, TEST_SIZE_2L)
RSVMAP_ENTRY(0, 0, 0, 0)
test_tree1_rsvmap_end:
test_tree1_struct:
BEGIN_NODE("")
PROP_STR(test_tree1, compatible, "test_tree1")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1)
PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1H, TEST_VALUE64_1L)
PROP_STR(test_tree1, prop_str, TEST_STRING_1)
PROP_INT(test_tree1, address_cells, 1)
PROP_INT(test_tree1, size_cells, 0)
@ -102,6 +94,7 @@ test_tree1_struct:
BEGIN_NODE("subsubnode")
PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode")
PROP_STR(test_tree1, placeholder, "this is a placeholder string\0string2")
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
END_NODE
@ -141,6 +134,7 @@ test_tree1_strings:
STRING(test_tree1, linux_phandle, "linux,phandle")
STRING(test_tree1, phandle, "phandle")
STRING(test_tree1, reg, "reg")
STRING(test_tree1, placeholder, "placeholder")
STRING(test_tree1, address_cells, "#address-cells")
STRING(test_tree1, size_cells, "#size-cells")
test_tree1_strings_end:
@ -213,8 +207,7 @@ bad_prop_char_end:
/* overflow_size_strings */
.balign 8
.globl _ovf_size_strings
_ovf_size_strings:
.globl ovf_size_strings
ovf_size_strings:
FDTLONG(FDT_MAGIC)
FDTLONG(ovf_size_strings_end - ovf_size_strings)

View File

@ -30,7 +30,7 @@
int main(int argc, char *argv[])
{
void *fdt = &_truncated_property;
void *fdt = &truncated_property;
const void *prop;
int len;

View File

@ -0,0 +1,12 @@
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
bus {
node@001 {
reg = <1 0>;
};
};
};

View File

@ -0,0 +1,12 @@
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
bus {
node@0x1 {
reg = <1 0>;
};
};
};

View File

@ -36,13 +36,13 @@ struct val_label {
int propoff;
};
struct val_label labels1[] = {
static struct val_label labels1[] = {
{ "start1", 0 },
{ "mid1", 2 },
{ "end1", -1 },
};
struct val_label labels2[] = {
static struct val_label labels2[] = {
{ "start2", 0 },
{ "innerstart2", 0 },
{ "innermid2", 4 },
@ -50,7 +50,7 @@ struct val_label labels2[] = {
{ "end2", -1 },
};
struct val_label labels3[] = {
static struct val_label labels3[] = {
{ "start3", 0 },
{ "innerstart3", 0 },
{ "innermid3", 1 },

View File

@ -137,7 +137,7 @@ static void write_propval_string(FILE *f, struct data val)
static void write_propval_cells(FILE *f, struct data val)
{
void *propend = val.val + val.len;
cell_t *cp = (cell_t *)val.val;
fdt32_t *cp = (fdt32_t *)val.val;
struct marker *m = val.markers;
fprintf(f, "<");
@ -275,8 +275,8 @@ void dt_to_source(FILE *f, struct dt_info *dti)
for_each_label(re->labels, l)
fprintf(f, "%s: ", l->label);
fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
(unsigned long long)re->re.address,
(unsigned long long)re->re.size);
(unsigned long long)re->address,
(unsigned long long)re->size);
}
write_tree_source_node(f, dti->dt, 0);

11
util.c
View File

@ -396,7 +396,7 @@ void utilfdt_print_data(const char *data, int len)
} while (s < data + len);
} else if ((len % 4) == 0) {
const uint32_t *cell = (const uint32_t *)data;
const fdt32_t *cell = (const fdt32_t *)data;
printf(" = <");
for (i = 0, len /= 4; i < len; i++)
@ -412,15 +412,16 @@ void utilfdt_print_data(const char *data, int len)
}
}
void util_version(void)
void NORETURN util_version(void)
{
printf("Version: %s\n", DTC_VERSION);
exit(0);
}
void util_usage(const char *errmsg, const char *synopsis,
const char *short_opts, struct option const long_opts[],
const char * const opts_help[])
void NORETURN util_usage(const char *errmsg, const char *synopsis,
const char *short_opts,
struct option const long_opts[],
const char * const opts_help[])
{
FILE *fp = errmsg ? stderr : stdout;
const char a_arg[] = "<arg>";

41
util.h
View File

@ -1,5 +1,5 @@
#ifndef _UTIL_H
#define _UTIL_H
#ifndef UTIL_H
#define UTIL_H
#include <stdarg.h>
#include <stdbool.h>
@ -25,15 +25,20 @@
* USA
*/
#ifdef __GNUC__
#define PRINTF(i, j) __attribute__((format (printf, i, j)))
#define NORETURN __attribute__((noreturn))
#else
#define PRINTF(i, j)
#define NORETURN
#endif
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#ifdef __GNUC__
static inline void
__attribute__((noreturn)) __attribute__((format (printf, 1, 2)))
die(const char *str, ...)
#else
static inline void die(const char *str, ...)
#endif
#define stringify(s) stringify_(s)
#define stringify_(s) #s
static inline void NORETURN PRINTF(1, 2) die(const char *str, ...)
{
va_list ap;
@ -66,12 +71,7 @@ static inline void *xrealloc(void *p, size_t len)
extern char *xstrdup(const char *s);
#ifdef __GNUC__
extern int __attribute__((format (printf, 2, 3)))
xasprintf(char **strp, const char *fmt, ...);
#else
extern int xasprintf(char **strp, const char *fmt, ...);
#endif
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
extern char *join_path(const char *path, const char *name);
/**
@ -200,7 +200,7 @@ void utilfdt_print_data(const char *data, int len);
/**
* Show source version and exit
*/
void util_version(void) __attribute__((noreturn));
void NORETURN util_version(void);
/**
* Show usage and exit
@ -214,9 +214,10 @@ void util_version(void) __attribute__((noreturn));
* @param long_opts The structure of long options
* @param opts_help An array of help strings (should align with long_opts)
*/
void util_usage(const char *errmsg, const char *synopsis,
const char *short_opts, struct option const long_opts[],
const char * const opts_help[]) __attribute__((noreturn));
void NORETURN util_usage(const char *errmsg, const char *synopsis,
const char *short_opts,
struct option const long_opts[],
const char * const opts_help[]);
/**
* Show usage and exit
@ -262,4 +263,4 @@ void util_usage(const char *errmsg, const char *synopsis,
case 'V': util_version(); \
case '?': usage("unknown option");
#endif /* _UTIL_H */
#endif /* UTIL_H */