Snap for 4453288 from 65effc285b to pi-release

Change-Id: I0cc8d7061c58db1751f1e1bb262e58bd006c0217
This commit is contained in:
android-build-team Robot 2017-11-15 08:31:10 +00:00
commit 7d53feaf11
35 changed files with 1677 additions and 29 deletions

View file

@ -1,5 +1,30 @@
language: c
# Coverity Scan uploads
env:
global:
# COVERITY_SCAN_TOKEN (dgibson/dtc)
- secure: "vlHvXe618//IM9LQaKzqsrUbjs7ng0L9UCST4kJbJnFQDXvVe5JiSmJGd4ef7mm0NUv5bMRl2W3xCiu6BYAu/NvU3tMNHoLG+JgCJs0+wLJXbWOwji/NmH7olqgJG+CmpaCMXjARF6+nrTnBYHJL6cYyf4KVoV4B0I/hLUW91+s="
matrix:
include:
- addons:
apt:
packages:
- swig
- python-dev
coverity_scan:
project:
name: dtc
description: Device Tree Compiler
notification_email: david@gibson.dropbear.id.au
build_command: make
branch_pattern: coverity_scan
- addons:
apt:
packages:
script:
- make
- make check

View file

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

View file

@ -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 python >/dev/null 2>&1; then \
if which swig >/dev/null 2>&1; then \
can_build=yes; \
fi; \
fi; \
if [ "$$can_build" = "yes" ]; then \
$(MAKE) pylibfdt; \
else \
echo "## Skipping pylibfdt (install python dev and swig to build)"; \
fi
ifeq ($(NO_PYTHON),)
all: maybe_pylibfdt
endif
ifneq ($(DEPTARGETS),)
-include $(DTC_OBJS:%.o=%.d)
@ -124,6 +151,7 @@ ifneq ($(DEPTARGETS),)
-include $(FDTDUMP_OBJS:%.o=%.d)
-include $(FDTGET_OBJS:%.o=%.d)
-include $(FDTPUT_OBJS:%.o=%.d)
-include $(FDTOVERLAY_OBJS:%.o=%.d)
endif
@ -180,6 +208,10 @@ install-includes:
install: install-bin install-lib install-includes
ifeq ($(NO_PYTHON),)
install: install_pylibfdt
endif
$(VERSION_FILE): Makefile FORCE
$(call filechk,version)
@ -196,12 +228,30 @@ fdtget: $(FDTGET_OBJS) $(LIBFDT_archive)
fdtput: $(FDTPUT_OBJS) $(LIBFDT_archive)
fdtoverlay: $(FDTOVERLAY_OBJS) $(LIBFDT_archive)
dist:
git archive --format=tar --prefix=dtc-$(dtc_version)/ HEAD \
> ../dtc-$(dtc_version).tar
cat ../dtc-$(dtc_version).tar | \
gzip -9 > ../dtc-$(dtc_version).tar.gz
#
# Rules for pylibfdt
#
PYLIBFDT_srcdir = pylibfdt
PYLIBFDT_objdir = pylibfdt
include $(PYLIBFDT_srcdir)/Makefile.pylibfdt
.PHONY: pylibfdt
pylibfdt: $(PYLIBFDT_objdir)/_libfdt.so
pylibfdt_clean:
@$(VECHO) CLEAN "(pylibfdt)"
rm -f $(addprefix $(PYLIBFDT_objdir)/,$(PYLIBFDT_cleanfiles))
#
# Release signing and uploading
# This is for maintainer convenience, don't try this at home.
@ -234,6 +284,10 @@ TESTS_BIN += convert-dtsv0
TESTS_BIN += fdtput
TESTS_BIN += fdtget
TESTS_BIN += fdtdump
TESTS_BIN += fdtoverlay
ifeq ($(NO_PYTHON),)
TESTS_PYLIBFDT += maybe_pylibfdt
endif
include tests/Makefile.tests
@ -243,7 +297,7 @@ include tests/Makefile.tests
STD_CLEANFILES = *~ *.o *.$(SHAREDLIB_EXT) *.d *.a *.i *.s core a.out vgcore.* \
*.tab.[ch] *.lex.c *.output
clean: libfdt_clean tests_clean
clean: libfdt_clean pylibfdt_clean tests_clean
@$(VECHO) CLEAN
rm -f $(STD_CLEANFILES)
rm -f $(VERSION_FILE)
@ -287,7 +341,7 @@ clean: libfdt_clean tests_clean
$(LIBFDT_lib):
@$(VECHO) LD $@
$(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
$(CC) $(LDFLAGS) $(SHAREDLIB_LDFLAGS)$(LIBFDT_soname) -o $(LIBFDT_lib) $^
%.lex.c: %.l
@$(VECHO) LEX $@

View file

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

66
README
View file

@ -7,6 +7,72 @@ 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.
Mailing list
------------
The following list is for discussion about dtc and libfdt implementation

231
checks.c
View file

@ -681,6 +681,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 (!strneq(node->name, "pci", node->basenamelen) &&
!strneq(node->name, "pcie", node->basenamelen))
FAIL(c, dti, "Node %s node name is not \"pci\" or \"pcie\"",
node->fullpath);
prop = get_property(node, "ranges");
if (!prop)
FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)",
node->fullpath);
if (node_addr_cells(node) != 3)
FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge",
node->fullpath);
if (node_size_cells(node) != 2)
FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge",
node->fullpath);
prop = get_property(node, "bus-range");
if (!prop) {
FAIL(c, dti, "Node %s missing bus-range for PCI bridge",
node->fullpath);
return;
}
if (prop->val.len != (sizeof(cell_t) * 2)) {
FAIL(c, dti, "Node %s bus-range must be 2 cells",
node->fullpath);
return;
}
cells = (cell_t *)prop->val.val;
if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1]))
FAIL(c, dti, "Node %s bus-range 1st cell must be less than or equal to 2nd cell",
node->fullpath);
if (fdt32_to_cpu(cells[1]) > 0xff)
FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256",
node->fullpath);
}
WARNING(pci_bridge, check_pci_bridge, NULL,
&device_type_is_string, &addr_size_cells);
static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node)
{
struct property *prop;
unsigned int bus_num, min_bus, max_bus;
cell_t *cells;
if (!node->parent || (node->parent->bus != &pci_bus))
return;
prop = get_property(node, "reg");
if (!prop)
return;
cells = (cell_t *)prop->val.val;
bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16;
prop = get_property(node->parent, "bus-range");
if (!prop) {
min_bus = max_bus = 0;
} else {
cells = (cell_t *)prop->val.val;
min_bus = fdt32_to_cpu(cells[0]);
max_bus = fdt32_to_cpu(cells[0]);
}
if ((bus_num < min_bus) || (bus_num > max_bus))
FAIL(c, dti, "Node %s PCI bus number %d out of range, expected (%d - %d)",
node->fullpath, bus_num, min_bus, max_bus);
}
WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, &reg_format, &pci_bridge);
static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node)
{
struct property *prop;
const char *unitname = get_unitname(node);
char unit_addr[5];
unsigned int dev, func, reg;
cell_t *cells;
if (!node->parent || (node->parent->bus != &pci_bus))
return;
prop = get_property(node, "reg");
if (!prop) {
FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath);
return;
}
cells = (cell_t *)prop->val.val;
if (cells[1] || cells[2])
FAIL(c, dti, "Node %s PCI reg config space address cells 2 and 3 must be 0",
node->fullpath);
reg = fdt32_to_cpu(cells[0]);
dev = (reg & 0xf800) >> 11;
func = (reg & 0x700) >> 8;
if (reg & 0xff000000)
FAIL(c, dti, "Node %s PCI reg address is not configuration space",
node->fullpath);
if (reg & 0x000000ff)
FAIL(c, dti, "Node %s PCI reg config space address register number must be 0",
node->fullpath);
if (func == 0) {
snprintf(unit_addr, sizeof(unit_addr), "%x", dev);
if (streq(unitname, unit_addr))
return;
}
snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func);
if (streq(unitname, unit_addr))
return;
FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"",
node->fullpath, unit_addr);
}
WARNING(pci_device_reg, check_pci_device_reg, NULL, &reg_format, &pci_bridge);
static const struct bus_type simple_bus = {
.name = "simple-bus",
};
static bool node_is_compatible(struct node *node, const char *compat)
{
struct property *prop;
const char *str, *end;
prop = get_property(node, "compatible");
if (!prop)
return false;
for (str = prop->val.val, end = str + prop->val.len; str < end;
str += strnlen(str, end - str) + 1) {
if (strneq(str, compat, end - str))
return true;
}
return false;
}
static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
{
if (node_is_compatible(node, "simple-bus"))
node->bus = &simple_bus;
}
WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
{
struct property *prop;
const char *unitname = get_unitname(node);
char unit_addr[17];
unsigned int size;
uint64_t reg = 0;
cell_t *cells = NULL;
if (!node->parent || (node->parent->bus != &simple_bus))
return;
prop = get_property(node, "reg");
if (prop)
cells = (cell_t *)prop->val.val;
else {
prop = get_property(node, "ranges");
if (prop && prop->val.len)
/* skip of child address */
cells = ((cell_t *)prop->val.val) + node_addr_cells(node);
}
if (!cells) {
if (node->parent->parent && !(node->bus == &simple_bus))
FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath);
return;
}
size = node_addr_cells(node->parent);
while (size--)
reg = (reg << 32) | fdt32_to_cpu(*(cells++));
snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg);
if (!streq(unitname, unit_addr))
FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"",
node->fullpath, unit_addr);
}
WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_format, &simple_bus_bridge);
static void check_unit_address_format(struct check *c, struct dt_info *dti,
struct node *node)
{
const char *unitname = get_unitname(node);
if (node->parent && node->parent->bus)
return;
if (!unitname[0])
return;
if (!strncmp(unitname, "0x", 2)) {
FAIL(c, dti, "Node %s unit name should not have leading \"0x\"",
node->fullpath);
/* skip over 0x for next test */
unitname += 2;
}
if (unitname[0] == '0' && isxdigit(unitname[1]))
FAIL(c, dti, "Node %s unit name should not have leading 0s",
node->fullpath);
}
WARNING(unit_address_format, check_unit_address_format, NULL,
&node_name_format, &pci_bridge, &simple_bus_bridge);
/*
* Style checks
*/
@ -752,6 +975,14 @@ static struct check *check_table[] = {
&addr_size_cells, &reg_format, &ranges_format,
&unit_address_vs_reg,
&unit_address_format,
&pci_bridge,
&pci_device_reg,
&pci_device_bus_num,
&simple_bus_bridge,
&simple_bus_reg,
&avoid_default_addr_size,
&obsolete_chosen_interrupt_controller,

2
dtc.c
View file

@ -31,7 +31,7 @@ int reservenum; /* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob accroding to the alignsize */
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */
int generate_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */

6
dtc.h
View file

@ -31,6 +31,7 @@
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#include <libfdt_env.h>
#include <fdt.h>
@ -135,6 +136,10 @@ struct label {
struct label *next;
};
struct bus_type {
const char *name;
};
struct property {
bool deleted;
char *name;
@ -161,6 +166,7 @@ struct node {
int addr_cells, size_cells;
struct label *labels;
const struct bus_type *bus;
};
#define for_each_label_withdel(l0, l) \

View file

@ -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

168
fdtoverlay.c Normal file
View file

@ -0,0 +1,168 @@
/*
* 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 <alloca.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;
}
ret = 0;
/* allocate blob pointer array */
ovblob = alloca(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(blob);
return ret;
}
int main(int argc, char *argv[])
{
int opt, i;
char *input_filename = NULL;
char *output_filename = NULL;
while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
case_USAGE_COMMON_FLAGS
case 'i':
input_filename = optarg;
break;
case 'o':
output_filename = optarg;
break;
case 'v':
verbose = 1;
break;
}
}
if (!input_filename)
usage("missing input file");
if (!output_filename)
usage("missing output file");
argv += optind;
argc -= optind;
if (argc <= 0)
usage("missing overlay file(s)");
if (verbose) {
printf("input = %s\n", input_filename);
printf("output = %s\n", output_filename);
for (i = 0; i < argc; i++)
printf("overlay[%d] = %s\n", i, argv[i]);
}
if (do_fdtoverlay(input_filename, output_filename, argc, argv))
return 1;
return 0;
}

