1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2 /*
3 * pylibfdt - Flat Device Tree manipulation in Python
4 * Copyright (C) 2017 Google, Inc.
5 * Written by Simon Glass <[email protected]>
6 */
7
8 %module libfdt
9
10 %include <stdint.i>
11
12 %{
13 #define SWIG_FILE_WITH_INIT
14 #include "libfdt.h"
15
16 /*
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.
20 */
fdt_property_stub(void * fdt,const char * name,const void * val,int len)21 static int fdt_property_stub(void *fdt, const char *name, const void *val,
22 int len)
23 {
24 return fdt_property(fdt, name, val, len);
25 }
26
27 %}
28
29 %pythoncode %{
30
31 import struct
32
33 # Error codes, corresponding to FDT_ERR_... in libfdt.h
34 (NOTFOUND,
35 EXISTS,
36 NOSPACE,
37 BADOFFSET,
38 BADPATH,
39 BADPHANDLE,
40 BADSTATE,
41 TRUNCATED,
42 BADMAGIC,
43 BADVERSION,
44 BADSTRUCTURE,
45 BADLAYOUT,
46 INTERNAL,
47 BADNCELLS,
48 BADVALUE,
49 BADOVERLAY,
50 NOPHANDLES) = QUIET_ALL = range(1, 18)
51 # QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
52 # altogether. All # functions passed this value will return an error instead
53 # of raising an exception.
54
55 # Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
56 # instead of raising an exception.
57 QUIET_NOTFOUND = (NOTFOUND,)
58 QUIET_NOSPACE = (NOSPACE,)
59
60
61 class FdtException(Exception):
62 """An exception caused by an error such as one of the codes above"""
63 def __init__(self, err):
64 self.err = err
65
66 def __str__(self):
67 return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
68
69 def strerror(fdt_err):
70 """Get the string for an error number
71
72 Args:
73 fdt_err: Error number (-ve)
74
75 Returns:
76 String containing the associated error
77 """
78 return fdt_strerror(fdt_err)
79
80 def check_err(val, quiet=()):
81 """Raise an error if the return value is -ve
82
83 This is used to check for errors returned by libfdt C functions.
84
85 Args:
86 val: Return value from a libfdt function
87 quiet: Errors to ignore (empty to raise on all errors)
88
89 Returns:
90 val if val >= 0
91
92 Raises
93 FdtException if val < 0
94 """
95 if isinstance(val, int) and val < 0:
96 if -val not in quiet:
97 raise FdtException(val)
98 return val
99
100 def check_err_null(val, quiet=()):
101 """Raise an error if the return value is NULL
102
103 This is used to check for a NULL return value from certain libfdt C
104 functions
105
106 Args:
107 val: Return value from a libfdt function
108 quiet: Errors to ignore (empty to raise on all errors)
109
110 Returns:
111 val if val is a list, None if not
112
113 Raises
114 FdtException if val indicates an error was reported and the error
115 is not in @quiet.
116 """
117 # Normally a list is returned which contains the data and its length.
118 # If we get just an integer error code, it means the function failed.
119 if not isinstance(val, list):
120 if -val not in quiet:
121 raise FdtException(val)
122 return val
123
124 class FdtRo(object):
125 """Class for a read-only device-tree
126
127 This is a base class used by FdtRw (read-write access) and FdtSw
128 (sequential-write access). It implements read-only access to the
129 device tree.
130
131 Here are the three classes and when you should use them:
132
133 FdtRo - read-only access to an existing FDT
134 FdtRw - read-write access to an existing FDT (most common case)
135 FdtSw - for creating a new FDT, as well as allowing read-only access
136 """
137 def __init__(self, data):
138 self._fdt = bytearray(data)
139 check_err(fdt_check_header(self._fdt));
140
141 def as_bytearray(self):
142 """Get the device tree contents as a bytearray
143
144 This can be passed directly to libfdt functions that access a
145 const void * for the device tree.
146
147 Returns:
148 bytearray containing the device tree
149 """
150 return bytearray(self._fdt)
151
152 def next_node(self, nodeoffset, depth, quiet=()):
153 """Find the next subnode
154
155 Args:
156 nodeoffset: Node offset of previous node
157 depth: The depth of the node at nodeoffset. This is used to
158 calculate the depth of the returned node
159 quiet: Errors to ignore (empty to raise on all errors)
160
161 Returns:
162 Typle:
163 Offset of the next node, if any, else a -ve error
164 Depth of the returned node, if any, else undefined
165
166 Raises:
167 FdtException if no more nodes found or other error occurs
168 """
169 return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
170
171 def first_subnode(self, nodeoffset, quiet=()):
172 """Find the first subnode of a parent node
173
174 Args:
175 nodeoffset: Node offset of parent node
176 quiet: Errors to ignore (empty to raise on all errors)
177
178 Returns:
179 The offset of the first subnode, if any
180
181 Raises:
182 FdtException if no subnodes found or other error occurs
183 """
184 return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
185
186 def next_subnode(self, nodeoffset, quiet=()):
187 """Find the next subnode
188
189 Args:
190 nodeoffset: Node offset of previous subnode
191 quiet: Errors to ignore (empty to raise on all errors)
192
193 Returns:
194 The offset of the next subnode, if any
195
196 Raises:
197 FdtException if no more subnodes found or other error occurs
198 """
199 return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
200
201 def magic(self):
202 """Return the magic word from the header
203
204 Returns:
205 Magic word
206 """
207 return fdt_magic(self._fdt)
208
209 def totalsize(self):
210 """Return the total size of the device tree
211
212 Returns:
213 Total tree size in bytes
214 """
215 return fdt_totalsize(self._fdt)
216
217 def off_dt_struct(self):
218 """Return the start of the device-tree struct area
219
220 Returns:
221 Start offset of struct area
222 """
223 return fdt_off_dt_struct(self._fdt)
224
225 def off_dt_strings(self):
226 """Return the start of the device-tree string area
227
228 Returns:
229 Start offset of string area
230 """
231 return fdt_off_dt_strings(self._fdt)
232
233 def off_mem_rsvmap(self):
234 """Return the start of the memory reserve map
235
236 Returns:
237 Start offset of memory reserve map
238 """
239 return fdt_off_mem_rsvmap(self._fdt)
240
241 def version(self):
242 """Return the version of the device tree
243
244 Returns:
245 Version number of the device tree
246 """
247 return fdt_version(self._fdt)
248
249 def last_comp_version(self):
250 """Return the last compatible version of the device tree
251
252 Returns:
253 Last compatible version number of the device tree
254 """
255 return fdt_last_comp_version(self._fdt)
256
257 def boot_cpuid_phys(self):
258 """Return the physical boot CPU ID
259
260 Returns:
261 Physical boot CPU ID
262 """
263 return fdt_boot_cpuid_phys(self._fdt)
264
265 def size_dt_strings(self):
266 """Return the start of the device-tree string area
267
268 Returns:
269 Start offset of string area
270 """
271 return fdt_size_dt_strings(self._fdt)
272
273 def size_dt_struct(self):
274 """Return the start of the device-tree struct area
275
276 Returns:
277 Start offset of struct area
278 """
279 return fdt_size_dt_struct(self._fdt)
280
281 def num_mem_rsv(self, quiet=()):
282 """Return the number of memory reserve-map records
283
284 Returns:
285 Number of memory reserve-map records
286 """
287 return check_err(fdt_num_mem_rsv(self._fdt), quiet)
288
289 def get_mem_rsv(self, index, quiet=()):
290 """Return the indexed memory reserve-map record
291
292 Args:
293 index: Record to return (0=first)
294
295 Returns:
296 Number of memory reserve-map records
297 """
298 return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
299
300 def subnode_offset(self, parentoffset, name, quiet=()):
301 """Get the offset of a named subnode
302
303 Args:
304 parentoffset: Offset of the parent node to check
305 name: Name of the required subnode, e.g. 'subnode@1'
306 quiet: Errors to ignore (empty to raise on all errors)
307
308 Returns:
309 The node offset of the found node, if any
310
311 Raises
312 FdtException if there is no node with that name, or other error
313 """
314 return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
315 quiet)
316
317 def path_offset(self, path, quiet=()):
318 """Get the offset for a given path
319
320 Args:
321 path: Path to the required node, e.g. '/node@3/subnode@1'
322 quiet: Errors to ignore (empty to raise on all errors)
323
324 Returns:
325 Node offset
326
327 Raises
328 FdtException if the path is not valid or not found
329 """
330 return check_err(fdt_path_offset(self._fdt, path), quiet)
331
332 def get_name(self, nodeoffset):
333 """Get the name of a node
334
335 Args:
336 nodeoffset: Offset of node to check
337
338 Returns:
339 Node name
340
341 Raises:
342 FdtException on error (e.g. nodeoffset is invalid)
343 """
344 return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
345
346 def first_property_offset(self, nodeoffset, quiet=()):
347 """Get the offset of the first property in a node offset
348
349 Args:
350 nodeoffset: Offset to the node to check
351 quiet: Errors to ignore (empty to raise on all errors)
352
353 Returns:
354 Offset of the first property
355
356 Raises
357 FdtException if the associated node has no properties, or some
358 other error occurred
359 """
360 return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
361 quiet)
362
363 def next_property_offset(self, prop_offset, quiet=()):
364 """Get the next property in a node
365
366 Args:
367 prop_offset: Offset of the previous property
368 quiet: Errors to ignore (empty to raise on all errors)
369
370 Returns:
371 Offset of the next property
372
373 Raises:
374 FdtException if the associated node has no more properties, or
375 some other error occurred
376 """
377 return check_err(fdt_next_property_offset(self._fdt, prop_offset),
378 quiet)
379
380 def get_property_by_offset(self, prop_offset, quiet=()):
381 """Obtains a property that can be examined
382
383 Args:
384 prop_offset: Offset of property (e.g. from first_property_offset())
385 quiet: Errors to ignore (empty to raise on all errors)
386
387 Returns:
388 Property object, or None if not found
389
390 Raises:
391 FdtException on error (e.g. invalid prop_offset or device
392 tree format)
393 """
394 pdata = check_err_null(
395 fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
396 if isinstance(pdata, (int)):
397 return pdata
398 return Property(pdata[0], pdata[1])
399
400 def getprop(self, nodeoffset, prop_name, quiet=()):
401 """Get a property from a node
402
403 Args:
404 nodeoffset: Node offset containing property to get
405 prop_name: Name of property to get
406 quiet: Errors to ignore (empty to raise on all errors)
407
408 Returns:
409 Value of property as a Property object (which can be used as a
410 bytearray/string), or -ve error number. On failure, returns an
411 integer error
412
413 Raises:
414 FdtError if any error occurs (e.g. the property is not found)
415 """
416 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
417 quiet)
418 if isinstance(pdata, (int)):
419 return pdata
420 return Property(prop_name, bytearray(pdata[0]))
421
422 def get_phandle(self, nodeoffset):
423 """Get the phandle of a node
424
425 Args:
426 nodeoffset: Node offset to check
427
428 Returns:
429 phandle of node, or 0 if the node has no phandle or another error
430 occurs
431 """
432 return fdt_get_phandle(self._fdt, nodeoffset)
433
434 def get_alias(self, name):
435 """Get the full path referenced by a given alias
436
437 Args:
438 name: name of the alias to lookup
439
440 Returns:
441 Full path to the node for the alias named 'name', if it exists
442 None, if the given alias or the /aliases node does not exist
443 """
444 return fdt_get_alias(self._fdt, name)
445
446 def get_path(self, nodeoffset, size_hint=1024, quiet=()):
447 """Get the full path of a node
448
449 Args:
450 nodeoffset: Node offset to check
451 size_hint: Hint for size of returned string
452
453 Returns:
454 Full path to the node
455
456 Raises:
457 FdtException if an error occurs
458 """
459 while True:
460 ret, path = fdt_get_path(self._fdt, nodeoffset, size_hint)
461 if ret == -NOSPACE:
462 size_hint *= 2
463 continue
464 err = check_err(ret, quiet)
465 if err:
466 return err
467 return path
468
469 def parent_offset(self, nodeoffset, quiet=()):
470 """Get the offset of a node's parent
471
472 Args:
473 nodeoffset: Node offset to check
474 quiet: Errors to ignore (empty to raise on all errors)
475
476 Returns:
477 The offset of the parent node, if any
478
479 Raises:
480 FdtException if no parent found or other error occurs
481 """
482 return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
483
484 def node_offset_by_phandle(self, phandle, quiet=()):
485 """Get the offset of a node with the given phandle
486
487 Args:
488 phandle: Phandle to search for
489 quiet: Errors to ignore (empty to raise on all errors)
490
491 Returns:
492 The offset of node with that phandle, if any
493
494 Raises:
495 FdtException if no node found or other error occurs
496 """
497 return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
498
499
500 class Fdt(FdtRo):
501 """Device tree class, supporting all operations
502
503 The Fdt object is created is created from a device tree binary file,
504 e.g. with something like:
505
506 fdt = Fdt(open("filename.dtb").read())
507
508 Operations can then be performed using the methods in this class. Each
509 method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
510
511 All methods raise an FdtException if an error occurs. To avoid this
512 behaviour a 'quiet' parameter is provided for some functions. This
513 defaults to empty, but you can pass a list of errors that you expect.
514 If one of these errors occurs, the function will return an error number
515 (e.g. -NOTFOUND).
516 """
517 def __init__(self, data):
518 FdtRo.__init__(self, data)
519
520 @staticmethod
521 def create_empty_tree(size, quiet=()):
522 """Create an empty device tree ready for use
523
524 Args:
525 size: Size of device tree in bytes
526
527 Returns:
528 Fdt object containing the device tree
529 """
530 data = bytearray(size)
531 err = check_err(fdt_create_empty_tree(data, size), quiet)
532 if err:
533 return err
534 return Fdt(data)
535
536 def resize(self, size, quiet=()):
537 """Move the device tree into a larger or smaller space
538
539 This creates a new device tree of size @size and moves the existing
540 device tree contents over to that. It can be used to create more space
541 in a device tree. Note that the Fdt object remains the same, but it
542 now has a new bytearray holding the contents.
543
544 Args:
545 size: Required new size of device tree in bytes
546 """
547 fdt = bytearray(size)
548 err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
549 if err:
550 return err
551 self._fdt = fdt
552
553 def pack(self, quiet=()):
554 """Pack the device tree to remove unused space
555
556 This adjusts the tree in place.
557
558 Args:
559 quiet: Errors to ignore (empty to raise on all errors)
560
561 Returns:
562 Error code, or 0 if OK
563
564 Raises:
565 FdtException if any error occurs
566 """
567 err = check_err(fdt_pack(self._fdt), quiet)
568 if err:
569 return err
570 del self._fdt[self.totalsize():]
571 return err
572
573 def set_name(self, nodeoffset, name, quiet=()):
574 """Set the name of a node
575
576 Args:
577 nodeoffset: Node offset of node to update
578 name: New node name (string without \0)
579
580 Returns:
581 Error code, or 0 if OK
582
583 Raises:
584 FdtException if no parent found or other error occurs
585 """
586 if chr(0) in name:
587 raise ValueError('Property contains embedded nul characters')
588 return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
589
590 def setprop(self, nodeoffset, prop_name, val, quiet=()):
591 """Set the value of a property
592
593 Args:
594 nodeoffset: Node offset containing the property to create/update
595 prop_name: Name of property
596 val: Value to write (string or bytearray)
597 quiet: Errors to ignore (empty to raise on all errors)
598
599 Returns:
600 Error code, or 0 if OK
601
602 Raises:
603 FdtException if no parent found or other error occurs
604 """
605 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
606 len(val)), quiet)
607
608 def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
609 """Set the value of a property
610
611 Args:
612 nodeoffset: Node offset containing the property to create/update
613 prop_name: Name of property
614 val: Value to write (integer)
615 quiet: Errors to ignore (empty to raise on all errors)
616
617 Returns:
618 Error code, or 0 if OK
619
620 Raises:
621 FdtException if no parent found or other error occurs
622 """
623 return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
624 quiet)
625
626 def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
627 """Set the value of a property
628
629 Args:
630 nodeoffset: Node offset containing the property to create/update
631 prop_name: Name of property
632 val: Value to write (integer)
633 quiet: Errors to ignore (empty to raise on all errors)
634
635 Returns:
636 Error code, or 0 if OK
637
638 Raises:
639 FdtException if no parent found or other error occurs
640 """
641 return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
642 quiet)
643
644 def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
645 """Set the string value of a property
646
647 The property is set to the string, with a nul terminator added
648
649 Args:
650 nodeoffset: Node offset containing the property to create/update
651 prop_name: Name of property
652 val: Value to write (string without nul terminator). Unicode is
653 supposed by encoding to UTF-8
654 quiet: Errors to ignore (empty to raise on all errors)
655
656 Returns:
657 Error code, or 0 if OK
658
659 Raises:
660 FdtException if no parent found or other error occurs
661 """
662 val = val.encode('utf-8') + b'\0'
663 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
664 val, len(val)), quiet)
665
666 def delprop(self, nodeoffset, prop_name, quiet=()):
667 """Delete a property from a node
668
669 Args:
670 nodeoffset: Node offset containing property to delete
671 prop_name: Name of property to delete
672 quiet: Errors to ignore (empty to raise on all errors)
673
674 Returns:
675 Error code, or 0 if OK
676
677 Raises:
678 FdtError if the property does not exist, or another error occurs
679 """
680 return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name), quiet)
681
682 def add_subnode(self, parentoffset, name, quiet=()):
683 """Add a new subnode to a node
684
685 Args:
686 parentoffset: Parent offset to add the subnode to
687 name: Name of node to add
688
689 Returns:
690 offset of the node created, or negative error code on failure
691
692 Raises:
693 FdtError if there is not enough space, or another error occurs
694 """
695 return check_err(fdt_add_subnode(self._fdt, parentoffset, name), quiet)
696
697 def del_node(self, nodeoffset, quiet=()):
698 """Delete a node
699
700 Args:
701 nodeoffset: Offset of node to delete
702
703 Returns:
704 Error code, or 0 if OK
705
706 Raises:
707 FdtError if an error occurs
708 """
709 return check_err(fdt_del_node(self._fdt, nodeoffset), quiet)
710
711
712 class Property(bytearray):
713 """Holds a device tree property name and value.
714
715 This holds a copy of a property taken from the device tree. It does not
716 reference the device tree, so if anything changes in the device tree,
717 a Property object will remain valid.
718
719 Properties:
720 name: Property name
721 value: Property value as a bytearray
722 """
723 def __init__(self, name, value):
724 bytearray.__init__(self, value)
725 self.name = name
726
727 def as_cell(self, fmt):
728 return struct.unpack('>' + fmt, self)[0]
729
730 def as_uint32(self):
731 return self.as_cell('L')
732
733 def as_int32(self):
734 return self.as_cell('l')
735
736 def as_uint64(self):
737 return self.as_cell('Q')
738
739 def as_int64(self):
740 return self.as_cell('q')
741
742 def as_list(self, fmt):
743 return list(map(lambda x: x[0], struct.iter_unpack('>' + fmt, self)))
744
745 def as_uint32_list(self):
746 return self.as_list('L')
747
748 def as_int32_list(self):
749 return self.as_list('l')
750
751 def as_uint64_list(self):
752 return self.as_list('Q')
753
754 def as_int64_list(self):
755 return self.as_list('q')
756
757 def as_str(self):
758 """Unicode is supported by decoding from UTF-8"""
759 if self[-1] != 0:
760 raise ValueError('Property lacks nul termination')
761 if 0 in self[:-1]:
762 raise ValueError('Property contains embedded nul characters')
763 return self[:-1].decode('utf-8')
764
765 def as_stringlist(self):
766 """Unicode is supported by decoding from UTF-8"""
767 if self[-1] != 0:
768 raise ValueError('Property lacks nul termination')
769 parts = self[:-1].split(b'\x00')
770 return list(map(lambda x: x.decode('utf-8'), parts))
771
772
773 class FdtSw(FdtRo):
774 """Software interface to create a device tree from scratch
775
776 The methods in this class work by adding to an existing 'partial' device
777 tree buffer of a fixed size created by instantiating this class. When the
778 tree is complete, call as_fdt() to obtain a device tree ready to be used.
779
780 Similarly with nodes, a new node is started with begin_node() and finished
781 with end_node().
782
783 The context manager functions can be used to make this a bit easier:
784
785 # First create the device tree with a node and property:
786 sw = FdtSw()
787 sw.finish_reservemap()
788 with sw.add_node(''):
789 with sw.add_node('node'):
790 sw.property_u32('reg', 2)
791 fdt = sw.as_fdt()
792
793 # Now we can use it as a real device tree
794 fdt.setprop_u32(0, 'reg', 3)
795
796 The size hint provides a starting size for the space to be used by the
797 device tree. This will be increased automatically as needed as new items
798 are added to the tree.
799 """
800 INC_SIZE = 1024 # Expand size by this much when out of space
801
802 def __init__(self, size_hint=None):
803 """Create a new FdtSw object
804
805 Args:
806 size_hint: A hint as to the initial size to use
807
808 Raises:
809 ValueError if size_hint is negative
810
811 Returns:
812 FdtSw object on success, else integer error code (if not raising)
813 """
814 if not size_hint:
815 size_hint = self.INC_SIZE
816 fdtsw = bytearray(size_hint)
817 err = check_err(fdt_create(fdtsw, size_hint))
818 if err:
819 return err
820 self._fdt = fdtsw
821
822 def as_fdt(self):
823 """Convert a FdtSw into an Fdt so it can be accessed as normal
824
825 Creates a new Fdt object from the work-in-progress device tree. This
826 does not call fdt_finish() on the current object, so it is possible to
827 add more nodes/properties and call as_fdt() again to get an updated
828 tree.
829
830 Returns:
831 Fdt object allowing access to the newly created device tree
832 """
833 fdtsw = bytearray(self._fdt)
834 check_err(fdt_finish(fdtsw))
835 return Fdt(fdtsw)
836
837 def check_space(self, val):
838 """Check if we need to add more space to the FDT
839
840 This should be called with the error code from an operation. If this is
841 -NOSPACE then the FDT will be expanded to have more space, and True will
842 be returned, indicating that the operation needs to be tried again.
843
844 Args:
845 val: Return value from the operation that was attempted
846
847 Returns:
848 True if the operation must be retried, else False
849 """
850 if check_err(val, QUIET_NOSPACE) < 0:
851 self.resize(len(self._fdt) + self.INC_SIZE)
852 return True
853 return False
854
855 def resize(self, size):
856 """Resize the buffer to accommodate a larger tree
857
858 Args:
859 size: New size of tree
860
861 Raises:
862 FdtException on any error
863 """
864 fdt = bytearray(size)
865 err = check_err(fdt_resize(self._fdt, fdt, size))
866 self._fdt = fdt
867
868 def add_reservemap_entry(self, addr, size):
869 """Add a new memory reserve map entry
870
871 Once finished adding, you must call finish_reservemap().
872
873 Args:
874 addr: 64-bit start address
875 size: 64-bit size
876
877 Raises:
878 FdtException on any error
879 """
880 while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
881 size)):
882 pass
883
884 def finish_reservemap(self):
885 """Indicate that there are no more reserve map entries to add
886
887 Raises:
888 FdtException on any error
889 """
890 while self.check_space(fdt_finish_reservemap(self._fdt)):
891 pass
892
893 def begin_node(self, name):
894 """Begin a new node
895
896 Use this before adding properties to the node. Then call end_node() to
897 finish it. You can also use the context manager as shown in the FdtSw
898 class comment.
899
900 Args:
901 name: Name of node to begin
902
903 Raises:
904 FdtException on any error
905 """
906 while self.check_space(fdt_begin_node(self._fdt, name)):
907 pass
908
909 def property_string(self, name, string):
910 """Add a property with a string value
911
912 The string will be nul-terminated when written to the device tree
913
914 Args:
915 name: Name of property to add
916 string: String value of property
917
918 Raises:
919 FdtException on any error
920 """
921 while self.check_space(fdt_property_string(self._fdt, name, string)):
922 pass
923
924 def property_u32(self, name, val):
925 """Add a property with a 32-bit value
926
927 Write a single-cell value to the device tree
928
929 Args:
930 name: Name of property to add
931 val: Value of property
932
933 Raises:
934 FdtException on any error
935 """
936 while self.check_space(fdt_property_u32(self._fdt, name, val)):
937 pass
938
939 def property_u64(self, name, val):
940 """Add a property with a 64-bit value
941
942 Write a double-cell value to the device tree in big-endian format
943
944 Args:
945 name: Name of property to add
946 val: Value of property
947
948 Raises:
949 FdtException on any error
950 """
951 while self.check_space(fdt_property_u64(self._fdt, name, val)):
952 pass
953
954 def property_cell(self, name, val):
955 """Add a property with a single-cell value
956
957 Write a single-cell value to the device tree
958
959 Args:
960 name: Name of property to add
961 val: Value of property
962 quiet: Errors to ignore (empty to raise on all errors)
963
964 Raises:
965 FdtException on any error
966 """
967 while self.check_space(fdt_property_cell(self._fdt, name, val)):
968 pass
969
970 def property(self, name, val):
971 """Add a property
972
973 Write a new property with the given value to the device tree. The value
974 is taken as is and is not nul-terminated
975
976 Args:
977 name: Name of property to add
978 val: Value of property (bytes)
979 quiet: Errors to ignore (empty to raise on all errors)
980
981 Raises:
982 FdtException on any error
983 """
984 while self.check_space(fdt_property_stub(self._fdt, name, val,
985 len(val))):
986 pass
987
988 def end_node(self):
989 """End a node
990
991 Use this after adding properties to a node to close it off. You can also
992 use the context manager as shown in the FdtSw class comment.
993
994 Args:
995 quiet: Errors to ignore (empty to raise on all errors)
996
997 Raises:
998 FdtException on any error
999 """
1000 while self.check_space(fdt_end_node(self._fdt)):
1001 pass
1002
1003 def add_node(self, name):
1004 """Create a new context for adding a node
1005
1006 When used in a 'with' clause this starts a new node and finishes it
1007 afterward.
1008
1009 Args:
1010 name: Name of node to add
1011 """
1012 return NodeAdder(self, name)
1013
1014
1015 class NodeAdder():
1016 """Class to provide a node context
1017
1018 This allows you to add nodes in a more natural way:
1019
1020 with fdtsw.add_node('name'):
1021 fdtsw.property_string('test', 'value')
1022
1023 The node is automatically completed with a call to end_node() when the
1024 context exits.
1025 """
1026 def __init__(self, fdtsw, name):
1027 self._fdt = fdtsw
1028 self._name = name
1029
1030 def __enter__(self):
1031 self._fdt.begin_node(self._name)
1032
1033 def __exit__(self, type, value, traceback):
1034 self._fdt.end_node()
1035 %}
1036
1037 %rename(fdt_property) fdt_property_func;
1038
1039 %immutable fdt_property::data;
1040 %immutable fdt_node_header::name;
1041
1042 /*
1043 * fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h
1044 * so use the same type here.
1045 */
1046 typedef uint32_t fdt32_t;
1047
1048 %include "fdt.h"
1049
1050 %include "typemaps.i"
1051
1052 /* Most functions don't change the device tree, so use a const void * */
1053 %typemap(in) (const void *)(const void *fdt) {
1054 if (!PyByteArray_Check($input)) {
1055 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1056 "', argument " "$argnum"" of type '" "$type""'");
1057 }
1058 $1 = (void *)PyByteArray_AsString($input);
1059 fdt = $1;
1060 (void)fdt; /* avoid unused variable warning */
1061 }
1062
1063 /* Some functions do change the device tree, so use void * */
1064 %typemap(in) (void *)(const void *fdt) {
1065 if (!PyByteArray_Check($input)) {
1066 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1067 "', argument " "$argnum"" of type '" "$type""'");
1068 }
1069 $1 = PyByteArray_AsString($input);
1070 fdt = $1;
1071 (void)fdt; /* avoid unused variable warning */
1072 }
1073
1074 /* typemap used for fdt_get_property_by_offset() */
1075 %typemap(out) (struct fdt_property *) {
1076 PyObject *buff;
1077
1078 if ($1) {
1079 resultobj = PyString_FromString(
1080 fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
1081 buff = PyByteArray_FromStringAndSize(
1082 (const char *)($1 + 1), fdt32_to_cpu($1->len));
1083 resultobj = SWIG_Python_AppendOutput(resultobj, buff);
1084 }
1085 }
1086
1087 %apply int *OUTPUT { int *lenp };
1088
1089 /* typemap used for fdt_getprop() */
1090 %typemap(out) (const void *) {
1091 if (!$1) {
1092 $result = Py_None;
1093 Py_INCREF($result);
1094 } else {
1095 %#if PY_VERSION_HEX >= 0x03000000
1096 $result = Py_BuildValue("y#", $1, (Py_ssize_t)*arg4);
1097 %#else
1098 $result = Py_BuildValue("s#", $1, (Py_ssize_t)*arg4);
1099 %#endif
1100 }
1101 }
1102
1103 /* typemap used for fdt_setprop() */
1104 %typemap(in) (const void *val) {
1105 %#if PY_VERSION_HEX >= 0x03000000
1106 if (!PyBytes_Check($input)) {
1107 SWIG_exception_fail(SWIG_TypeError, "bytes expected in method '" "$symname"
1108 "', argument " "$argnum"" of type '" "$type""'");
1109 }
1110 $1 = PyBytes_AsString($input);
1111 %#else
1112 $1 = PyString_AsString($input); /* char *str */
1113 %#endif
1114 }
1115
1116 /* typemaps used for fdt_next_node() */
1117 %typemap(in, numinputs=1) int *depth (int depth) {
1118 depth = (int) PyInt_AsLong($input);
1119 $1 = &depth;
1120 }
1121
1122 %typemap(argout) int *depth {
1123 PyObject *val = Py_BuildValue("i", *arg$argnum);
1124 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1125 }
1126
1127 %apply int *depth { int *depth };
1128
1129 /* typemaps for fdt_get_mem_rsv */
1130 %typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
1131 $1 = &temp;
1132 }
1133
1134 %typemap(argout) uint64_t * {
1135 PyObject *val = PyLong_FromUnsignedLongLong(*arg$argnum);
1136 if (!result) {
1137 if (PyTuple_GET_SIZE(resultobj) == 0)
1138 resultobj = val;
1139 else
1140 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1141 }
1142 }
1143
1144 %include "cstring.i"
1145
1146 %cstring_output_maxsize(char *buf, int buflen);
1147 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
1148
1149 /* We have both struct fdt_property and a function fdt_property() */
1150 %warnfilter(302) fdt_property;
1151
1152 /* These are macros in the header so have to be redefined here */
1153 uint32_t fdt_magic(const void *fdt);
1154 uint32_t fdt_totalsize(const void *fdt);
1155 uint32_t fdt_off_dt_struct(const void *fdt);
1156 uint32_t fdt_off_dt_strings(const void *fdt);
1157 uint32_t fdt_off_mem_rsvmap(const void *fdt);
1158 uint32_t fdt_version(const void *fdt);
1159 uint32_t fdt_last_comp_version(const void *fdt);
1160 uint32_t fdt_boot_cpuid_phys(const void *fdt);
1161 uint32_t fdt_size_dt_strings(const void *fdt);
1162 uint32_t fdt_size_dt_struct(const void *fdt);
1163
1164 int fdt_property_string(void *fdt, const char *name, const char *val);
1165 int fdt_property_cell(void *fdt, const char *name, uint32_t val);
1166
1167 /*
1168 * This function has a stub since the name fdt_property is used for both a
1169 * function and a struct, which confuses SWIG.
1170 */
1171 int fdt_property_stub(void *fdt, const char *name, const void *val, int len);
1172
1173 %include <libfdt.h>
1174