From 33c3985226d344662511f999aa1920c112a549da Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Mar 2017 09:44:16 -0500 Subject: checks: Add bus checks for PCI buses Add PCI bridge and device node checks. We identify PCI bridges with 'device_type = "pci"' as only PCI bridges should set that property. For bridges, check that node name is pci or pcie, ranges and bus-range are present, and #address-cells and #size-cells are correct. For devices, check the reg property fields are correct for the first element (the config address). Check that the unit address is formatted corectly based on the reg property. Device unit addresses are in the form DD or DD,F where DD is the device 0-0x1f and F is the function 0-7. Also, check that the bus number is within the expected range defined by bridge's bus-ranges. Reviewed-by: David Gibson Signed-off-by: Rob Herring [dwg: Added a missing check dependency] Signed-off-by: David Gibson --- checks.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dtc.h | 5 +++ 2 files changed, 141 insertions(+) diff --git a/checks.c b/checks.c index 38f548e..2b57944 100644 --- a/checks.c +++ b/checks.c @@ -681,6 +681,138 @@ 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, ®_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); + /* * Style checks */ @@ -753,6 +885,10 @@ static struct check *check_table[] = { &unit_address_vs_reg, + &pci_bridge, + &pci_device_reg, + &pci_device_bus_num, + &avoid_default_addr_size, &obsolete_chosen_interrupt_controller, diff --git a/dtc.h b/dtc.h index 403b79d..fc24e17 100644 --- a/dtc.h +++ b/dtc.h @@ -135,6 +135,10 @@ struct label { struct label *next; }; +struct bus_type { + const char *name; +}; + struct property { bool deleted; char *name; @@ -161,6 +165,7 @@ struct node { int addr_cells, size_cells; struct label *labels; + const struct bus_type *bus; }; #define for_each_label_withdel(l0, l) \ -- cgit v1.2.3 From 4c15d5da17cc966285d1b15bae821fa3599afac8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Mar 2017 09:44:17 -0500 Subject: checks: Add bus checks for simple-bus buses Add checks to identify simple-bus bus types and checks for child devices. Simple-bus type is generally identified by "simple-bus" compatible string. We also treat the root as a simple-bus, but only for child nodes with reg property. Signed-off-by: Rob Herring Signed-off-by: David Gibson --- checks.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/checks.c b/checks.c index 2b57944..4ae5c62 100644 --- a/checks.c +++ b/checks.c @@ -813,6 +813,73 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no } 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 (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), "%lx", 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); + /* * Style checks */ @@ -889,6 +956,9 @@ static struct check *check_table[] = { &pci_device_reg, &pci_device_bus_num, + &simple_bus_bridge, + &simple_bus_reg, + &avoid_default_addr_size, &obsolete_chosen_interrupt_controller, -- cgit v1.2.3 From cdbb2b6c7a3a5aabf6f942f1b5f5b1d997555b07 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Mar 2017 09:44:18 -0500 Subject: checks: Warn on node name unit-addresses with '0x' or leading 0s Node name unit-addresses should generally never begin with 0x or leading 0s. Add warnings to check for these cases, but only for nodes without a known bus type as there should be better bus specific checks of the unit address in those cases. Any unit addresses that don't follow the general rule will need to add a new bus type. There aren't any known ones ATM. Reviewed-by: David Gibson Signed-off-by: Rob Herring Signed-off-by: David Gibson --- checks.c | 25 +++++++++++++++++++++++++ tests/run_tests.sh | 2 ++ tests/unit-addr-leading-0s.dts | 12 ++++++++++++ tests/unit-addr-leading-0x.dts | 12 ++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 tests/unit-addr-leading-0s.dts create mode 100644 tests/unit-addr-leading-0x.dts diff --git a/checks.c b/checks.c index 4ae5c62..5adfc8f 100644 --- a/checks.c +++ b/checks.c @@ -880,6 +880,30 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no } 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 */ @@ -951,6 +975,7 @@ static struct check *check_table[] = { &addr_size_cells, ®_format, &ranges_format, &unit_address_vs_reg, + &unit_address_format, &pci_bridge, &pci_device_reg, diff --git a/tests/run_tests.sh b/tests/run_tests.sh index ed489db..0f5c3db 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -540,6 +540,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 diff --git a/tests/unit-addr-leading-0s.dts b/tests/unit-addr-leading-0s.dts new file mode 100644 index 0000000..cc017e9 --- /dev/null +++ b/tests/unit-addr-leading-0s.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + bus { + node@001 { + reg = <1 0>; + }; + }; +}; diff --git a/tests/unit-addr-leading-0x.dts b/tests/unit-addr-leading-0x.dts new file mode 100644 index 0000000..74f1967 --- /dev/null +++ b/tests/unit-addr-leading-0x.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + bus { + node@0x1 { + reg = <1 0>; + }; + }; +}; -- cgit v1.2.3 From 50f2507016315e0b9499dd58876ffc1acf91cc5a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 17 Mar 2017 16:14:30 -0600 Subject: Add an initial Python library for libfdt Add Python bindings for a bare-bones set of libfdt functions. These allow navigating the tree and reading node names and properties. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- Makefile | 1 + pylibfdt/.gitignore | 3 + pylibfdt/Makefile.pylibfdt | 17 ++ pylibfdt/libfdt.swig | 433 +++++++++++++++++++++++++++++++++++++++++++++ pylibfdt/setup.py | 34 ++++ 5 files changed, 488 insertions(+) create mode 100644 pylibfdt/.gitignore create mode 100644 pylibfdt/Makefile.pylibfdt create mode 100644 pylibfdt/libfdt.swig create mode 100644 pylibfdt/setup.py diff --git a/Makefile b/Makefile index c3f72e0..1b69f53 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ CFLAGS = -g -Os -fPIC -Werror $(WARNINGS) BISON = bison LEX = flex +SWIG = swig INSTALL = /usr/bin/install DESTDIR = diff --git a/pylibfdt/.gitignore b/pylibfdt/.gitignore new file mode 100644 index 0000000..5e8c5e3 --- /dev/null +++ b/pylibfdt/.gitignore @@ -0,0 +1,3 @@ +libfdt.py +libfdt.pyc +libfdt_wrap.c diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt new file mode 100644 index 0000000..0d8c010 --- /dev/null +++ b/pylibfdt/Makefile.pylibfdt @@ -0,0 +1,17 @@ +# Makefile.pylibfdt +# + +PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) +WRAP = $(PYLIBFDT_objdir)/libfdt_wrap.c +PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so + +$(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) + @$(VECHO) PYMOD $@ + python $(PYLIBFDT_objdir)/setup.py "$(CPPFLAGS)" $^ + mv _libfdt.so $(PYMODULE) + +$(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig + @$(VECHO) SWIG $@ + $(SWIG) -python -o $@ $< + +PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so diff --git a/pylibfdt/libfdt.swig b/pylibfdt/libfdt.swig new file mode 100644 index 0000000..cd1c6a9 --- /dev/null +++ b/pylibfdt/libfdt.swig @@ -0,0 +1,433 @@ +/* + * pylibfdt - Flat Device Tree manipulation in Python + * Copyright (C) 2017 Google, Inc. + * Written by Simon Glass + * + * 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> diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py new file mode 100644 index 0000000..0ff160c --- /dev/null +++ b/pylibfdt/setup.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +""" +setup.py file for SWIG libfdt +""" + +from distutils.core import setup, Extension +import os +import sys + +progname = sys.argv[0] +cflags = sys.argv[1] +files = sys.argv[2:] + +if cflags: + cflags = [flag for flag in cflags.split(' ') if flag] +else: + cflags = None + +libfdt_module = Extension( + '_libfdt', + sources = files, + extra_compile_args = cflags +) + +sys.argv = [progname, '--quiet', 'build_ext', '--inplace'] + +setup (name = 'libfdt', + version = '0.1', + author = "Simon Glass ", + description = """Python binding for libfdt""", + ext_modules = [libfdt_module], + py_modules = ["libfdt"], + ) -- cgit v1.2.3 From 12cfb740cc76c9c9fa906fee240dc028da2bddd0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 17 Mar 2017 16:14:31 -0600 Subject: Add tests for pylibfdt Add a set of tests to cover the functionality in pylibfdt. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- tests/pylibfdt_tests.py | 288 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 tests/pylibfdt_tests.py diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py new file mode 100644 index 0000000..ae392bb --- /dev/null +++ b/tests/pylibfdt_tests.py @@ -0,0 +1,288 @@ +# pylibfdt - Tests for Flat Device Tree manipulation in Python +# Copyright (C) 2017 Google, Inc. +# Written by Simon Glass +# +# 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() -- cgit v1.2.3 From b40aa8359affa52bd79afe468c26683d6bb41c68 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 17 Mar 2017 16:14:32 -0600 Subject: Mention pylibfdt in the documentation Add a note about pylibfdt in the README. Signed-off-by: Simon Glass Reviewed-by: David Gibson Signed-off-by: David Gibson --- README | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/README b/README index f92008f..96d8486 100644 --- a/README +++ b/README @@ -7,6 +7,53 @@ DTC and LIBFDT are maintained by: David Gibson Jon Loeliger + +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 + + +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 -- cgit v1.2.3 From 8cb3896358e9f70b6f742772734b038ed0d4ea19 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 17 Mar 2017 16:14:33 -0600 Subject: Adjust libfdt.h to work with swig There are a few places where libfdt.h cannot be used as is with swig: - macros like fdt_totalsize() have to be defined as C declarations - fdt_offset_ptr() and fdt_getprop_namelen() need special treatment due to a TODO in the wrapper for fdt_getprop(). However they are not useful to Python so can be removed Add #ifdefs to work around these problem. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- libfdt/libfdt.h | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index ac42e04..2c9ddb4 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -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 @@ -1734,8 +1751,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 -- cgit v1.2.3 From 756ffc4f52f6863ba8bf3a67129271566ba2000c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 17 Mar 2017 16:14:34 -0600 Subject: Build pylibfdt as part of the normal build process If swig and the Python are available, build pylibfdt automatically. Adjust the tests to run Python tests too in this case. Signed-off-by: Simon Glass [dwg: Make error message clearer that missing swig or python-dev isn't fatal to the whole build] Signed-off-by: David Gibson --- Makefile | 34 ++++++++++++++++++++++++++++++++-- tests/run_tests.sh | 28 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1b69f53..ed95384 100644 --- a/Makefile +++ b/Makefile @@ -116,7 +116,21 @@ BIN += fdtput 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 pylibgfdt (install python dev and swig to build)"; \ + fi + +all: $(BIN) libfdt maybe_pylibfdt ifneq ($(DEPTARGETS),) @@ -203,6 +217,22 @@ dist: 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. @@ -244,7 +274,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) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 0f5c3db..2a1ba44 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -771,6 +771,26 @@ fdtdump_tests () { run_fdtdump_test fdtdump.dts } +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") @@ -790,6 +810,11 @@ done if [ -z "$TESTSETS" ]; then TESTSETS="libfdt utilfdt dtc dtbs_equal fdtget fdtput fdtdump" + + # 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 @@ -818,6 +843,9 @@ for set in $TESTSETS; do "fdtdump") fdtdump_tests ;; + "pylibfdt") + pylibfdt_tests + ;; esac done -- cgit v1.2.3 From 6afd7d9688f58436bcc6025180473aa2ec1cdec4 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 22 Mar 2017 16:34:39 +1100 Subject: Correct typo: s/pylibgfdt/pylibfdt/ Signed-off-by: David Gibson --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ed95384..1d08ec1 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,7 @@ maybe_pylibfdt: FORCE if [ "$$can_build" = "yes" ]; then \ $(MAKE) pylibfdt; \ else \ - echo "## Skipping pylibgfdt (install python dev and swig to build)"; \ + echo "## Skipping pylibfdt (install python dev and swig to build)"; \ fi all: $(BIN) libfdt maybe_pylibfdt -- cgit v1.2.3 From 4e0e0d049757b15d53209a9687d9ea33ab3704c5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 26 Mar 2017 13:06:17 -0600 Subject: pylibfdt: Allow pkg-config to be supplied in the environment Some build systems have their own version of the pkg-config tool. Use a variable for this instead of hard-coding it, to allow for this. Signed-off-by: Simon Glass Suggested-by: Mike Frysinger Signed-off-by: David Gibson --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1d08ec1..e6d8251 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ CFLAGS = -g -Os -fPIC -Werror $(WARNINGS) BISON = bison LEX = flex SWIG = swig +PKG_CONFIG ?= pkg-config INSTALL = /usr/bin/install DESTDIR = @@ -119,7 +120,7 @@ SCRIPTS = dtdiff # 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 $(PKG_CONFIG) --cflags python >/dev/null 2>&1; then \ if which swig >/dev/null 2>&1; then \ can_build=yes; \ fi; \ -- cgit v1.2.3 From 89a5062ab23163a7cc4f6ec3d693e6b6883ac0a1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 26 Mar 2017 13:06:19 -0600 Subject: pylibfdt: Use environment to pass C flags and files At present setup.py adjusts its command line when running, so that the C flags and file list can be passed as arguments. Pass them in environment variables instead, so we can avoid this messiness. It also allows us to support the 'install' command. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- pylibfdt/Makefile.pylibfdt | 3 ++- pylibfdt/setup.py | 16 ++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index 0d8c010..3d99fd4 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -7,7 +7,8 @@ PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) @$(VECHO) PYMOD $@ - python $(PYLIBFDT_objdir)/setup.py "$(CPPFLAGS)" $^ + SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" \ + python $(PYLIBFDT_objdir)/setup.py --quiet build_ext --inplace mv _libfdt.so $(PYMODULE) $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py index 0ff160c..e45f110 100644 --- a/pylibfdt/setup.py +++ b/pylibfdt/setup.py @@ -2,6 +2,9 @@ """ setup.py file for SWIG libfdt + +Files to be built into the extension are provided in SOURCES +C flags to use are provided in CPPFLAGS """ from distutils.core import setup, Extension @@ -9,22 +12,15 @@ import os import sys progname = sys.argv[0] -cflags = sys.argv[1] -files = sys.argv[2:] - -if cflags: - cflags = [flag for flag in cflags.split(' ') if flag] -else: - cflags = None +files = os.environ['SOURCES'].split() +cflags = os.environ['CPPFLAGS'].split() libfdt_module = Extension( '_libfdt', sources = files, - extra_compile_args = cflags + extra_compile_args = cflags ) -sys.argv = [progname, '--quiet', 'build_ext', '--inplace'] - setup (name = 'libfdt', version = '0.1', author = "Simon Glass ", -- cgit v1.2.3 From 14c4171f4f9ad2674249e06c54eb9ce0b533d4b6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 26 Mar 2017 13:06:20 -0600 Subject: pylibfdt: Use package_dir to set the package directory At present we manually move _libfdt.so into the correct place. Provide a package directory so we can avoid needing to do this. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- pylibfdt/Makefile.pylibfdt | 3 +-- pylibfdt/setup.py | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index 3d99fd4..861e67c 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -7,9 +7,8 @@ PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) @$(VECHO) PYMOD $@ - SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" \ + SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \ python $(PYLIBFDT_objdir)/setup.py --quiet build_ext --inplace - mv _libfdt.so $(PYMODULE) $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig @$(VECHO) SWIG $@ diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py index e45f110..ef6e2c0 100644 --- a/pylibfdt/setup.py +++ b/pylibfdt/setup.py @@ -5,6 +5,7 @@ setup.py file for SWIG libfdt 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 """ from distutils.core import setup, Extension @@ -14,6 +15,7 @@ import sys progname = sys.argv[0] files = os.environ['SOURCES'].split() cflags = os.environ['CPPFLAGS'].split() +objdir = os.environ['OBJDIR'] libfdt_module = Extension( '_libfdt', @@ -26,5 +28,6 @@ setup (name = 'libfdt', author = "Simon Glass ", description = """Python binding for libfdt""", ext_modules = [libfdt_module], + package_dir = {'': objdir}, py_modules = ["libfdt"], ) -- cgit v1.2.3 From 741cdff85d3e57fbf9e71eac5c6c1140ae39a97b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 27 Mar 2017 16:30:27 +1100 Subject: .travis.yml: Add builds with and without Python library prerequisites To make sure the Makefile behaves in both cases, make Travis matrix builds with and without swig installed. Signed-off-by: David Gibson --- .travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.travis.yml b/.travis.yml index f2336d8..de36443 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,16 @@ language: c +matrix: + include: + - addons: + apt: + packages: + - swig + - python-dev + - addons: + apt: + packages: + script: - make - make check -- cgit v1.2.3 From 8a892fd85d94c733bbf184ff6df5d0ad5422be12 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 26 Mar 2017 13:06:18 -0600 Subject: pylibfdt: Allow building to be disabled Some build systems want to build python libraries separately from the rest of the build. Add a NO_PYTHON option to enable this. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- Makefile | 1 + README | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Makefile b/Makefile index e6d8251..5cf4aee 100644 --- a/Makefile +++ b/Makefile @@ -120,6 +120,7 @@ SCRIPTS = dtdiff # We need both Python and swig to build pylibfdt. .PHONY: maybe_pylibfdt maybe_pylibfdt: FORCE + if [ -n "${NO_PYTHON}" ]; then exit; fi; \ if $(PKG_CONFIG) --cflags python >/dev/null 2>&1; then \ if which swig >/dev/null 2>&1; then \ can_build=yes; \ diff --git a/README b/README index 96d8486..d2323fd 100644 --- a/README +++ b/README @@ -50,6 +50,12 @@ If you add new features, please check code coverage: # Open 'htmlcov/index.html' in your browser +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. -- cgit v1.2.3 From e91c652af21557698751c3944ceb7c46e5e58164 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 26 Mar 2017 13:06:21 -0600 Subject: pylibfdt: Enable installation of Python module Adjust the setup script to support installation, and call it from the Makefile if enabled. It will be disabled if we were unable to build the module (e.g. due to swig being missing), or the NO_PYTHON environment variable is set. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- Makefile | 2 +- README | 7 +++++++ pylibfdt/Makefile.pylibfdt | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5cf4aee..52ff72c 100644 --- a/Makefile +++ b/Makefile @@ -195,7 +195,7 @@ install-includes: $(INSTALL) -d $(DESTDIR)$(INCLUDEDIR) $(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR) -install: install-bin install-lib install-includes +install: install-bin install-lib install-includes maybe_install_pylibfdt $(VERSION_FILE): Makefile FORCE $(call filechk,version) diff --git a/README b/README index d2323fd..5add557 100644 --- a/README +++ b/README @@ -50,6 +50,13 @@ If you add new features, please check code coverage: # Open 'htmlcov/index.html' in your browser +To install the library use: + + make install_pylibfdt SETUP_PREFIX=/path/to/install_dir + +If SETUP_PREFIX is not provided, the default prefix is used, typically '/usr' +or '/usr/local'. See Python's distutils documentation for details. + To disable building the python library, even if swig and Python are available, use: diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index 861e67c..a0271da 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -14,4 +14,18 @@ $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig @$(VECHO) SWIG $@ $(SWIG) -python -o $@ $< +install_pylibfdt: $(WRAP) $(PYMODULE) + $(VECHO) INSTALL-PYLIB; \ + SOURCES="$(PYLIBFDT_srcs) $(WRAP)" CPPFLAGS="$(CPPFLAGS)" \ + OBJDIR="$(PYLIBFDT_objdir)" \ + python $(PYLIBFDT_objdir)/setup.py --quiet install \ + $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)) + +maybe_install_pylibfdt: + if [ -e $(PYMODULE) ]; then \ + if [ -z "$(NO_PYTHON)" ]; then \ + $(MAKE) install_pylibfdt; \ + fi; \ + fi + PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so -- cgit v1.2.3 From 9f2e3a3a1f19b569b9524fa0f4cb4790e23ad983 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 26 Mar 2017 13:06:22 -0600 Subject: pylibfdt: Use the correct libfdt version in the module Use the same version number in the module as with the rest of libfdt. This can be examined with: import pkg_resources print pkg_resources.require('libfdt')[0].version Signed-off-by: Simon Glass Signed-off-by: David Gibson --- pylibfdt/Makefile.pylibfdt | 3 ++- pylibfdt/setup.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index a0271da..a74cd30 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -8,6 +8,7 @@ PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) @$(VECHO) PYMOD $@ SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \ + VERSION="$(dtc_version)" \ python $(PYLIBFDT_objdir)/setup.py --quiet build_ext --inplace $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig @@ -17,7 +18,7 @@ $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig install_pylibfdt: $(WRAP) $(PYMODULE) $(VECHO) INSTALL-PYLIB; \ SOURCES="$(PYLIBFDT_srcs) $(WRAP)" CPPFLAGS="$(CPPFLAGS)" \ - OBJDIR="$(PYLIBFDT_objdir)" \ + OBJDIR="$(PYLIBFDT_objdir)" VERSION="$(dtc_version)" \ python $(PYLIBFDT_objdir)/setup.py --quiet install \ $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)) diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py index ef6e2c0..3bafe30 100644 --- a/pylibfdt/setup.py +++ b/pylibfdt/setup.py @@ -16,6 +16,7 @@ progname = sys.argv[0] files = os.environ['SOURCES'].split() cflags = os.environ['CPPFLAGS'].split() objdir = os.environ['OBJDIR'] +version = os.environ['VERSION'] libfdt_module = Extension( '_libfdt', @@ -24,7 +25,7 @@ libfdt_module = Extension( ) setup (name = 'libfdt', - version = '0.1', + version = version, author = "Simon Glass ", description = """Python binding for libfdt""", ext_modules = [libfdt_module], -- cgit v1.2.3 From ab15256d8d027fc379438a18a8bd85e7765557c6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 26 Mar 2017 13:06:23 -0600 Subject: pylibfdt: Use the call function to simplify the Makefile This is in a separate patch since I not sure if GNU make features are permitted in the Makefile. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- pylibfdt/Makefile.pylibfdt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index a74cd30..0d95c11 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -5,11 +5,13 @@ PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) WRAP = $(PYLIBFDT_objdir)/libfdt_wrap.c PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so +run_setup = SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \ + VERSION="$(dtc_version)" \ + python $(PYLIBFDT_objdir)/setup.py --quiet $(2) + $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) @$(VECHO) PYMOD $@ - SOURCES="$^" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \ - VERSION="$(dtc_version)" \ - python $(PYLIBFDT_objdir)/setup.py --quiet build_ext --inplace + $(call run_setup, $^, build_ext --inplace) $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig @$(VECHO) SWIG $@ @@ -17,10 +19,8 @@ $(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig install_pylibfdt: $(WRAP) $(PYMODULE) $(VECHO) INSTALL-PYLIB; \ - SOURCES="$(PYLIBFDT_srcs) $(WRAP)" CPPFLAGS="$(CPPFLAGS)" \ - OBJDIR="$(PYLIBFDT_objdir)" VERSION="$(dtc_version)" \ - python $(PYLIBFDT_objdir)/setup.py --quiet install \ - $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX)) + $(call run_setup, $(PYLIBFDT_srcs) $(WRAP), \ + install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX))) maybe_install_pylibfdt: if [ -e $(PYMODULE) ]; then \ -- cgit v1.2.3 From 580a9f6c288079e952eae6707c267644338f7c7b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 1 Apr 2017 09:31:41 -0600 Subject: Add a libfdt function to write a property placeholder The existing function to add a new property to a tree being built requires that the entire contents of the new property be passed in. For some applications it is more convenient to be able to add the property contents later, perhaps by reading from a file. This avoids double-buffering of the contents. Add a new function to support this and adjust the existing fdt_property() to use it. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- libfdt/fdt_sw.c | 16 ++++++++++++++-- libfdt/libfdt.h | 16 ++++++++++++++++ tests/include7.dts | 1 + tests/sw_tree1.c | 5 +++++ tests/test_tree1.dts | 1 + tests/test_tree1_label_noderef.dts | 1 + tests/trees.S | 2 ++ 7 files changed, 40 insertions(+), 2 deletions(-) diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c index 6a80485..2bd15e7 100644 --- a/libfdt/fdt_sw.c +++ b/libfdt/fdt_sw.c @@ -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; } diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index 2c9ddb4..a248b1b 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -1314,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); diff --git a/tests/include7.dts b/tests/include7.dts index 2f6eb89..ab2c948 100644 --- a/tests/include7.dts +++ b/tests/include7.dts @@ -5,6 +5,7 @@ subsubnode { compatible = "subsubnode1", "subsubnode"; + placeholder = "this is a placeholder string", "string2"; prop-int = <0xdeadbeef>; }; diff --git a/tests/sw_tree1.c b/tests/sw_tree1.c index 4887dc3..6a338fc 100644 --- a/tests/sw_tree1.c +++ b/tests/sw_tree1.c @@ -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")); diff --git a/tests/test_tree1.dts b/tests/test_tree1.dts index 67ecfd0..77ea325 100644 --- a/tests/test_tree1.dts +++ b/tests/test_tree1.dts @@ -18,6 +18,7 @@ subsubnode { compatible = "subsubnode1", "subsubnode"; + placeholder = "this is a placeholder string", "string2"; prop-int = <0xdeadbeef>; }; diff --git a/tests/test_tree1_label_noderef.dts b/tests/test_tree1_label_noderef.dts index b2b194c..cfe5946 100644 --- a/tests/test_tree1_label_noderef.dts +++ b/tests/test_tree1_label_noderef.dts @@ -18,6 +18,7 @@ subsubnode { compatible = "subsubnode1", "subsubnode"; + placeholder = "this is a placeholder string", "string2"; prop-int = <0xdeadbeef>; }; diff --git a/tests/trees.S b/tests/trees.S index 3d24aa2..9854d1d 100644 --- a/tests/trees.S +++ b/tests/trees.S @@ -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: -- cgit v1.2.3 From 1c5170d3a466dc96ec67c08f71a570631b404c62 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Apr 2017 10:01:38 -0600 Subject: pylibfdt: Rename libfdt.swig to libfdt.i The .i extension allows Python distutils to automatically handle the swig file. Rename it. Signed-off-by: Simon Glass Suggested-by: Mike Frysinger Signed-off-by: David Gibson --- pylibfdt/Makefile.pylibfdt | 2 +- pylibfdt/libfdt.i | 433 +++++++++++++++++++++++++++++++++++++++++++++ pylibfdt/libfdt.swig | 433 --------------------------------------------- 3 files changed, 434 insertions(+), 434 deletions(-) create mode 100644 pylibfdt/libfdt.i delete mode 100644 pylibfdt/libfdt.swig diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index 0d95c11..06f9296 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -13,7 +13,7 @@ $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) @$(VECHO) PYMOD $@ $(call run_setup, $^, build_ext --inplace) -$(WRAP): $(PYLIBFDT_srcdir)/libfdt.swig +$(WRAP): $(PYLIBFDT_srcdir)/libfdt.i @$(VECHO) SWIG $@ $(SWIG) -python -o $@ $< diff --git a/pylibfdt/libfdt.i b/pylibfdt/libfdt.i new file mode 100644 index 0000000..cd1c6a9 --- /dev/null +++ b/pylibfdt/libfdt.i @@ -0,0 +1,433 @@ +/* + * pylibfdt - Flat Device Tree manipulation in Python + * Copyright (C) 2017 Google, Inc. + * Written by Simon Glass + * + * 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> diff --git a/pylibfdt/libfdt.swig b/pylibfdt/libfdt.swig deleted file mode 100644 index cd1c6a9..0000000 --- a/pylibfdt/libfdt.swig +++ /dev/null @@ -1,433 +0,0 @@ -/* - * pylibfdt - Flat Device Tree manipulation in Python - * Copyright (C) 2017 Google, Inc. - * Written by Simon Glass - * - * 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> -- cgit v1.2.3 From b04a2cf08862ddac1ff7da40eef58ecb360da941 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Apr 2017 10:01:39 -0600 Subject: pylibfdt: Fix code style in setup.py We should follow PEP8 even for our setup() call. Signed-off-by: Simon Glass Suggested-by: Mike Frysinger Signed-off-by: David Gibson --- pylibfdt/setup.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py index 3bafe30..1597b44 100644 --- a/pylibfdt/setup.py +++ b/pylibfdt/setup.py @@ -24,11 +24,12 @@ libfdt_module = Extension( extra_compile_args = cflags ) -setup (name = 'libfdt', - version = version, - author = "Simon Glass ", - description = """Python binding for libfdt""", - ext_modules = [libfdt_module], - package_dir = {'': objdir}, - py_modules = ["libfdt"], - ) +setup( + name='libfdt', + version= version, + author='Simon Glass ', + description='Python binding for libfdt', + ext_modules=[libfdt_module], + package_dir={'': objdir}, + py_modules=['libfdt'], +) -- cgit v1.2.3 From e20d9658cd8f1cf2c03e843678cc9e89107e87ad Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 7 Apr 2017 15:55:16 +1000 Subject: Add Coverity Scan support I've recently signed up dtc for Coverity Scan coverage. This adds magic to the .travis.yml file to submit builds to Coverity for analysis. Signed-off-by: David Gibson --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.travis.yml b/.travis.yml index de36443..a07c989 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,11 @@ 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: @@ -7,6 +13,14 @@ matrix: 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: -- cgit v1.2.3 From 90db6d9989ca09ed3c32fbdc646d284ebf9fe1cf Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 7 Apr 2017 15:51:32 -0600 Subject: pylibfdt: Allow setup.py to operate stand-alone At present we require that setup.py is executed from the Makefile, which sets up various important things like the list of files to build and the version number. However many installation systems expect to be able to change to the directory containing setup.py and run it. This allows them to support (for example) building/installing for multiple Python versions, varying installation paths, particular C flags, etc. The problem in implementing this is that we don't want to duplicate the information in the Makefile. A common solution (so I am told) is to parse the Makefile to obtain the required information. Update the setup.py script to read a few Makefiles when it does not see the required information in its environment. This allows installation using: ./pylibfdt/setup.py install Signed-off-by: Simon Glass Signed-off-by: David Gibson --- Makefile | 1 + README | 14 +++++-- pylibfdt/Makefile.pylibfdt | 9 +++-- pylibfdt/setup.py | 98 +++++++++++++++++++++++++++++++++++++++++++--- tests/Makefile.tests | 6 +-- 5 files changed, 112 insertions(+), 16 deletions(-) mode change 100644 => 100755 pylibfdt/setup.py diff --git a/Makefile b/Makefile index 52ff72c..154f5bf 100644 --- a/Makefile +++ b/Makefile @@ -267,6 +267,7 @@ TESTS_BIN += convert-dtsv0 TESTS_BIN += fdtput TESTS_BIN += fdtget TESTS_BIN += fdtdump +TESTS_PYLIBFDT += maybe_pylibfdt include tests/Makefile.tests diff --git a/README b/README index 5add557..17dc845 100644 --- a/README +++ b/README @@ -50,12 +50,18 @@ If you add new features, please check code coverage: # Open 'htmlcov/index.html' in your browser -To install the library use: +To install the library via the normal setup.py method, use: - make install_pylibfdt SETUP_PREFIX=/path/to/install_dir + ./pylibfdt/setup.py [--prefix=/path/to/install_dir] -If SETUP_PREFIX is not provided, the default prefix is used, typically '/usr' -or '/usr/local'. See Python's distutils documentation for details. +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: diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index 06f9296..0e8ac5f 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -5,13 +5,16 @@ PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) WRAP = $(PYLIBFDT_objdir)/libfdt_wrap.c PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so -run_setup = SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" \ - VERSION="$(dtc_version)" \ - python $(PYLIBFDT_objdir)/setup.py --quiet $(2) +define run_setup + SOURCES="$(1)" CPPFLAGS="$(CPPFLAGS)" OBJDIR="$(PYLIBFDT_objdir)" + VERSION="$(dtc_version)" + $(PYLIBFDT_objdir)/setup.py --quiet $(2) +endef $(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) @$(VECHO) PYMOD $@ $(call run_setup, $^, build_ext --inplace) + mv _libfdt.so $@ $(WRAP): $(PYLIBFDT_srcdir)/libfdt.i @$(VECHO) SWIG $@ diff --git a/pylibfdt/setup.py b/pylibfdt/setup.py old mode 100644 new mode 100755 index 1597b44..90e80f3 --- a/pylibfdt/setup.py +++ b/pylibfdt/setup.py @@ -2,26 +2,112 @@ """ setup.py file for SWIG libfdt +Copyright (C) 2017 Google, Inc. +Written by Simon Glass 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\w+) *(?P[+])?= *(?P.*)$') + + +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['SOURCES'].split() -cflags = os.environ['CPPFLAGS'].split() -objdir = os.environ['OBJDIR'] -version = os.environ['VERSION'] +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 + extra_compile_args = cflags, + swig_opts = swig_opts, ) setup( @@ -31,5 +117,5 @@ setup( description='Python binding for libfdt', ext_modules=[libfdt_module], package_dir={'': objdir}, - py_modules=['libfdt'], + py_modules=['pylibfdt/libfdt'], ) diff --git a/tests/Makefile.tests b/tests/Makefile.tests index 3d7a4f8..2258135 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -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),) -- cgit v1.2.3 From 896f1c1332650f5370a21c1c507106a87d17fd3d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 7 Apr 2017 15:51:33 -0600 Subject: pylibfdt: Use Makefile constructs to implement NO_PYTHON The current mechanism uses a shell construct, but it seems better to use a Makefile approach. Signed-off-by: Simon Glass Suggested-by: Mike Frysinger Signed-off-by: David Gibson --- Makefile | 15 ++++++++++++--- pylibfdt/Makefile.pylibfdt | 7 ------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 154f5bf..beca4a0 100644 --- a/Makefile +++ b/Makefile @@ -117,10 +117,11 @@ BIN += fdtput SCRIPTS = dtdiff +all: $(BIN) libfdt + # We need both Python and swig to build pylibfdt. .PHONY: maybe_pylibfdt maybe_pylibfdt: FORCE - if [ -n "${NO_PYTHON}" ]; then exit; fi; \ if $(PKG_CONFIG) --cflags python >/dev/null 2>&1; then \ if which swig >/dev/null 2>&1; then \ can_build=yes; \ @@ -132,7 +133,9 @@ maybe_pylibfdt: FORCE echo "## Skipping pylibfdt (install python dev and swig to build)"; \ fi -all: $(BIN) libfdt maybe_pylibfdt +ifeq ($(NO_PYTHON),) +all: maybe_pylibfdt +endif ifneq ($(DEPTARGETS),) @@ -195,7 +198,11 @@ install-includes: $(INSTALL) -d $(DESTDIR)$(INCLUDEDIR) $(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR) -install: install-bin install-lib install-includes maybe_install_pylibfdt +install: install-bin install-lib install-includes + +ifeq ($(NO_PYTHON),) +install: install_pylibfdt +endif $(VERSION_FILE): Makefile FORCE $(call filechk,version) @@ -267,7 +274,9 @@ TESTS_BIN += convert-dtsv0 TESTS_BIN += fdtput TESTS_BIN += fdtget TESTS_BIN += fdtdump +ifeq ($(NO_PYTHON),) TESTS_PYLIBFDT += maybe_pylibfdt +endif include tests/Makefile.tests diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index 0e8ac5f..4036b1f 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -25,11 +25,4 @@ install_pylibfdt: $(WRAP) $(PYMODULE) $(call run_setup, $(PYLIBFDT_srcs) $(WRAP), \ install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX))) -maybe_install_pylibfdt: - if [ -e $(PYMODULE) ]; then \ - if [ -z "$(NO_PYTHON)" ]; then \ - $(MAKE) install_pylibfdt; \ - fi; \ - fi - PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so -- cgit v1.2.3 From e56f2b07be3866eff49651cbe34be3bce79ceb38 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 7 Apr 2017 15:51:34 -0600 Subject: pylibfdt: Use setup.py to build the swig file Since we are using the standard .i extension for the swig file, we can use setup.py to build the wrapper. Drop the existing build code since it is not needed. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- pylibfdt/Makefile.pylibfdt | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pylibfdt/Makefile.pylibfdt b/pylibfdt/Makefile.pylibfdt index 4036b1f..9507d3d 100644 --- a/pylibfdt/Makefile.pylibfdt +++ b/pylibfdt/Makefile.pylibfdt @@ -1,8 +1,8 @@ # Makefile.pylibfdt # -PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) -WRAP = $(PYLIBFDT_objdir)/libfdt_wrap.c +PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) \ + $(PYLIBFDT_srcdir)/libfdt.i PYMODULE = $(PYLIBFDT_objdir)/_libfdt.so define run_setup @@ -11,18 +11,14 @@ define run_setup $(PYLIBFDT_objdir)/setup.py --quiet $(2) endef -$(PYMODULE): $(PYLIBFDT_srcs) $(WRAP) +$(PYMODULE): $(PYLIBFDT_srcs) @$(VECHO) PYMOD $@ $(call run_setup, $^, build_ext --inplace) mv _libfdt.so $@ -$(WRAP): $(PYLIBFDT_srcdir)/libfdt.i - @$(VECHO) SWIG $@ - $(SWIG) -python -o $@ $< - -install_pylibfdt: $(WRAP) $(PYMODULE) +install_pylibfdt: $(PYMODULE) $(VECHO) INSTALL-PYLIB; \ - $(call run_setup, $(PYLIBFDT_srcs) $(WRAP), \ + $(call run_setup, $(PYLIBFDT_srcs), \ install $(if $(SETUP_PREFIX),--prefix=$(SETUP_PREFIX))) PYLIBFDT_cleanfiles = libfdt_wrap.c libfdt.py libfdt.pyc _libfdt.so -- cgit v1.2.3 From 9067ee4be0e6ac5090c30907da63e24514fd569e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 8 Apr 2017 10:14:42 -0600 Subject: Fix a few whitespace and style nits These were noticed when synching with U-Boot's downstream tree. Signed-off-by: Simon Glass Signed-off-by: David Gibson --- libfdt/fdt_empty_tree.c | 1 - libfdt/fdt_ro.c | 4 ++-- libfdt/fdt_rw.c | 4 ++-- libfdt/fdt_wip.c | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libfdt/fdt_empty_tree.c b/libfdt/fdt_empty_tree.c index f72d13b..f2ae9b7 100644 --- a/libfdt/fdt_empty_tree.c +++ b/libfdt/fdt_empty_tree.c @@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize) return fdt_open_into(buf, buf, bufsize); } - diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 3d00d2e..08de2cc 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -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; diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index 3fd5847..8b487f6 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -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); diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c index 6aaab39..5e85919 100644 --- a/libfdt/fdt_wip.c +++ b/libfdt/fdt_wip.c @@ -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)); -- cgit v1.2.3 From c2258841a785742a3fd5c423f4965caac73d01af Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 18 Apr 2017 12:52:08 +1000 Subject: fdtdump: Fix over-zealous version check It's perfectly valid for a dtb to have version and last compat version set to the same value, and that value can be 17 (the latest defined version). However, since 0931cea "dtc: fdtdump: check fdt if not in scanning mode" fdtdump will refuse to process such a dtb. We get away with this in many cases because dtc's typical output has last compat version equal to 16, rather than 17, but it's still a bug. Signed-off-by: David Gibson --- fdtdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdtdump.c b/fdtdump.c index 4eaade9..f199bc5 100644 --- a/fdtdump.c +++ b/fdtdump.c @@ -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) -- cgit v1.2.3 From 548aea2c436ab47ff09ba9ec7e902e971bbc399c Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 18 Apr 2017 13:05:08 +1000 Subject: fdtdump: Discourage use of fdtdump fdtdump is, and always has been, a quick-and-dirty debugging tool. However I keep getting reports of people using it for real work. For production decompiling of a dtb, dtc in -I dtb -O dts mode is the right tool. In the hopes of getting that message out there, add a warning message to fdtdump to discourage its use. Signed-off-by: David Gibson --- fdtdump.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fdtdump.c b/fdtdump.c index f199bc5..fa3b561 100644 --- a/fdtdump.c +++ b/fdtdump.c @@ -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 \n\n" + ); while ((opt = util_getopt_long()) != EOF) { switch (opt) { case_USAGE_COMMON_FLAGS -- cgit v1.2.3 From a10cb3c818d3024caad1efccce1b11947cf316c9 Mon Sep 17 00:00:00 2001 From: Tim Montague Date: Mon, 17 Apr 2017 16:51:05 -0700 Subject: Fix get_node_by_path string equality check When determining if to recurse into a node, get_node_by_path does not check if the length of each node name is equal. If searching for /foo/baz, this can result in recursing into /foobar because strneq("foo", "foobar", 3) is true. This can result in a reference to /foo/baz to be incorrectly set to /foobar/baz. A test for this was added. Signed-off-by: Tim Montague Signed-off-by: David Gibson --- livetree.c | 3 ++- tests/path-references.c | 12 +++++++++++- tests/path-references.dts | 13 +++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/livetree.c b/livetree.c index 3673de0..aecd278 100644 --- a/livetree.c +++ b/livetree.c @@ -478,7 +478,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; diff --git a/tests/path-references.c b/tests/path-references.c index c8d25fb..5e332e8 100644 --- a/tests/path-references.c +++ b/tests/path-references.c @@ -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(); diff --git a/tests/path-references.dts b/tests/path-references.dts index b00fd79..8c66d80 100644 --- a/tests/path-references.dts +++ b/tests/path-references.dts @@ -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; + }; + }; }; -- cgit v1.2.3 From 2a42b14d0d0332a8b24d17dca1b68c154bf4d484 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 16 May 2017 10:08:08 -0600 Subject: dtc: check.c fix compile error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following compile error found on odroid-xu4: checks.c: In function ‘check_simple_bus_reg’: checks.c:876:41: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘uint64_t{aka long long unsigned int}’ [-Werror=format=] snprintf(unit_addr, sizeof(unit_addr), "%lx", reg); ^ checks.c:876:41: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘uint64_t {aka long long unsigned int}’ [-Werror=format=] cc1: all warnings being treated as errors Makefile:304: recipe for target 'checks.o' failed make: *** [checks.o] Error 1 Signed-off-by: Shuah Khan [dwg: Correct new format to be correct in general] Signed-off-by: David Gibson --- checks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks.c b/checks.c index 5adfc8f..4b72b53 100644 --- a/checks.c +++ b/checks.c @@ -873,7 +873,7 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no while (size--) reg = (reg << 32) | fdt32_to_cpu(*(cells++)); - snprintf(unit_addr, sizeof(unit_addr), "%lx", reg); + snprintf(unit_addr, sizeof(unit_addr), "%zx", reg); if (!streq(unitname, unit_addr)) FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"", node->fullpath, unit_addr); -- cgit v1.2.3 From 21a2bc896e3d6ccff22f9224d5e554c198eee04d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 17 May 2017 12:15:26 +1000 Subject: Suppress expected error message in fdtdump test Since 548aea2 "fdtdump: Discourage use of fdtdump", fdtdump unconditionally prints a message discouraging its own use except for debugging purposes. This shows up messily in the "make check" output, so suppress it. Signed-off-by: David Gibson --- tests/run_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 2a1ba44..5df1480 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -157,7 +157,7 @@ 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 } BAD_FIXUP_TREES="bad_index \ -- cgit v1.2.3 From 51f56dedf8ea1108edc66150c0bf7e9f76b48daa Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 19 May 2017 16:11:48 +1000 Subject: Clean up shared library compile/link options - Allow overriding of shared library compile time flags for platforms whic need it - Include -fPIC in the link flags variable instead of including it raw in the target rule - Cosmetic formatting tweaks Signed-off-by: David Gibson --- Makefile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index beca4a0..7fa2be8 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ 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 @@ -36,11 +36,13 @@ HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ sed -e 's/\(cygwin\).*/cygwin/') 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 -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 # @@ -330,7 +332,7 @@ clean: libfdt_clean pylibfdt_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 $@ -- cgit v1.2.3 From d990b8013889b816ec054c7e07a77db59c56c400 Mon Sep 17 00:00:00 2001 From: "Cufi, Carles" Date: Fri, 19 May 2017 09:06:54 +0000 Subject: Makefile: Fix build on MSYS2 and Cygwin The host compiler on MSYS2 and Cygwin does not allow the -fPIC option, issuing a warning that is treated as an error and stops the build. Detect whether we're running under MSYS2 or Cygwin and avoid adding -fPIC to prevent the error from happening. Tested on Linux, MSYS2 and Cygwin. Signed-off-by: Carles Cufi [dwg: Added explicit empty CFLAGS for clarity] Signed-off-by: David Gibson --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7fa2be8..43957e6 100644 --- a/Makefile +++ b/Makefile @@ -33,12 +33,16 @@ 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_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_CFLAGS = -fPIC -- cgit v1.2.3 From 13ce6e1c2fc4549fbb53a9ca5f577166c6e315ac Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 8 Jun 2017 14:35:16 +1000 Subject: dtc: fix sprintf() format string error, again 2a42b14 "dtc: check.c fix compile error" changed a format string using %lx which wasn't correct for all platforms. Unfortunately it changed it to %zx, which is wrong for a different set of platforms (and only right on the others by accident). The parameter we're formatting here is uint64_t, not size_t, so we need to use the PRIx64 macro from to get this right. Signed-off-by: David Gibson --- checks.c | 2 +- dtc.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/checks.c b/checks.c index 4b72b53..afabf64 100644 --- a/checks.c +++ b/checks.c @@ -873,7 +873,7 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no while (size--) reg = (reg << 32) | fdt32_to_cpu(*(cells++)); - snprintf(unit_addr, sizeof(unit_addr), "%zx", reg); + 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); diff --git a/dtc.h b/dtc.h index fc24e17..409db76 100644 --- a/dtc.h +++ b/dtc.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From aae22722fc8d93d88b40c3621705917d74244ca7 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 14 Jun 2017 17:50:27 +0300 Subject: manual: Document missing options The -d and -s options were undocumented. Add an entry in the manual. Signed-off-by: Pantelis Antoniou Signed-off-by: David Gibson --- Documentation/manual.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/manual.txt b/Documentation/manual.txt index 2f07350..d4e99e3 100644 --- a/Documentation/manual.txt +++ b/Documentation/manual.txt @@ -674,4 +674,8 @@ The fdtdump program prints a readable version of a flat device tree file. The syntax of the fdtdump command line is: - fdtdump + fdtdump [options] + +Where options are: + -d,--debug Dump debug information while decoding the file + -s,--scan Scan for an embedded fdt in given file -- cgit v1.2.3 From 42409146f2db22d71559154fa1233694c964cc14 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 14 Jun 2017 17:51:11 +0300 Subject: fdtoverlay: A tool that applies overlays Since libfdt support overlay application on FDT blobs, provide a command line tool that applies an arbitrary number of overlays, one after another to a base fdt blob and output the result in the given file. Signed-off-by: Pantelis Antoniou Signed-off-by: David Gibson --- Documentation/manual.txt | 14 ++++ Makefile | 5 ++ Makefile.utils | 6 ++ fdtoverlay.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 fdtoverlay.c diff --git a/Documentation/manual.txt b/Documentation/manual.txt index d4e99e3..72403ac 100644 --- a/Documentation/manual.txt +++ b/Documentation/manual.txt @@ -679,3 +679,17 @@ The syntax of the fdtdump command line is: 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 -o [ ...] + +Where options are: + -i, --input Input base DT blob + -o, --output Output DT blob + -v, --verbose Verbose message output diff --git a/Makefile b/Makefile index 43957e6..fe482b9 100644 --- a/Makefile +++ b/Makefile @@ -120,6 +120,7 @@ BIN += dtc BIN += fdtdump BIN += fdtget BIN += fdtput +BIN += fdtoverlay SCRIPTS = dtdiff @@ -150,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 @@ -226,6 +228,8 @@ 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 @@ -280,6 +284,7 @@ TESTS_BIN += convert-dtsv0 TESTS_BIN += fdtput TESTS_BIN += fdtget TESTS_BIN += fdtdump +TESTS_BIN += fdtoverlay ifeq ($(NO_PYTHON),) TESTS_PYLIBFDT += maybe_pylibfdt endif diff --git a/Makefile.utils b/Makefile.utils index 48ece49..e028922 100644 --- a/Makefile.utils +++ b/Makefile.utils @@ -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) diff --git a/fdtoverlay.c b/fdtoverlay.c new file mode 100644 index 0000000..9c5618c --- /dev/null +++ b/fdtoverlay.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2017 Konsulko Group Inc. All rights reserved. + * + * Author: + * Pantelis Antoniou + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#include "util.h" + +/* Usage related data. */ +static const char usage_synopsis[] = + "apply a number of overlays to a base blob\n" + " fdtoverlay [ []]\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; +} -- cgit v1.2.3 From e3b9a9588a3515bcce776a37411f64a3ef5194c9 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 14 Jun 2017 17:51:12 +0300 Subject: tests: fdtoverlay unit test Add an fdtoverlay unit test. Applies applies overlay(s) and then retrieves an inserted property to verify. Signed-off-by: Pantelis Antoniou Signed-off-by: David Gibson --- tests/fdtoverlay-runtest.sh | 40 ++++++++++++++++++++++++++++++++++++++++ tests/run_tests.sh | 27 ++++++++++++++++++++++++++- tests/tests.sh | 1 + 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 tests/fdtoverlay-runtest.sh diff --git a/tests/fdtoverlay-runtest.sh b/tests/fdtoverlay-runtest.sh new file mode 100644 index 0000000..06c1169 --- /dev/null +++ b/tests/fdtoverlay-runtest.sh @@ -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 diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 5df1480..d20729c 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -160,6 +160,14 @@ run_fdtdump_test() { 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 \ empty \ empty_index \ @@ -771,6 +779,20 @@ 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 @@ -809,7 +831,7 @@ 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 @@ -846,6 +868,9 @@ for set in $TESTSETS; do "pylibfdt") pylibfdt_tests ;; + "fdtoverlay") + fdtoverlay_tests + ;; esac done diff --git a/tests/tests.sh b/tests/tests.sh index 818fd09..8dda6e1 100644 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -22,6 +22,7 @@ DTC=../dtc DTGET=../fdtget DTPUT=../fdtput FDTDUMP=../fdtdump +FDTOVERLAY=../fdtoverlay verbose_run () { if [ -z "$QUIET_TEST" ]; then -- cgit v1.2.3 From 0016f8c2aa32423f680ec6e94a00f1095b81b5fc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 12 Jul 2017 17:20:30 -0500 Subject: dtc: change default phandles to ePAPR style instead of both Currently, both legacy (linux,phandle) and ePAPR (phandle) properties are inserted into dtbs by default. The newer ePAPR style has been supported in dtc and Linux kernel for 7 years. That should be a long enough transition period. We can save a little space by not putting both into the dtb. Signed-off-by: Rob Herring Signed-off-by: David Gibson --- dtc.c | 2 +- tests/run_tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dtc.c b/dtc.c index f5eed9d..5ed873c 100644 --- a/dtc.c +++ b/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 */ diff --git a/tests/run_tests.sh b/tests/run_tests.sh index d20729c..b8a2825 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -428,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 -- cgit v1.2.3