View file

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

View file

@ -60,7 +60,7 @@ static int _fdt_nodename_eq(const void *fdt, int offset,
{
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
if (! p)
if (!p)
/* short match */
return 0;
@ -327,7 +327,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const struct fdt_property *prop;
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
if (! prop)
if (!prop)
return NULL;
return prop->data;

View file

@ -207,7 +207,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
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),
@ -323,7 +323,7 @@ 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);

View file

@ -220,7 +220,7 @@ 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;
@ -238,7 +238,19 @@ int fdt_property(void *fdt, const char *name, const void *val, int len)
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;
}

View file

@ -82,7 +82,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
int proplen;
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if (! propval)
if (!propval)
return proplen;
if (proplen != len)
@ -107,7 +107,7 @@ 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));

View file

@ -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))
@ -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);
@ -1734,8 +1767,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

View file

@ -500,7 +500,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) &&
strneq(path, child->name, p-path))
return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name))
return child;

3
pylibfdt/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
libfdt.py
libfdt.pyc
libfdt_wrap.c

View file

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

433
pylibfdt/libfdt.i Normal file
View file

@ -0,0 +1,433 @@
/*
* 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
%{
#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 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])
class Property:
"""Holds a device tree property name and value.
This holds a copy of a property taken from the device tree. It does not
reference the device tree, so if anything changes in the device tree,
a Property object will remain valid.
Properties:
name: Property name
value: Proper value as a bytearray
"""
def __init__(self, name, value):
self.name = name
self.value = value
%}
%rename(fdt_property) fdt_property_func;
typedef int fdt32_t;
%include "libfdt/fdt.h"
%include "typemaps.i"
/* Most functions don't change the device tree, so use a const void * */
%typemap(in) (const void *)(const void *fdt) {
if (!PyByteArray_Check($input)) {
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
"', argument " "$argnum"" of type '" "$type""'");
}
$1 = (void *)PyByteArray_AsString($input);
fdt = $1;
fdt = fdt; /* avoid unused variable warning */
}
/* Some functions do change the device tree, so use void * */
%typemap(in) (void *)(const void *fdt) {
if (!PyByteArray_Check($input)) {
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
"', argument " "$argnum"" of type '" "$type""'");
}
$1 = PyByteArray_AsString($input);
fdt = $1;
fdt = fdt; /* avoid unused variable warning */
}
%typemap(out) (struct fdt_property *) {
PyObject *buff;
if ($1) {
resultobj = PyString_FromString(
fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
buff = PyByteArray_FromStringAndSize(
(const char *)($1 + 1), fdt32_to_cpu($1->len));
resultobj = SWIG_Python_AppendOutput(resultobj, buff);
}
}
%apply int *OUTPUT { int *lenp };
/* typemap used for fdt_getprop() */
%typemap(out) (const void *) {
if (!$1)
$result = Py_None;
else
$result = Py_BuildValue("s#", $1, *arg4);
}
/* We have both struct fdt_property and a function fdt_property() */
%warnfilter(302) fdt_property;
/* These are macros in the header so have to be redefined here */
int fdt_magic(const void *fdt);
int fdt_totalsize(const void *fdt);
int fdt_off_dt_struct(const void *fdt);
int fdt_off_dt_strings(const void *fdt);
int fdt_off_mem_rsvmap(const void *fdt);
int fdt_version(const void *fdt);
int fdt_last_comp_version(const void *fdt);
int fdt_boot_cpuid_phys(const void *fdt);
int fdt_size_dt_strings(const void *fdt);
int fdt_size_dt_struct(const void *fdt);
%include <../libfdt/libfdt.h>

121
pylibfdt/setup.py Executable file
View file

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

View file

@ -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),)

