diff --git a/fdtget.c b/fdtget.c index dd70985..c616969 100644 --- a/fdtget.c +++ b/fdtget.c @@ -138,21 +138,20 @@ static int show_data(struct display_info *disp, const char *data, int len) static int list_properties(const void *blob, int node) { const char *name; + const void *p; int prop; - prop = fdt_first_property_offset(blob, node); - do { - /* Stop silently when there are no more properties */ - if (prop < 0) - return prop == -FDT_ERR_NOTFOUND ? 0 : prop; - fdt_getprop_by_offset(blob, prop, &name, NULL); - if (name) + fdt_for_each_property_offset(prop, blob, node) { + p = fdt_getprop_by_offset(blob, prop, &name, NULL); + if (p && name) puts(name); - prop = fdt_next_property_offset(blob, prop); - } while (1); -} + } -#define MAX_LEVEL 32 /* how deeply nested we will go */ + if ((prop < 0) && (prop != -FDT_ERR_NOTFOUND)) + return prop; + + return 0; +} /** * List all subnodes in a node, one per line @@ -163,47 +162,21 @@ static int list_properties(const void *blob, int node) */ static int list_subnodes(const void *blob, int node) { - int nextoffset; /* next node offset from libfdt */ - uint32_t tag; /* current tag */ - int level = 0; /* keep track of nesting level */ const char *pathp; - int depth = 1; /* the assumed depth of this node */ + int subnode; - while (level >= 0) { - tag = fdt_next_tag(blob, node, &nextoffset); - switch (tag) { - case FDT_BEGIN_NODE: - pathp = fdt_get_name(blob, node, NULL); - if (level <= depth) { - if (pathp == NULL) - pathp = "/* NULL pointer error */"; - if (*pathp == '\0') - pathp = "/"; /* root is nameless */ - if (level == 1) - puts(pathp); - } - level++; - if (level >= MAX_LEVEL) { - printf("Nested too deep, aborting.\n"); - return 1; - } - break; - case FDT_END_NODE: - level--; - if (level == 0) - level = -1; /* exit the loop */ - break; - case FDT_END: - return 1; - case FDT_PROP: - break; - default: - if (level <= depth) - printf("Unknown tag 0x%08X\n", tag); - return 1; - } - node = nextoffset; + fdt_for_each_subnode(subnode, blob, node) { + pathp = fdt_get_name(blob, subnode, NULL); + if (pathp == NULL) + pathp = "/* NULL pointer error */"; + if (*pathp == '\0') + pathp = "/"; /* root is nameless */ + puts(pathp); } + + if (subnode < 0 && (subnode != -FDT_ERR_NOTFOUND)) + return subnode; + return 0; } diff --git a/libfdt/meson.build b/libfdt/meson.build index 68d4c1d..6c41f9f 100644 --- a/libfdt/meson.build +++ b/libfdt/meson.build @@ -27,8 +27,10 @@ endif link_args += version_script libfdt = library( - 'fdt', sources, + 'fdt', + sources: sources, version: meson.project_version(), + soversion: '1', link_args: link_args, link_depends: 'version.lds', install: get_option('default_library') != 'static' or not wheel_only, diff --git a/pylibfdt/libfdt.i b/pylibfdt/libfdt.i index 1f9c047..b41c03f 100644 --- a/pylibfdt/libfdt.i +++ b/pylibfdt/libfdt.i @@ -302,6 +302,38 @@ class FdtRo(object): check_err(val[0], quiet) return val[1:] + def address_cells(self, nodeoffset, quiet=()): + """Return the number of address cells used by a node's children + + Args: + nodeoffset: Offset of the node to check + quiet: Errors to ignore (empty to raise on all errors) + + Returns: + Number of address cells used by the children of @nodeoffset + + Raises: + FdtException if the node has an invalid #address-cells property, + or another error occurs + """ + return check_err(fdt_address_cells(self._fdt, nodeoffset), quiet) + + def size_cells(self, nodeoffset, quiet=()): + """Return the number of size cells used by a node's children + + Args: + nodeoffset: Offset of the node to check + quiet: Errors to ignore (empty to raise on all errors) + + Returns: + Number of size cells used by the children of @nodeoffset + + Raises: + FdtException if the node has an invalid #size-cells property, or + another error occurs + """ + return check_err(fdt_size_cells(self._fdt, nodeoffset), quiet) + def subnode_offset(self, parentoffset, name, quiet=()): """Get the offset of a named subnode @@ -604,6 +636,42 @@ class Fdt(FdtRo): del self._fdt[self.totalsize():] return err + def add_mem_rsv(self, addr, size, quiet=()): + """Add a memory reserve-map record + + This asks the client program not to use the given region of memory, + e.g. because something was loaded there. + + Args: + addr: Start address of the region to reserve + size: Size of the region to reserve, in bytes + quiet: Errors to ignore (empty to raise on all errors) + + Returns: + Error code, or 0 if OK + + Raises: + FdtException if there is no space for another record, or another + error occurs + """ + return check_err(fdt_add_mem_rsv(self._fdt, addr, size), quiet) + + def del_mem_rsv(self, index, quiet=()): + """Remove the indexed memory reserve-map record + + Args: + index: Record to remove (0=first) + quiet: Errors to ignore (empty to raise on all errors) + + Returns: + Error code, or 0 if OK + + Raises: + FdtException if there is no record at @index, or another error + occurs + """ + return check_err(fdt_del_mem_rsv(self._fdt, index), quiet) + def set_name(self, nodeoffset, name, quiet=()): """Set the name of a node @@ -857,7 +925,7 @@ class FdtSw(FdtRo): device tree. This will be increased automatically as needed as new items are added to the tree. """ - INC_SIZE = 1024 # Expand size by this much when out of space + INC_SIZE = 1024 # Expand size by at least this much when out of space def __init__(self, size_hint=None): """Create a new FdtSw object @@ -901,6 +969,10 @@ class FdtSw(FdtRo): -NOSPACE then the FDT will be expanded to have more space, and True will be returned, indicating that the operation needs to be tried again. + Each expansion copies the whole tree into a new buffer, so the size is + at least doubled rather than grown by a fixed amount, to keep the total + amount of copying proportional to the size of the tree. + Args: val: Return value from the operation that was attempted @@ -908,7 +980,7 @@ class FdtSw(FdtRo): True if the operation must be retried, else False """ if check_err(val, QUIET_NOSPACE) < 0: - self.resize(len(self._fdt) + self.INC_SIZE) + self.resize(len(self._fdt) + max(len(self._fdt), self.INC_SIZE)) return True return False @@ -1136,7 +1208,7 @@ typedef uint32_t fdt32_t; PyObject *buff; if ($1) { - resultobj = PyString_FromString( + resultobj = PyUnicode_FromString( fdt_string(fdt1, fdt32_to_cpu($1->nameoff))); buff = PyByteArray_FromStringAndSize( (const char *)($1 + 1), fdt32_to_cpu($1->len)); @@ -1169,13 +1241,13 @@ typedef uint32_t fdt32_t; } $1 = PyBytes_AsString($input); %#else - $1 = PyString_AsString($input); /* char *str */ + $1 = PyBytes_AsString($input); /* char *str */ %#endif } /* typemaps used for fdt_next_node() */ %typemap(in, numinputs=1) int *depth (int depth) { - depth = (int) PyInt_AsLong($input); + depth = (int) PyLong_AsLong($input); $1 = &depth; } diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py index 6af11f2..0e16607 100644 --- a/tests/pylibfdt_tests.py +++ b/tests/pylibfdt_tests.py @@ -411,6 +411,35 @@ class PyLibfdtBasicTests(unittest.TestCase): self.fdt.get_mem_rsv(0)) self.assertEqual([123456789, 0o10000], self.fdt.get_mem_rsv(1)) + def testAddDelReserveMap(self): + """Test that we can add to and remove from the memory reserve map""" + fdt = _ReadFdt('test_tree1.dtb') + fdt.resize(fdt.totalsize() + 64) + + self.assertEqual(0, fdt.add_mem_rsv(0x40000000, 0x2000)) + self.assertEqual(3, fdt.num_mem_rsv()) + self.assertEqual([0x40000000, 0x2000], fdt.get_mem_rsv(2)) + + self.assertEqual(0, fdt.del_mem_rsv(2)) + self.assertEqual(2, fdt.num_mem_rsv()) + self.assertEqual(-libfdt.NOTFOUND, + fdt.del_mem_rsv(2, QUIET_NOTFOUND)) + + def testCells(self): + """Test that we can read #address-cells and #size-cells""" + self.assertEqual(1, self.fdt.address_cells(0)) + self.assertEqual(0, self.fdt.size_cells(0)) + + # A node without the properties inherits neither, so the libfdt + # defaults of 2 and 1 apply + node = self.fdt.path_offset('/subnode@1') + self.assertEqual(2, self.fdt.address_cells(node)) + self.assertEqual(1, self.fdt.size_cells(node)) + + node = self.fdt.path_offset('/subnode@2') + self.assertEqual(1, self.fdt.address_cells(node)) + self.assertEqual(0, self.fdt.size_cells(node)) + def testEmpty(self): """Test that we can create an empty tree""" self.assertEqual(-libfdt.NOSPACE,