Import dtc 1.4.6
This commit is contained in:
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
@ -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
|
||||
|
72
Makefile
72
Makefile
@ -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 $@
|
||||
|
@ -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
77
README
@ -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
717
checks.c
@ -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, ®_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, ®_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, ®_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, ®_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,
|
||||
};
|
||||
|
@ -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
16
data.c
@ -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)
|
||||
|
@ -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, ...);
|
||||
|
||||
%}
|
||||
|
||||
|
27
dtc-parser.y
27
dtc-parser.y
@ -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
14
dtc.c
@ -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
22
dtc.h
@ -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 */
|
||||
|
@ -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
|
||||
|
51
fdtget.c
51
fdtget.c
@ -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
175
fdtoverlay.c
Normal 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;
|
||||
}
|
10
fdtput.c
10
fdtput.c
@ -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,
|
||||
|
60
flattree.c
60
flattree.c
@ -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);
|
||||
|
||||
|
10
libfdt/fdt.c
10
libfdt/fdt.c
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize)
|
||||
|
||||
return fdt_open_into(buf, buf, bufsize);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
114
libfdt/fdt_rw.c
114
libfdt/fdt_rw.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
53
livetree.c
53
livetree.c
@ -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;
|
||||
|
||||
|
24
pylibfdt/Makefile.pylibfdt
Normal file
24
pylibfdt/Makefile.pylibfdt
Normal 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
493
pylibfdt/libfdt.i
Normal 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
121
pylibfdt/setup.py
Executable 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'],
|
||||
)
|
17
srcpos.h
17
srcpos.h
@ -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 */
|
||||
|
@ -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
10
tests/bad-chosen.dts
Normal file
@ -0,0 +1,10 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
node2 {
|
||||
chosen {
|
||||
bootargs = <0xdeadbeef>;
|
||||
stdout-path = <1>;
|
||||
};
|
||||
};
|
||||
};
|
13
tests/bad-gpio.dts
Normal file
13
tests/bad-gpio.dts
Normal 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>;
|
||||
};
|
||||
};
|
12
tests/bad-interrupt-cells.dts
Normal file
12
tests/bad-interrupt-cells.dts
Normal file
@ -0,0 +1,12 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
interrupt-parent = <&intc>;
|
||||
intc: interrupt-controller {
|
||||
#interrupt-cells = <3>;
|
||||
};
|
||||
|
||||
node {
|
||||
interrupts = <1>;
|
||||
};
|
||||
};
|
11
tests/bad-phandle-cells.dts
Normal file
11
tests/bad-phandle-cells.dts
Normal file
@ -0,0 +1,11 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
intc: interrupt-controller {
|
||||
#interrupt-cells = <3>;
|
||||
};
|
||||
|
||||
node {
|
||||
interrupts-extended = <&intc>;
|
||||
};
|
||||
};
|
@ -4,4 +4,11 @@
|
||||
device_type = <0xdeadbeef>;
|
||||
model = <0xdeadbeef>;
|
||||
status = <0xdeadbeef>;
|
||||
label = <0xdeadbeef>;
|
||||
|
||||
foobar-names = "foo", <1>;
|
||||
|
||||
node {
|
||||
compatible = "good", <0xdeadbeef>;
|
||||
};
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "tests.h"
|
||||
#include "testdata.h"
|
||||
|
||||
int notequal; /* = 0 */
|
||||
static int notequal; /* = 0 */
|
||||
|
||||
#define MISMATCH(fmt, ...) \
|
||||
do { \
|
||||
|
@ -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;
|
||||
|
@ -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
40
tests/fdtoverlay-runtest.sh
Executable 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
|
@ -5,6 +5,7 @@
|
||||
|
||||
subsubnode {
|
||||
compatible = "subsubnode1", "subsubnode";
|
||||
placeholder = "this is a placeholder string", "string2";
|
||||
prop-int = <0xdeadbeef>;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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__); \
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
16
tests/pci-bridge-bad1.dts
Normal 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
16
tests/pci-bridge-bad2.dts
Normal 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
25
tests/pci-bridge-ok.dts
Normal 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>;
|
||||
};
|
||||
};
|
@ -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
334
tests/pylibfdt_tests.py
Normal 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()
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
13
tests/stacked_overlay_bar.dts
Normal file
13
tests/stacked_overlay_bar.dts
Normal file
@ -0,0 +1,13 @@
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
/ {
|
||||
fragment@1 {
|
||||
target = <&foo>;
|
||||
__overlay__ {
|
||||
overlay-1-property;
|
||||
bar: barnode {
|
||||
bar-property = "bar";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
6
tests/stacked_overlay_base.dts
Normal file
6
tests/stacked_overlay_base.dts
Normal file
@ -0,0 +1,6 @@
|
||||
/dts-v1/;
|
||||
/ {
|
||||
foo: foonode {
|
||||
foo-property = "foo";
|
||||
};
|
||||
};
|
13
tests/stacked_overlay_baz.dts
Normal file
13
tests/stacked_overlay_baz.dts
Normal file
@ -0,0 +1,13 @@
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
/ {
|
||||
fragment@1 {
|
||||
target = <&bar>;
|
||||
__overlay__ {
|
||||
overlay-2-property;
|
||||
baz: baznode {
|
||||
baz-property = "baz";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -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.
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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"));
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
subsubnode {
|
||||
compatible = "subsubnode1", "subsubnode";
|
||||
placeholder = "this is a placeholder string", "string2";
|
||||
prop-int = <0xdeadbeef>;
|
||||
};
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
subsubnode {
|
||||
compatible = "subsubnode1", "subsubnode";
|
||||
placeholder = "this is a placeholder string", "string2";
|
||||
prop-int = <0xdeadbeef>;
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -22,6 +22,7 @@ DTC=../dtc
|
||||
DTGET=../fdtget
|
||||
DTPUT=../fdtput
|
||||
FDTDUMP=../fdtdump
|
||||
FDTOVERLAY=../fdtoverlay
|
||||
|
||||
verbose_run () {
|
||||
if [ -z "$QUIET_TEST" ]; then
|
||||
|
@ -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)
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *fdt = &_truncated_property;
|
||||
void *fdt = &truncated_property;
|
||||
const void *prop;
|
||||
int len;
|
||||
|
||||
|
12
tests/unit-addr-leading-0s.dts
Normal file
12
tests/unit-addr-leading-0s.dts
Normal file
@ -0,0 +1,12 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
bus {
|
||||
node@001 {
|
||||
reg = <1 0>;
|
||||
};
|
||||
};
|
||||
};
|
12
tests/unit-addr-leading-0x.dts
Normal file
12
tests/unit-addr-leading-0x.dts
Normal file
@ -0,0 +1,12 @@
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
bus {
|
||||
node@0x1 {
|
||||
reg = <1 0>;
|
||||
};
|
||||
};
|
||||
};
|
@ -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 },
|
||||
|
@ -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
11
util.c
@ -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
41
util.h
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user