1 /* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
3 * pylibfdt - Flat Device Tree manipulation in Python
4 * Copyright (C) 2017 Google, Inc.
5 * Written by Simon Glass <sjg@chromium.org>
13 #define SWIG_FILE_WITH_INIT
17 * We rename this function here to avoid problems with swig, since we also have
18 * a struct called fdt_property. That struct causes swig to create a class in
19 * libfdt.py called fdt_property(), which confuses things.
21 static int _fdt_property(void *fdt, const char *name, const char *val, int len)
23 return fdt_property(fdt, name, val, len);
32 # Error codes, corresponding to FDT_ERR_... in libfdt.h
49 NOPHANDLES) = QUIET_ALL = range(1, 18)
50 # QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
51 # altogether. All # functions passed this value will return an error instead
52 # of raising an exception.
54 # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
55 # instead of raising an exception.
56 QUIET_NOTFOUND = (NOTFOUND,)
59 class FdtException(Exception):
60 """An exception caused by an error such as one of the codes above"""
61 def __init__(self, err):
65 return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
67 def strerror(fdt_err):
68 """Get the string for an error number
71 fdt_err: Error number (-ve)
74 String containing the associated error
76 return fdt_strerror(fdt_err)
78 def check_err(val, quiet=()):
79 """Raise an error if the return value is -ve
81 This is used to check for errors returned by libfdt C functions.
84 val: Return value from a libfdt function
85 quiet: Errors to ignore (empty to raise on all errors)
91 FdtException if val < 0
95 raise FdtException(val)
98 def check_err_null(val, quiet=()):
99 """Raise an error if the return value is NULL
101 This is used to check for a NULL return value from certain libfdt C
105 val: Return value from a libfdt function
106 quiet: Errors to ignore (empty to raise on all errors)
109 val if val is a list, None if not
112 FdtException if val indicates an error was reported and the error
115 # Normally a list is returned which contains the data and its length.
116 # If we get just an integer error code, it means the function failed.
117 if not isinstance(val, list):
118 if -val not in quiet:
119 raise FdtException(val)
124 """Device tree class, supporting all operations
126 The Fdt object is created is created from a device tree binary file,
127 e.g. with something like:
129 fdt = Fdt(open("filename.dtb").read())
131 Operations can then be performed using the methods in this class. Each
132 method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
134 All methods raise an FdtException if an error occurs. To avoid this
135 behaviour a 'quiet' parameter is provided for some functions. This
136 defaults to empty, but you can pass a list of errors that you expect.
137 If one of these errors occurs, the function will return an error number
140 def __init__(self, data):
141 self._fdt = bytearray(data)
142 check_err(fdt_check_header(self._fdt));
144 def as_bytearray(self):
145 """Get the device tree contents as a bytearray
147 This can be passed directly to libfdt functions that access a
148 const void * for the device tree.
151 bytearray containing the device tree
153 return bytearray(self._fdt)
155 def next_node(self, nodeoffset, depth, quiet=()):
156 """Find the next subnode
159 nodeoffset: Node offset of previous node
160 depth: On input, the depth of the node at nodeoffset. On output, the
161 depth of the returned node
162 quiet: Errors to ignore (empty to raise on all errors)
165 The offset of the next node, if any
168 FdtException if no more nodes found or other error occurs
170 return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
172 def first_subnode(self, nodeoffset, quiet=()):
173 """Find the first subnode of a parent node
176 nodeoffset: Node offset of parent node
177 quiet: Errors to ignore (empty to raise on all errors)
180 The offset of the first subnode, if any
183 FdtException if no subnodes found or other error occurs
185 return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
187 def next_subnode(self, nodeoffset, quiet=()):
188 """Find the next subnode
191 nodeoffset: Node offset of previous subnode
192 quiet: Errors to ignore (empty to raise on all errors)
195 The offset of the next subnode, if any
198 FdtException if no more subnodes found or other error occurs
200 return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
203 """Return the magic word from the header
208 return fdt_magic(self._fdt) & 0xffffffff
211 """Return the total size of the device tree
214 Total tree size in bytes
216 return check_err(fdt_totalsize(self._fdt))
218 def off_dt_struct(self):
219 """Return the start of the device-tree struct area
222 Start offset of struct area
224 return check_err(fdt_off_dt_struct(self._fdt))
226 def off_dt_strings(self):
227 """Return the start of the device-tree string area
230 Start offset of string area
232 return check_err(fdt_off_dt_strings(self._fdt))
234 def off_mem_rsvmap(self):
235 """Return the start of the memory reserve map
238 Start offset of memory reserve map
240 return check_err(fdt_off_mem_rsvmap(self._fdt))
243 """Return the version of the device tree
246 Version number of the device tree
248 return check_err(fdt_version(self._fdt))
250 def last_comp_version(self):
251 """Return the last compatible version of the device tree
254 Last compatible version number of the device tree
256 return check_err(fdt_last_comp_version(self._fdt))
258 def boot_cpuid_phys(self):
259 """Return the physical boot CPU ID
264 return check_err(fdt_boot_cpuid_phys(self._fdt))
266 def size_dt_strings(self):
267 """Return the start of the device-tree string area
270 Start offset of string area
272 return check_err(fdt_size_dt_strings(self._fdt))
274 def size_dt_struct(self):
275 """Return the start of the device-tree struct area
278 Start offset of struct area
280 return check_err(fdt_size_dt_struct(self._fdt))
282 def num_mem_rsv(self, quiet=()):
283 """Return the number of memory reserve-map records
286 Number of memory reserve-map records
288 return check_err(fdt_num_mem_rsv(self._fdt), quiet)
290 def get_mem_rsv(self, index, quiet=()):
291 """Return the indexed memory reserve-map record
294 index: Record to return (0=first)
297 Number of memory reserve-map records
299 return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
301 def subnode_offset(self, parentoffset, name, quiet=()):
302 """Get the offset of a named subnode
305 parentoffset: Offset of the parent node to check
306 name: Name of the required subnode, e.g. 'subnode@1'
307 quiet: Errors to ignore (empty to raise on all errors)
310 The node offset of the found node, if any
313 FdtException if there is no node with that name, or other error
315 return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
318 def path_offset(self, path, quiet=()):
319 """Get the offset for a given path
322 path: Path to the required node, e.g. '/node@3/subnode@1'
323 quiet: Errors to ignore (empty to raise on all errors)
329 FdtException if the path is not valid or not found
331 return check_err(fdt_path_offset(self._fdt, path), quiet)
333 def get_name(self, nodeoffset):
334 """Get the name of a node
337 nodeoffset: Offset of node to check
343 FdtException on error (e.g. nodeoffset is invalid)
345 return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
347 def first_property_offset(self, nodeoffset, quiet=()):
348 """Get the offset of the first property in a node offset
351 nodeoffset: Offset to the node to check
352 quiet: Errors to ignore (empty to raise on all errors)
355 Offset of the first property
358 FdtException if the associated node has no properties, or some
361 return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
364 def next_property_offset(self, prop_offset, quiet=()):
365 """Get the next property in a node
368 prop_offset: Offset of the previous property
369 quiet: Errors to ignore (empty to raise on all errors)
372 Offset of the next property
375 FdtException if the associated node has no more properties, or
376 some other error occurred
378 return check_err(fdt_next_property_offset(self._fdt, prop_offset),
381 def get_property_by_offset(self, prop_offset, quiet=()):
382 """Obtains a property that can be examined
385 prop_offset: Offset of property (e.g. from first_property_offset())
386 quiet: Errors to ignore (empty to raise on all errors)
389 Property object, or None if not found
392 FdtException on error (e.g. invalid prop_offset or device
395 pdata = check_err_null(
396 fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
397 if isinstance(pdata, (int)):
399 return Property(pdata[0], pdata[1])
402 def create_empty_tree(size, quiet=()):
403 """Create an empty device tree ready for use
406 size: Size of device tree in bytes
409 Fdt object containing the device tree
411 data = bytearray(size)
412 err = check_err(fdt_create_empty_tree(data, size), quiet)
417 def open_into(self, size, quiet=()):
418 """Move the device tree into a larger or smaller space
420 This creates a new device tree of size @size and moves the existing
421 device tree contents over to that. It can be used to create more space
425 size: Required new size of device tree in bytes
427 fdt = bytearray(size)
428 fdt[:len(self._fdt)] = self._fdt
429 err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
434 def pack(self, quiet=()):
435 """Pack the device tree to remove unused space
437 This adjusts the tree in place.
440 quiet: Errors to ignore (empty to raise on all errors)
443 FdtException if any error occurs
445 return check_err(fdt_pack(self._fdt), quiet)
447 def getprop(self, nodeoffset, prop_name, quiet=()):
448 """Get a property from a node
451 nodeoffset: Node offset containing property to get
452 prop_name: Name of property to get
453 quiet: Errors to ignore (empty to raise on all errors)
456 Value of property as a string, or -ve error number
459 FdtError if any error occurs (e.g. the property is not found)
461 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
463 if isinstance(pdata, (int)):
467 def getprop_obj(self, nodeoffset, prop_name, quiet=()):
468 """Get a property from a node as a Property object
471 nodeoffset: Node offset containing property to get
472 prop_name: Name of property to get
473 quiet: Errors to ignore (empty to raise on all errors)
476 Property object, or None if not found
479 FdtError if any error occurs (e.g. the property is not found)
481 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
483 if isinstance(pdata, (int)):
485 return Property(prop_name, bytearray(pdata[0]))
487 def get_phandle(self, nodeoffset):
488 """Get the phandle of a node
491 nodeoffset: Node offset to check
494 phandle of node, or 0 if the node has no phandle or another error
497 return fdt_get_phandle(self._fdt, nodeoffset)
499 def parent_offset(self, nodeoffset, quiet=()):
500 """Get the offset of a node's parent
503 nodeoffset: Node offset to check
504 quiet: Errors to ignore (empty to raise on all errors)
507 The offset of the parent node, if any
510 FdtException if no parent found or other error occurs
512 return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
514 def set_name(self, nodeoffset, name, quiet=()):
515 """Set the name of a node
518 nodeoffset: Node offset of node to update
522 Error code, or 0 if OK
525 FdtException if no parent found or other error occurs
527 return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
529 def setprop(self, nodeoffset, prop_name, val, quiet=()):
530 """Set the value of a property
533 nodeoffset: Node offset containing the property to create/update
534 prop_name: Name of property
535 val: Value to write (string or bytearray)
536 quiet: Errors to ignore (empty to raise on all errors)
539 Error code, or 0 if OK
542 FdtException if no parent found or other error occurs
544 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
547 def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
548 """Set the value of a property
551 nodeoffset: Node offset containing the property to create/update
552 prop_name: Name of property
553 val: Value to write (integer)
554 quiet: Errors to ignore (empty to raise on all errors)
557 Error code, or 0 if OK
560 FdtException if no parent found or other error occurs
562 return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
565 def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
566 """Set the value of a property
569 nodeoffset: Node offset containing the property to create/update
570 prop_name: Name of property
571 val: Value to write (integer)
572 quiet: Errors to ignore (empty to raise on all errors)
575 Error code, or 0 if OK
578 FdtException if no parent found or other error occurs
580 return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
583 def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
584 """Set the string value of a property
586 The property is set to the string, with a nul terminator added
589 nodeoffset: Node offset containing the property to create/update
590 prop_name: Name of property
591 val: Value to write (string without nul terminator)
592 quiet: Errors to ignore (empty to raise on all errors)
595 Error code, or 0 if OK
598 FdtException if no parent found or other error occurs
601 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
602 val, len(val)), quiet)
604 def delprop(self, nodeoffset, prop_name):
605 """Delete a property from a node
608 nodeoffset: Node offset containing property to delete
609 prop_name: Name of property to delete
612 FdtError if the property does not exist, or another error occurs
614 return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
616 def node_offset_by_phandle(self, phandle, quiet=()):
617 """Get the offset of a node with the given phandle
620 phandle: Phandle to search for
621 quiet: Errors to ignore (empty to raise on all errors)
624 The offset of node with that phandle, if any
627 FdtException if no node found or other error occurs
629 return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
632 class Property(bytearray):
633 """Holds a device tree property name and value.
635 This holds a copy of a property taken from the device tree. It does not
636 reference the device tree, so if anything changes in the device tree,
637 a Property object will remain valid.
641 value: Property value as a bytearray
643 def __init__(self, name, value):
644 bytearray.__init__(self, value)
647 def as_cell(self, fmt):
648 return struct.unpack('>' + fmt, self)[0]
651 return self.as_cell('L')
654 return self.as_cell('l')
657 return self.as_cell('Q')
660 return self.as_cell('q')
667 """Software interface to create a device tree from scratch
669 The methods in this class work by adding to an existing 'partial' device
670 tree buffer of a fixed size created by instantiating this class. When the
671 tree is complete, call finish() to complete the device tree so that it can
674 Similarly with nodes, a new node is started with begin_node() and finished
677 The context manager functions can be used to make this a bit easier:
679 # First create the device tree with a node and property:
680 with FdtSw(small_size) as sw:
681 with sw.AddNode('node'):
682 sw.property_u32('reg', 2)
685 # Now we can use it as a real device tree
686 fdt.setprop_u32(0, 'reg', 3)
688 def __init__(self, size, quiet=()):
689 fdtrw = bytearray(size)
690 err = check_err(fdt_create(fdtrw, size))
696 """Contact manager to use to create a device tree via software"""
699 def __exit__(self, type, value, traceback):
700 check_err(fdt_finish(self._fdtrw))
703 """Convert a FdtSw into an Fdt so it can be accessed as normal
705 Note that finish() must be called before this function will work. If
706 you are using the context manager (see 'with' code in the FdtSw class
707 comment) then this will happen automatically.
710 Fdt object allowing access to the newly created device tree
712 return Fdt(self._fdtrw)
714 def resize(self, size, quiet=()):
715 """Resize the buffer to accommodate a larger tree
718 size: New size of tree
719 quiet: Errors to ignore (empty to raise on all errors)
722 FdtException if no node found or other error occurs
724 fdt = bytearray(size)
725 fdt[:len(self._fdtrw)] = self._fdtrw
726 err = check_err(fdt_resize(self._fdtrw, fdt, size), quiet)
731 def add_reservemap_entry(self, addr, size, quiet=()):
732 """Add a new memory reserve map entry
734 Once finished adding, you must call finish_reservemap().
737 addr: 64-bit start address
739 quiet: Errors to ignore (empty to raise on all errors)
742 FdtException if no node found or other error occurs
744 return check_err(fdt_add_reservemap_entry(self._fdtrw, addr, size),
747 def finish_reservemap(self, quiet=()):
748 """Indicate that there are no more reserve map entries to add
751 quiet: Errors to ignore (empty to raise on all errors)
754 FdtException if no node found or other error occurs
756 return check_err(fdt_finish_reservemap(self._fdtrw), quiet)
758 def begin_node(self, name, quiet=()):
761 Use this before adding properties to the node. Then call end_node() to
762 finish it. You can also use the context manager as shown in the FdtSw
766 name: Name of node to begin
767 quiet: Errors to ignore (empty to raise on all errors)
770 FdtException if no node found or other error occurs
772 return check_err(fdt_begin_node(self._fdtrw, name), quiet)
774 def property_string(self, name, string, quiet=()):
775 """Add a property with a string value
777 The string will be nul-terminated when written to the device tree
780 name: Name of property to add
781 string: String value of property
782 quiet: Errors to ignore (empty to raise on all errors)
785 FdtException if no node found or other error occurs
787 return check_err(fdt_property_string(self._fdtrw, name, string), quiet)
789 def property_u32(self, name, val, quiet=()):
790 """Add a property with a 32-bit value
792 Write a single-cell value to the device tree
795 name: Name of property to add
796 val: Value of property
797 quiet: Errors to ignore (empty to raise on all errors)
800 FdtException if no node found or other error occurs
802 return check_err(fdt_property_u32(self._fdtrw, name, val), quiet)
804 def property_u64(self, name, val, quiet=()):
805 """Add a property with a 64-bit value
807 Write a double-cell value to the device tree in big-endian format
810 name: Name of property to add
811 val: Value of property
812 quiet: Errors to ignore (empty to raise on all errors)
815 FdtException if no node found or other error occurs
817 return check_err(fdt_property_u64(self._fdtrw, name, val), quiet)
819 def property_cell(self, name, val, quiet=()):
820 """Add a property with a single-cell value
822 Write a single-cell value to the device tree
825 name: Name of property to add
826 val: Value of property
827 quiet: Errors to ignore (empty to raise on all errors)
830 FdtException if no node found or other error occurs
832 return check_err(fdt_property_cell(self._fdtrw, name, val), quiet)
834 def property(self, name, val, quiet=()):
837 Write a new property with the given value to the device tree. The value
838 is taken as is and is not nul-terminated
841 name: Name of property to add
842 val: Value of property
843 quiet: Errors to ignore (empty to raise on all errors)
846 FdtException if no node found or other error occurs
848 return check_err(_fdt_property(self._fdtrw, name, val, len(val)), quiet)
850 def end_node(self, quiet=()):
853 Use this after adding properties to a node to close it off. You can also
854 use the context manager as shown in the FdtSw class comment.
857 quiet: Errors to ignore (empty to raise on all errors)
860 FdtException if no node found or other error occurs
862 return check_err(fdt_end_node(self._fdtrw), quiet)
864 def finish(self, quiet=()):
865 """Finish writing the device tree
867 This closes off the device tree ready for use
870 quiet: Errors to ignore (empty to raise on all errors)
873 FdtException if no node found or other error occurs
875 return check_err(fdt_finish(self._fdtrw), quiet)
877 def AddNode(self, name):
878 """Create a new context for adding a node
880 When used in a 'with' clause this starts a new node and finishes it
884 name: Name of node to add
886 return NodeAdder(self._fdtrw, name)
890 """Class to provide a node context
892 This allows you to add nodes in a more natural way:
894 with fdtsw.AddNode('name'):
895 fdtsw.property_string('test', 'value')
897 The node is automatically completed with a call to end_node() when the
900 def __init__(self, fdt, name):
905 check_err(fdt_begin_node(self._fdt, self._name))
907 def __exit__(self, type, value, traceback):
908 check_err(fdt_end_node(self._fdt))
911 %rename(fdt_property) fdt_property_func;
915 %include "libfdt/fdt.h"
917 %include "typemaps.i"
919 /* Most functions don't change the device tree, so use a const void * */
920 %typemap(in) (const void *)(const void *fdt) {
921 if (!PyByteArray_Check($input)) {
922 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
923 "', argument " "$argnum"" of type '" "$type""'");
925 $1 = (void *)PyByteArray_AsString($input);
927 fdt = fdt; /* avoid unused variable warning */
930 /* Some functions do change the device tree, so use void * */
931 %typemap(in) (void *)(const void *fdt) {
932 if (!PyByteArray_Check($input)) {
933 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
934 "', argument " "$argnum"" of type '" "$type""'");
936 $1 = PyByteArray_AsString($input);
938 fdt = fdt; /* avoid unused variable warning */
941 /* typemap used for fdt_get_property_by_offset() */
942 %typemap(out) (struct fdt_property *) {
946 resultobj = PyString_FromString(
947 fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
948 buff = PyByteArray_FromStringAndSize(
949 (const char *)($1 + 1), fdt32_to_cpu($1->len));
950 resultobj = SWIG_Python_AppendOutput(resultobj, buff);
954 %apply int *OUTPUT { int *lenp };
956 /* typemap used for fdt_getprop() */
957 %typemap(out) (const void *) {
961 $result = Py_BuildValue("s#", $1, *arg4);
964 /* typemap used for fdt_setprop() */
965 %typemap(in) (const void *val) {
966 $1 = PyString_AsString($input); /* char *str */
969 /* typemap used for fdt_add_reservemap_entry() */
970 %typemap(in) uint64_t {
971 $1 = PyLong_AsUnsignedLong($input);
974 /* typemaps used for fdt_next_node() */
975 %typemap(in, numinputs=1) int *depth (int depth) {
976 depth = (int) PyInt_AsLong($input);
980 %typemap(argout) int *depth {
981 PyObject *val = Py_BuildValue("i", *arg$argnum);
982 resultobj = SWIG_Python_AppendOutput(resultobj, val);
985 %apply int *depth { int *depth };
987 /* typemaps for fdt_get_mem_rsv */
988 %typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
992 %typemap(argout) uint64_t * {
993 PyObject *val = PyLong_FromUnsignedLong(*arg$argnum);
995 if (PyTuple_GET_SIZE(resultobj) == 0)
998 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1002 /* We have both struct fdt_property and a function fdt_property() */
1003 %warnfilter(302) fdt_property;
1005 /* These are macros in the header so have to be redefined here */
1006 int fdt_magic(const void *fdt);
1007 int fdt_totalsize(const void *fdt);
1008 int fdt_off_dt_struct(const void *fdt);
1009 int fdt_off_dt_strings(const void *fdt);
1010 int fdt_off_mem_rsvmap(const void *fdt);
1011 int fdt_version(const void *fdt);
1012 int fdt_last_comp_version(const void *fdt);
1013 int fdt_boot_cpuid_phys(const void *fdt);
1014 int fdt_size_dt_strings(const void *fdt);
1015 int fdt_size_dt_struct(const void *fdt);
1016 int fdt_property_string(void *fdt, const char *name, const char *val);
1017 int fdt_property_cell(void *fdt, const char *name, uint32_t val);
1020 * This function has a stub since the name fdt_property is used for both a
1021 * function and a struct, which confuses SWIG.
1023 int _fdt_property(void *fdt, const char *name, const char *val, int len);
1025 %include <../libfdt/libfdt.h>