View file

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

View file

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

View file

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

View file

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

288
tests/pylibfdt_tests.py Normal file
View file

@ -0,0 +1,288 @@
# 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.append('../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.fdt_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 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))
if __name__ == "__main__":
unittest.main()

View file

@ -157,7 +157,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 \
@ -420,7 +428,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
@ -540,6 +548,8 @@ 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
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
@ -769,6 +779,40 @@ 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}
}
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 +831,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 +865,12 @@ for set in $TESTSETS; do
"fdtdump")
fdtdump_tests
;;
"pylibfdt")
pylibfdt_tests
;;
"fdtoverlay")
fdtoverlay_tests
;;
esac
done

View file

@ -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);
@ -135,6 +138,8 @@ int main(int argc, char *argv[])
CHECK(fdt_begin_node(fdt, "subsubnode"));
CHECK(fdt_property(fdt, "compatible", "subsubnode1\0subsubnode",
23));
CHECK(fdt_property_placeholder(fdt, "placeholder", place_len, &place));
memcpy(place, place_str, place_len);
CHECK(fdt_property_cell(fdt, "prop-int", TEST_VALUE_1));
CHECK(fdt_end_node(fdt));
CHECK(fdt_begin_node(fdt, "ss1"));

View file

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

View file

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

View file

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

View file

@ -102,6 +102,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 +142,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:

View file

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

View file

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