1
2 """
3 Device Tree Blob Parser
4
5 Copyright 2014 Neil 'superna' Armstrong <superna9999@gmail.com>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19 @author: Neil 'superna' Armstrong <superna9999@gmail.com>
20 """
21
22 import string
23 import os
24 import json
25 from copy import deepcopy, copy
26 from struct import Struct, unpack, pack
27
28 FDT_MAGIC = 0xd00dfeed
29 FDT_BEGIN_NODE = 0x1
30 FDT_END_NODE = 0x2
31 FDT_PROP = 0x3
32 FDT_NOP = 0x4
33 FDT_END = 0x9
34
35 INDENT = ' ' * 4
36
37 FDT_MAX_VERSION = 17
41 """ Represents an empty property"""
42
43 @staticmethod
45 """Checks the name validity"""
46 return not any([True for char in name
47 if char not in string.printable])
48
50 """Init with name"""
51 self.name = name
52 if not FdtProperty.__validate_dt_name(self.name):
53 raise Exception("Invalid name '%s'" % self.name)
54
56 """Get property name"""
57 return self.name
58
60 """String representation"""
61 return "Property(%s)" % self.name
62
64 """Get dts string representation"""
65 return INDENT*depth + self.name + ';'
66
68 """Get blob representation"""
69
70 strpos = string_store.find(self.name+'\0')
71 if strpos < 0:
72 strpos = len(string_store)
73 string_store += self.name+'\0'
74 pos += 12
75 return (pack('>III', FDT_PROP, 0, strpos),
76 string_store, pos)
77
79 """Ouput JSON"""
80 return '%s: null' % json.dumps(self.name)
81
83 """Return RAW value representation"""
84 return ''
85
87 """Returns No Items"""
88 return None
89
91 """Check property inequality
92 """
93 return not self.__eq__(node)
94
96 """Check node equality
97 check properties are the same (same values)
98 """
99 if not isinstance(node, FdtProperty):
100 raise Exception("Invalid object type")
101 if self.name != node.get_name():
102 return False
103 return True
104
105 @staticmethod
107 """Check property string validity
108 Python version of util_is_printable_string from dtc
109 """
110 pos = 0
111 posi = 0
112 end = len(value)
113
114 if not len(value):
115 return None
116
117 if ord(value[-1]) > 0:
118 return None
119
120 while pos < end:
121 posi = pos
122 while pos < end and ord(value[pos]) > 0 \
123 and value[pos] in string.printable \
124 and value[pos] not in ('\r', '\n'):
125 pos += 1
126
127 if ord(value[pos]) > 0 or pos == posi:
128 return None
129 pos += 1
130
131 return True
132
133 @staticmethod
144
147 """Property with strings as value"""
148
149 @classmethod
151 """Extract strings from raw_value"""
152 return [st for st in value.split('\0') if len(st)]
153
155 """Init with strings"""
156 FdtProperty.__init__(self, name)
157 if not strings:
158 raise Exception("Invalid strings")
159 for stri in strings:
160 if len(stri) == 0:
161 raise Exception("Invalid strings")
162 if any([True for char in stri
163 if char not in string.printable
164 or char in ('\r', '\n')]):
165 raise Exception("Invalid chars in strings")
166 self.strings = strings
167
168 @classmethod
172
174 """Get dts string representation"""
175 return INDENT*depth + self.name + ' = "' + \
176 '", "'.join(self.strings) + '";'
177
179 """Get blob representation"""
180
181 blob = ''
182 for chars in self.strings:
183 blob += chars + '\0'
184 blob_len = len(blob)
185 if version < 16 and (pos+12) % 8 != 0:
186 blob = '\0'*(8-((pos+12) % 8)) + blob
187 if blob_len % 4:
188 blob += '\0'*(4-(blob_len % 4))
189 strpos = string_store.find(self.name+'\0')
190 if strpos < 0:
191 strpos = len(string_store)
192 string_store += self.name+'\0'
193 blob = pack('>III', FDT_PROP, blob_len, strpos) + blob
194 pos += len(blob)
195 return (blob, string_store, pos)
196
198 """Ouput JSON"""
199 result = '%s: ["strings", ' % json.dumps(self.name)
200 result += ', '.join([json.dumps(stri) for stri in self.strings])
201 result += ']'
202 return result
203
205 """Return RAW value representation"""
206 return ''.join([chars+'\0' for chars in self.strings])
207
209 """String representation"""
210 return "Property(%s,Strings:%s)" % (self.name, self.strings)
211
213 """Get strings, returns a string"""
214 return self.strings[index]
215
217 """Get strings count"""
218 return len(self.strings)
219
221 """Check node equality
222 check properties are the same (same values)
223 """
224 if not FdtProperty.__eq__(self, node):
225 return False
226 if self.__len__() != len(node):
227 return False
228 for index in range(self.__len__()):
229 if self.strings[index] != node[index]:
230 return False
231 return True
232
234 """Property with words as value"""
235
237 """Init with words"""
238 FdtProperty.__init__(self, name)
239 for word in words:
240 if not 0 <= word <= 4294967295:
241 raise Exception("Invalid word value %d, requires 0 <= number <= 4294967295" % word)
242 if not len(words):
243 raise Exception("Invalid Words")
244 self.words = words
245
246 @classmethod
248 """Init from raw"""
249 if len(raw_value) % 4 == 0:
250 words = [unpack(">I", raw_value[i:i+4])[0]
251 for i in range(0, len(raw_value), 4)]
252 return cls(name, words)
253 else:
254 raise Exception("Invalid raw Words")
255
257 """Get dts string representation"""
258 return INDENT*depth + self.name + ' = <' + \
259 ' '.join(["0x%08x" % word for word in self.words]) + ">;"
260
262 """Get blob representation"""
263
264 strpos = string_store.find(self.name+'\0')
265 if strpos < 0:
266 strpos = len(string_store)
267 string_store += self.name+'\0'
268 blob = pack('>III', FDT_PROP, len(self.words)*4, strpos) + \
269 ''.join([pack('>I', word) for word in self.words])
270 pos += len(blob)
271 return (blob, string_store, pos)
272
274 """Ouput JSON"""
275 result = '%s: ["words", "' % json.dumps(self.name)
276 result += '", "'.join(["0x%08x" % word for word in self.words])
277 result += '"]'
278 return result
279
281 """Return RAW value representation"""
282 return ''.join([pack('>I', word) for word in self.words])
283
285 """String representation"""
286 return "Property(%s,Words:%s)" % (self.name, self.words)
287
289 """Get words, returns a word integer"""
290 return self.words[index]
291
293 """Get words count"""
294 return len(self.words)
295
297 """Check node equality
298 check properties are the same (same values)
299 """
300 if not FdtProperty.__eq__(self, node):
301 return False
302 if self.__len__() != len(node):
303 return False
304 for index in range(self.__len__()):
305 if self.words[index] != node[index]:
306 return False
307 return True
308
311 """Property with signed bytes as value"""
312
314 """Init with bytes"""
315 FdtProperty.__init__(self, name)
316 for byte in bytez:
317 if not -128 <= byte <= 127:
318 raise Exception("Invalid value for byte %d, requires -128 <= number <= 127" % byte)
319 if not bytez:
320 raise Exception("Invalid Bytes")
321 self.bytes = bytez
322
323 @classmethod
325 """Init from raw"""
326 return cls(name, [unpack('b', byte)[0] for byte in raw_value])
327
329 """Get dts string representation"""
330 return INDENT*depth + self.name + ' = [' + \
331 ' '.join(["%02x" % (byte & int('ffffffff',16))
332 for byte in self.bytes]) + "];"
333
335 """Get blob representation"""
336
337 strpos = string_store.find(self.name+'\0')
338 if strpos < 0:
339 strpos = len(string_store)
340 string_store += self.name+'\0'
341 blob = pack('>III', FDT_PROP, len(self.bytes), strpos)
342 blob += ''.join([pack('>b', byte) for byte in self.bytes])
343 if len(blob) % 4:
344 blob += '\0'*(4-(len(blob) % 4))
345 pos += len(blob)
346 return (blob, string_store, pos)
347
349 """Ouput JSON"""
350 result = '%s: ["bytes", "' % json.dumps(self.name)
351 result += '", "'.join(["%02x" % byte
352 for byte in self.bytes])
353 result += '"]'
354 return result
355
357 """Return RAW value representation"""
358 return ''.join([pack('>b', byte) for byte in self.bytes])
359
361 """String representation"""
362 return "Property(%s,Bytes:%s)" % (self.name, self.bytes)
363
365 """Get bytes, returns a byte"""
366 return self.bytes[index]
367
369 """Get strings count"""
370 return len(self.bytes)
371
373 """Check node equality
374 check properties are the same (same values)
375 """
376 if not FdtProperty.__eq__(self, node):
377 return False
378 if self.__len__() != len(node):
379 return False
380 for index in range(self.__len__()):
381 if self.bytes[index] != node[index]:
382 return False
383 return True
384
387 """Nop child representation"""
388
390 """Init with nothing"""
391
393 """Return name"""
394 return None
395
397 """String representation"""
398 return ''
399
401 """Get dts string representation"""
402 return INDENT*depth+'// [NOP]'
403
405 """Get blob representation"""
406
407 pos += 4
408 return (pack('>I', FDT_NOP), string_store, pos)
409
412 """Node representation"""
413
414 @staticmethod
416 """Checks the name validity"""
417 return not any([True for char in name
418 if char not in string.printable])
419
421 """Init node with name"""
422 self.name = name
423 self.subdata = []
424 self.parent = None
425 if not FdtNode.__validate_dt_name(self.name):
426 raise Exception("Invalid name '%s'" % self.name)
427
429 """Get property name"""
430 return self.name
431
433 """Checks if name is not in a subnode"""
434 for data in self.subdata:
435 if not isinstance(data, FdtNop) \
436 and data.get_name() == name:
437 return True
438 return False
439
441 """Add child, deprecated use append()"""
442 self.append(node)
443
447
449 """Set parent node, None and FdtNode accepted"""
450 if node is not None and \
451 not isinstance(node, FdtNode):
452 raise Exception("Invalid object type")
453 self.parent = node
454
456 """Get parent node"""
457 return self.parent
458
460 """String representation"""
461 return "Node(%s)" % self.name
462
464 """Get dts string representation"""
465 result = ('\n').join([sub.dts_represent(depth+1)
466 for sub in self.subdata])
467 if len(result) > 0:
468 result += '\n'
469 return INDENT*depth + self.name + ' {\n' + \
470 result + INDENT*depth + "};"
471
473 """Get blob representation
474 Pass string storage as strings_store, pos for current node start
475 and version as current dtb version
476 """
477
478 strings = strings_store
479 if self.get_name() == '/':
480 blob = pack('>II', FDT_BEGIN_NODE, 0)
481 else:
482 blob = pack('>I', FDT_BEGIN_NODE)
483 blob += self.get_name() + '\0'
484 if len(blob) % 4:
485 blob += '\0'*(4-(len(blob) % 4))
486 pos += len(blob)
487 for sub in self.subdata:
488 (data, strings, pos) = sub.dtb_represent(strings, pos, version)
489 blob += data
490 pos += 4
491 blob += pack('>I', FDT_END_NODE)
492 return (blob, strings, pos)
493
495 """Get dts string representation"""
496 result = (',\n'+ \
497 INDENT*(depth+1)).join([sub.json_represent(depth+1)
498 for sub in self.subdata
499 if not isinstance(sub, FdtNop)])
500 if len(result) > 0:
501 result = INDENT + result + '\n'+INDENT*depth
502 if self.get_name() == '/':
503 return "{\n" + INDENT*(depth) + result + "}"
504 else:
505 return json.dumps(self.name) + ': {\n' + \
506 INDENT*(depth) + result + "}"
507
509 """Get subnodes, returns either a Node, a Property or a Nop"""
510 return self.subdata[index]
511
513 """Set node at index, replacing previous subnode,
514 must not be a duplicate name
515 """
516 if self.subdata[index].get_name() != subnode.get_name() and \
517 self.__check_name_duplicate(subnode.get_name()):
518 raise Exception("%s : %s subnode already exists" % \
519 (self, subnode))
520 if not isinstance(subnode, (FdtNode, FdtProperty, FdtNop)):
521 raise Exception("Invalid object type")
522 self.subdata[index] = subnode
523
525 """Get strings count"""
526 return len(self.subdata)
527
529 """Check node inequality
530 i.e. is subnodes are the same, in either order
531 and properties are the same (same values)
532 The FdtNop is excluded from the check
533 """
534 return not self.__eq__(node)
535
537 """Check node equality
538 i.e. is subnodes are the same, in either order
539 and properties are the same (same values)
540 The FdtNop is excluded from the check
541 """
542 if not isinstance(node, FdtNode):
543 raise Exception("Invalid object type")
544 if self.name != node.get_name():
545 return False
546 curnames = set([subnode.get_name() for subnode in self.subdata
547 if not isinstance(subnode, FdtNop)])
548 cmpnames = set([subnode.get_name() for subnode in node
549 if not isinstance(subnode, FdtNop)])
550 if curnames != cmpnames:
551 return False
552 for subnode in [subnode for subnode in self.subdata
553 if not isinstance(subnode, FdtNop)]:
554 index = node.index(subnode.get_name())
555 if subnode != node[index]:
556 return False
557 return True
558
560 """Append subnode, same as add_subnode"""
561 if self.__check_name_duplicate(subnode.get_name()):
562 raise Exception("%s : %s subnode already exists" % \
563 (self, subnode))
564 if not isinstance(subnode, (FdtNode, FdtProperty, FdtNop)):
565 raise Exception("Invalid object type")
566 self.subdata.append(subnode)
567
568 - def pop(self, index=-1):
569 """Remove and returns subnode at index, default the last"""
570 return self.subdata.pop(index)
571
572 - def insert(self, index, subnode):
573 """Insert subnode before index, must not be a duplicate name"""
574 if self.__check_name_duplicate(subnode.get_name()):
575 raise Exception("%s : %s subnode already exists" % \
576 (self, subnode))
577 if not isinstance(subnode, (FdtNode, FdtProperty, FdtNop)):
578 raise Exception("Invalid object type")
579 self.subdata.insert(index, subnode)
580
582 """Find name in subnodes"""
583 for i in range(0, len(self.subdata)):
584 if not isinstance(self.subdata[i], FdtNop) and \
585 name == self.subdata[i].get_name():
586 return i
587 return None
588
590 """Remove subnode with the name
591 Raises ValueError is not present
592 """
593 index = self._find(name)
594 if index is None:
595 raise ValueError("Not present")
596 return self.subdata.pop(index)
597
599 """Returns position of subnode with the name
600 Raises ValueError is not present
601 """
602 index = self._find(name)
603 if index is None:
604 raise ValueError("Not present")
605 return index
606
608 """Merge two nodes and subnodes
609 Replace current properties with the given properties
610 """
611 if not isinstance(node, FdtNode):
612 raise Exception("Can only merge with a FdtNode")
613 for subnode in [obj for obj in node
614 if isinstance(obj, (FdtNode, FdtProperty))]:
615 index = self._find(subnode.get_name())
616 if index is None:
617 dup = deepcopy(subnode)
618 if isinstance(subnode, FdtNode):
619 dup.set_parent_node(self)
620 self.append(dup)
621 elif isinstance(subnode, FdtNode):
622 self.subdata[index].merge(subnode)
623 else:
624 self.subdata[index] = copy(subnode)
625
627 """Walk into subnodes and yield paths and objects
628 Returns set with (path string, node object)
629 """
630 node = self
631 start = 0
632 hist = []
633 curpath = []
634
635 while True:
636 for index in range(start, len(node)):
637 if isinstance(node[index], (FdtNode, FdtProperty)):
638 yield ('/' + '/'.join(curpath+[node[index].get_name()]),
639 node[index])
640 if isinstance(node[index], FdtNode):
641 if len(node[index]):
642 hist.append((node, index+1))
643 curpath.append(node[index].get_name())
644 node = node[index]
645 start = 0
646 index = -1
647 break
648 if index >= 0:
649 if len(hist):
650 (node, start) = hist.pop()
651 curpath.pop()
652 else:
653 break
654
655
656 -class Fdt(object):
657 """Flattened Device Tree representation"""
658
659 - def __init__(self, version=17, last_comp_version=16, boot_cpuid_phys=0):
660 """Init FDT object with version and boot values"""
661 self.header = {'magic': FDT_MAGIC,
662 'totalsize': 0,
663 'off_dt_struct': 0,
664 'off_dt_strings': 0,
665 'off_mem_rsvmap': 0,
666 'version': version,
667 'last_comp_version': last_comp_version,
668 'boot_cpuid_phys': boot_cpuid_phys,
669 'size_dt_strings': 0,
670 'size_dt_struct': 0}
671 self.rootnode = None
672 self.prenops = None
673 self.postnops = None
674 self.reserve_entries = None
675
676 - def add_rootnode(self, rootnode, prenops=None, postnops=None):
677 """Add root node"""
678 self.rootnode = rootnode
679 self.prenops = prenops
680 self.postnops = postnops
681
683 """Get root node"""
684 return self.rootnode
685
687 """Add reserved entries as list of dict with
688 'address' and 'size' keys"""
689 self.reserve_entries = reserve_entries
690
692 """Export to DTS representation in string format"""
693 result = "/dts-v1/;\n"
694 result += "// version:\t\t%d\n" % self.header['version']
695 result += "// last_comp_version:\t%d\n" % \
696 self.header['last_comp_version']
697 if self.header['version'] >= 2:
698 result += "// boot_cpuid_phys:\t0x%x\n" % \
699 self.header['boot_cpuid_phys']
700 result += '\n'
701 if self.reserve_entries is not None:
702 for entry in self.reserve_entries:
703 result += "/memreserve/ "
704 if entry['address']:
705 result += "%#x " % entry['address']
706 else:
707 result += "0 "
708 if entry['size']:
709 result += "%#x" % entry['size']
710 else:
711 result += "0"
712 result += ";\n"
713 if self.prenops:
714 result += '\n'.join([nop.dts_represent() for nop in self.prenops])
715 result += '\n'
716 if self.rootnode is not None:
717 result += self.rootnode.dts_represent()
718 if self.postnops:
719 result += '\n'
720 result += '\n'.join([nop.dts_represent() for nop in self.postnops])
721 return result
722
724 """Export to Blob format"""
725 if self.rootnode is None:
726 return None
727 blob_reserve_entries = ''
728 if self.reserve_entries is not None:
729 for entry in self.reserve_entries:
730 blob_reserve_entries += pack('>QQ',
731 entry['address'],
732 entry['size'])
733 blob_reserve_entries += pack('>QQ', 0, 0)
734 header_size = 7 * 4
735 if self.header['version'] >= 2:
736 header_size += 4
737 if self.header['version'] >= 3:
738 header_size += 4
739 if self.header['version'] >= 17:
740 header_size += 4
741 header_adjust = ''
742 if header_size % 8 != 0:
743 header_adjust = '\0'*(8 - (header_size % 8))
744 header_size += len(header_adjust)
745 dt_start = header_size + len(blob_reserve_entries)
746
747 (blob_dt, blob_strings, dt_pos) = \
748 self.rootnode.dtb_represent('', dt_start, self.header['version'])
749 if self.prenops is not None:
750 blob_dt = ''.join([nop.dtb_represent('')[0]
751 for nop in self.prenops])\
752 + blob_dt
753 if self.postnops is not None:
754 blob_dt += ''.join([nop.dtb_represent('')[0]
755 for nop in self.postnops])
756 blob_dt += pack('>I', FDT_END)
757 self.header['size_dt_strings'] = len(blob_strings)
758 self.header['size_dt_struct'] = len(blob_dt)
759 self.header['off_mem_rsvmap'] = header_size
760 self.header['off_dt_struct'] = dt_start
761 self.header['off_dt_strings'] = dt_start + len(blob_dt)
762 self.header['totalsize'] = dt_start + len(blob_dt) + len(blob_strings)
763 blob_header = pack('>IIIIIII', self.header['magic'],
764 self.header['totalsize'],
765 self.header['off_dt_struct'],
766 self.header['off_dt_strings'],
767 self.header['off_mem_rsvmap'],
768 self.header['version'],
769 self.header['last_comp_version'])
770 if self.header['version'] >= 2:
771 blob_header += pack('>I', self.header['boot_cpuid_phys'])
772 if self.header['version'] >= 3:
773 blob_header += pack('>I', self.header['size_dt_strings'])
774 if self.header['version'] >= 17:
775 blob_header += pack('>I', self.header['size_dt_struct'])
776 return blob_header + header_adjust + blob_reserve_entries + blob_dt + blob_strings
777
779 """Ouput JSON"""
780 if self.rootnode is None:
781 return None
782 return self.rootnode.json_represent()
783
785 """Resolve path like /memory/reg and return either a FdtNode,
786 a FdtProperty or None"""
787 if self.rootnode is None:
788 return None
789 if not path.startswith('/'):
790 return None
791 if len(path) > 1 and path.endswith('/'):
792 path = path[:-1]
793 if path == '/':
794 return self.rootnode
795 curnode = self.rootnode
796 for subpath in path[1:].split('/'):
797 found = None
798 if not isinstance(curnode, FdtNode):
799 return None
800 for node in curnode:
801 if subpath == node.get_name():
802 found = node
803 break
804 if found is None:
805 return None
806 curnode = found
807 return curnode
808
810 """Populate FdtNode with JSON dict items"""
811 for (key, value) in subjson.items():
812 if isinstance(value, dict):
813 subnode = FdtNode(key.encode('ascii'))
814 subnode.set_parent_node(node)
815 node.append(subnode)
816 _add_json_to_fdtnode(subnode, value)
817 elif isinstance(value, list):
818 if len(value) < 2:
819 raise Exception("Invalid list for %s" % key)
820 if value[0] == "words":
821 words = [int(word, 16) for word in value[1:]]
822 node.append(FdtPropertyWords(key.encode('ascii'), words))
823 elif value[0] == "bytes":
824 bytez = [int(byte, 16) for byte in value[1:]]
825 node.append(FdtPropertyBytes(key.encode('ascii'), bytez))
826 elif value[0] == "strings":
827 node.append(FdtPropertyStrings(key.encode('ascii'), \
828 [s.encode('ascii') for s in value[1:]]))
829 else:
830 raise Exception("Invalid list for %s" % key)
831 elif value is None:
832 node.append(FdtProperty(key.encode('ascii')))
833 else:
834 raise Exception("Invalid value for %s" % key)
835
837 """Import FDT from JSON representation, see JSONDeviceTree.md for
838 structure and encoding
839 Returns an Fdt object
840 """
841 tree = json.loads(buf)
842
843 root = FdtNode('/')
844
845 _add_json_to_fdtnode(root, tree)
846
847 fdt = Fdt()
848 fdt.add_rootnode(root)
849 return fdt
850
852 """Parse device tree filesystem and return a Fdt instance
853 Should be /proc/device-tree on a device, or the fusemount.py
854 mount point.
855 """
856 root = FdtNode("/")
857
858 if path.endswith('/'):
859 path = path[:-1]
860
861 nodes = {path: root}
862
863 for subpath, subdirs, files in os.walk(path):
864 if subpath not in nodes.keys():
865 raise Exception("os.walk error")
866 cur = nodes[subpath]
867 for f in files:
868 with open(subpath+'/'+f, 'r') as content_file:
869 content = content_file.read()
870 prop = FdtProperty.new_raw_property(f, content)
871 cur.add_subnode(prop)
872 for subdir in subdirs:
873 subnode = FdtNode(subdir)
874 cur.add_subnode(subnode)
875 subnode.set_parent_node(cur)
876 nodes[subpath+'/'+subdir] = subnode
877
878 fdt = Fdt()
879 fdt.add_rootnode(root)
880 return fdt
881
883 """Parse from file input"""
884
885 __fdt_header_format = ">IIIIIII"
886 __fdt_header_names = ('magic', 'totalsize', 'off_dt_struct',
887 'off_dt_strings', 'off_mem_rsvmap', 'version',
888 'last_comp_version')
889
890 __fdt_reserve_entry_format = ">QQ"
891 __fdt_reserve_entry_names = ('address', 'size')
892
893 __fdt_dt_cell_format = ">I"
894 __fdt_dt_prop_format = ">II"
895 __fdt_dt_tag_name = {FDT_BEGIN_NODE: 'node_begin',
896 FDT_END_NODE: 'node_end',
897 FDT_PROP: 'prop',
898 FDT_NOP: 'nop',
899 FDT_END: 'end'}
900
902 """Extract DTB header"""
903 header = Struct(self.__fdt_header_format)
904 header_entry = Struct(">I")
905 data = self.infile.read(header.size)
906 result = dict(zip(self.__fdt_header_names, header.unpack_from(data)))
907 if result['version'] >= 2:
908 data = self.infile.read(header_entry.size)
909 result['boot_cpuid_phys'] = header_entry.unpack_from(data)[0]
910 if result['version'] >= 3:
911 data = self.infile.read(header_entry.size)
912 result['size_dt_strings'] = header_entry.unpack_from(data)[0]
913 if result['version'] >= 17:
914 data = self.infile.read(header_entry.size)
915 result['size_dt_struct'] = header_entry.unpack_from(data)[0]
916 return result
917
919 """Extract reserved memory entries"""
920 header = Struct(self.__fdt_reserve_entry_format)
921 entries = []
922 self.infile.seek(self.fdt_header['off_mem_rsvmap'])
923 while True:
924 data = self.infile.read(header.size)
925 result = dict(zip(self.__fdt_reserve_entry_names,
926 header.unpack_from(data)))
927 if result['address'] == 0 and result['size'] == 0:
928 return entries
929 entries.append(result)
930
932 """Extract node name"""
933 data = ''
934 pos = self.infile.tell()
935 while True:
936 byte = self.infile.read(1)
937 if ord(byte) == 0:
938 break
939 data += byte
940 align_pos = pos + len(data) + 1
941 align_pos = (((align_pos) + ((4) - 1)) & ~((4) - 1))
942 self.infile.seek(align_pos)
943 return data
944
946 """Extract string from string pool"""
947 data = ''
948 pos = self.infile.tell()
949 self.infile.seek(self.fdt_header['off_dt_strings']+prop_string_pos)
950 while True:
951 byte = self.infile.read(1)
952 if ord(byte) == 0:
953 break
954 data += byte
955 self.infile.seek(pos)
956 return data
957
959 """Extract property"""
960 prop = Struct(self.__fdt_dt_prop_format)
961 pos = self.infile.tell()
962 data = self.infile.read(prop.size)
963 (prop_size, prop_string_pos,) = prop.unpack_from(data)
964
965 prop_start = pos + prop.size
966 if self.fdt_header['version'] < 16 and prop_size >= 8:
967 prop_start = (((prop_start) + ((8) - 1)) & ~((8) - 1))
968
969 self.infile.seek(prop_start)
970 value = self.infile.read(prop_size)
971
972 align_pos = self.infile.tell()
973 align_pos = (((align_pos) + ((4) - 1)) & ~((4) - 1))
974 self.infile.seek(align_pos)
975
976 return (self.__extract_fdt_string(prop_string_pos), value)
977
979 """Extract tags"""
980 cell = Struct(self.__fdt_dt_cell_format)
981 tags = []
982 self.infile.seek(self.fdt_header['off_dt_struct'])
983 while True:
984 data = self.infile.read(cell.size)
985 if len(data) < cell.size:
986 break
987 tag, = cell.unpack_from(data)
988
989 if self.__fdt_dt_tag_name.get(tag, '') in 'node_begin':
990 name = self.__extract_fdt_nodename()
991 if len(name) == 0:
992 name = '/'
993 tags.append((tag, name))
994 elif self.__fdt_dt_tag_name.get(tag, '') in ('node_end', 'nop'):
995 tags.append((tag, ''))
996 elif self.__fdt_dt_tag_name.get(tag, '') in 'end':
997 tags.append((tag, ''))
998 break
999 elif self.__fdt_dt_tag_name.get(tag, '') in 'prop':
1000 propdata = self.__extract_fdt_prop()
1001 tags.append((tag, propdata))
1002 else:
1003 print "Unknown Tag %d" % tag
1004 return tags
1005
1007 """Init with file input"""
1008 self.infile = infile
1009 self.fdt_header = self.__extract_fdt_header()
1010 if self.fdt_header['magic'] != FDT_MAGIC:
1011 raise Exception('Invalid Magic')
1012 if self.fdt_header['version'] > FDT_MAX_VERSION:
1013 raise Exception('Invalid Version %d' % self.fdt_header['version'])
1014 if self.fdt_header['last_comp_version'] > FDT_MAX_VERSION-1:
1015 raise Exception('Invalid last compatible Version %d' %
1016 self.fdt_header['last_comp_version'])
1017 self.fdt_reserve_entries = self.__extract_fdt_reserve_entries()
1018 self.fdt_dt_tags = self.__extract_fdt_dt()
1019
1021 """Represent fdt as Node and properties structure
1022 Returns a set with the pre-node Nops, the Root Node,
1023 and the post-node Nops.
1024 """
1025 prenops = []
1026 postnops = []
1027 rootnode = None
1028 curnode = None
1029 for tag in self.fdt_dt_tags:
1030 if self.__fdt_dt_tag_name.get(tag[0], '') in 'node_begin':
1031 newnode = FdtNode(tag[1])
1032 if rootnode is None:
1033 rootnode = newnode
1034 if curnode is not None:
1035 curnode.add_subnode(newnode)
1036 newnode.set_parent_node(curnode)
1037 curnode = newnode
1038 elif self.__fdt_dt_tag_name.get(tag[0], '') in 'node_end':
1039 if curnode is not None:
1040 curnode = curnode.get_parent_node()
1041 elif self.__fdt_dt_tag_name.get(tag[0], '') in 'nop':
1042 if curnode is not None:
1043 curnode.add_subnode(FdtNop())
1044 elif rootnode is not None:
1045 postnops.append(FdtNop())
1046 else:
1047 prenops.append(FdtNop())
1048 elif self.__fdt_dt_tag_name.get(tag[0], '') in 'prop':
1049 if curnode is not None:
1050 curnode.add_raw_attribute(tag[1][0], tag[1][1])
1051 elif self.__fdt_dt_tag_name.get(tag[0], '') in 'end':
1052 continue
1053 return (prenops, rootnode, postnops)
1054
1056 """Create a fdt object
1057 Returns a Fdt object
1058 """
1059 if self.fdt_header['version'] >= 2:
1060 boot_cpuid_phys = self.fdt_header['boot_cpuid_phys']
1061 else:
1062 boot_cpuid_phys = 0
1063 fdt = Fdt(version=self.fdt_header['version'],
1064 last_comp_version=self.fdt_header['last_comp_version'],
1065 boot_cpuid_phys=boot_cpuid_phys)
1066 (prenops, rootnode, postnops) = self.__to_nodes()
1067 fdt.add_rootnode(rootnode, prenops=prenops, postnops=postnops)
1068 fdt.add_reserve_entries(self.fdt_reserve_entries)
1069 return fdt
1070