Package pyfdt :: Module pyfdt
[hide private]
[frames] | no frames]

Source Code for Module pyfdt.pyfdt

   1  # -*- coding: utf-8 -*- 
   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 
38 39 40 -class FdtProperty(object):
41 """ Represents an empty property""" 42 43 @staticmethod
44 - def __validate_dt_name(name):
45 """Checks the name validity""" 46 return not any([True for char in name 47 if char not in string.printable])
48
49 - def __init__(self, name):
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
55 - def get_name(self):
56 """Get property name""" 57 return self.name
58
59 - def __str__(self):
60 """String representation""" 61 return "Property(%s)" % self.name
62
63 - def dts_represent(self, depth=0):
64 """Get dts string representation""" 65 return INDENT*depth + self.name + ';'
66
67 - def dtb_represent(self, string_store, pos=0, version=17):
68 """Get blob representation""" 69 # print "%x:%s" % (pos, self) 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
78 - def json_represent(self, depth=0):
79 """Ouput JSON""" 80 return '%s: null' % json.dumps(self.name)
81
82 - def to_raw(self):
83 """Return RAW value representation""" 84 return ''
85
86 - def __getitem__(self, value):
87 """Returns No Items""" 88 return None
89
90 - def __ne__(self, node):
91 """Check property inequality 92 """ 93 return not self.__eq__(node)
94
95 - def __eq__(self, node):
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
106 - def __check_prop_strings(value):
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
134 - def new_raw_property(name, raw_value):
135 """Instantiate property with raw value type""" 136 if FdtProperty.__check_prop_strings(raw_value): 137 return FdtPropertyStrings.init_raw(name, raw_value) 138 elif len(raw_value) and len(raw_value) % 4 == 0: 139 return FdtPropertyWords.init_raw(name, raw_value) 140 elif len(raw_value) and len(raw_value): 141 return FdtPropertyBytes.init_raw(name, raw_value) 142 else: 143 return FdtProperty(name)
144
145 146 -class FdtPropertyStrings(FdtProperty):
147 """Property with strings as value""" 148 149 @classmethod
150 - def __extract_prop_strings(cls, value):
151 """Extract strings from raw_value""" 152 return [st for st in value.split('\0') if len(st)]
153
154 - def __init__(self, name, strings):
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
169 - def init_raw(cls, name, raw_value):
170 """Init from raw""" 171 return cls(name, cls.__extract_prop_strings(raw_value))
172
173 - def dts_represent(self, depth=0):
174 """Get dts string representation""" 175 return INDENT*depth + self.name + ' = "' + \ 176 '", "'.join(self.strings) + '";'
177
178 - def dtb_represent(self, string_store, pos=0, version=17):
179 """Get blob representation""" 180 # print "%x:%s" % (pos, self) 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
197 - def json_represent(self, depth=0):
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
204 - def to_raw(self):
205 """Return RAW value representation""" 206 return ''.join([chars+'\0' for chars in self.strings])
207
208 - def __str__(self):
209 """String representation""" 210 return "Property(%s,Strings:%s)" % (self.name, self.strings)
211
212 - def __getitem__(self, index):
213 """Get strings, returns a string""" 214 return self.strings[index]
215
216 - def __len__(self):
217 """Get strings count""" 218 return len(self.strings)
219
220 - def __eq__(self, node):
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
233 -class FdtPropertyWords(FdtProperty):
234 """Property with words as value""" 235
236 - def __init__(self, name, words):
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
247 - def init_raw(cls, name, raw_value):
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
256 - def dts_represent(self, depth=0):
257 """Get dts string representation""" 258 return INDENT*depth + self.name + ' = <' + \ 259 ' '.join(["0x%08x" % word for word in self.words]) + ">;"
260
261 - def dtb_represent(self, string_store, pos=0, version=17):
262 """Get blob representation""" 263 # # print "%x:%s" % (pos, self) 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
273 - def json_represent(self, depth=0):
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
280 - def to_raw(self):
281 """Return RAW value representation""" 282 return ''.join([pack('>I', word) for word in self.words])
283
284 - def __str__(self):
285 """String representation""" 286 return "Property(%s,Words:%s)" % (self.name, self.words)
287
288 - def __getitem__(self, index):
289 """Get words, returns a word integer""" 290 return self.words[index]
291
292 - def __len__(self):
293 """Get words count""" 294 return len(self.words)
295
296 - def __eq__(self, node):
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
309 310 -class FdtPropertyBytes(FdtProperty):
311 """Property with signed bytes as value""" 312
313 - def __init__(self, name, bytez):
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
324 - def init_raw(cls, name, raw_value):
325 """Init from raw""" 326 return cls(name, [unpack('b', byte)[0] for byte in raw_value])
327
328 - def dts_represent(self, depth=0):
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
334 - def dtb_represent(self, string_store, pos=0, version=17):
335 """Get blob representation""" 336 # print "%x:%s" % (pos, self) 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
348 - def json_represent(self, depth=0):
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
356 - def to_raw(self):
357 """Return RAW value representation""" 358 return ''.join([pack('>b', byte) for byte in self.bytes])
359
360 - def __str__(self):
361 """String representation""" 362 return "Property(%s,Bytes:%s)" % (self.name, self.bytes)
363
364 - def __getitem__(self, index):
365 """Get bytes, returns a byte""" 366 return self.bytes[index]
367
368 - def __len__(self):
369 """Get strings count""" 370 return len(self.bytes)
371
372 - def __eq__(self, node):
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
385 386 -class FdtNop(object): # pylint: disable-msg=R0903
387 """Nop child representation""" 388
389 - def __init__(self):
390 """Init with nothing"""
391
392 - def get_name(self): # pylint: disable-msg=R0201
393 """Return name""" 394 return None 395
396 - def __str__(self):
397 """String representation""" 398 return ''
399
400 - def dts_represent(self, depth=0): # pylint: disable-msg=R0201
401 """Get dts string representation""" 402 return INDENT*depth+'// [NOP]' 403
404 - def dtb_represent(self, string_store, pos=0, version=17):
405 """Get blob representation""" 406 # print "%x:%s" % (pos, self) 407 pos += 4 408 return (pack('>I', FDT_NOP), string_store, pos)
409
410 411 -class FdtNode(object):
412 """Node representation""" 413 414 @staticmethod
415 - def __validate_dt_name(name):
416 """Checks the name validity""" 417 return not any([True for char in name 418 if char not in string.printable])
419
420 - def __init__(self, name):
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
428 - def get_name(self):
429 """Get property name""" 430 return self.name
431
432 - def __check_name_duplicate(self, name):
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
440 - def add_subnode(self, node):
441 """Add child, deprecated use append()""" 442 self.append(node)
443
444 - def add_raw_attribute(self, name, raw_value):
445 """Construct a raw attribute and add to child""" 446 self.append(FdtProperty.new_raw_property(name, raw_value))
447
448 - def set_parent_node(self, node):
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
455 - def get_parent_node(self):
456 """Get parent node""" 457 return self.parent
458
459 - def __str__(self):
460 """String representation""" 461 return "Node(%s)" % self.name
462
463 - def dts_represent(self, depth=0):
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
472 - def dtb_represent(self, strings_store, pos=0, version=17):
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 # print "%x:%s" % (pos, self) 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
494 - def json_represent(self, depth=0):
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
508 - def __getitem__(self, index):
509 """Get subnodes, returns either a Node, a Property or a Nop""" 510 return self.subdata[index]
511
512 - def __setitem__(self, index, subnode):
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
524 - def __len__(self):
525 """Get strings count""" 526 return len(self.subdata)
527
528 - def __ne__(self, node):
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
536 - def __eq__(self, node):
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
559 - def append(self, subnode):
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
581 - def _find(self, name):
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
589 - def remove(self, name):
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
598 - def index(self, name):
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
607 - def merge(self, node):
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
626 - def walk(self):
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
682 - def get_rootnode(self):
683 """Get root node""" 684 return self.rootnode
685
686 - def add_reserve_entries(self, reserve_entries):
687 """Add reserved entries as list of dict with 688 'address' and 'size' keys""" 689 self.reserve_entries = reserve_entries
690
691 - def to_dts(self):
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
723 - def to_dtb(self):
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 # print "dt_start %d" % dt_start 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
778 - def to_json(self):
779 """Ouput JSON""" 780 if self.rootnode is None: 781 return None 782 return self.rootnode.json_represent()
783
784 - def resolve_path(self, path):
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
809 -def _add_json_to_fdtnode(node, subjson):
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
836 -def FdtJsonParse(buf):
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
851 -def FdtFsParse(path):
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
882 -class FdtBlobParse(object): # pylint: disable-msg=R0903
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
901 - def __extract_fdt_header(self):
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
918 - def __extract_fdt_reserve_entries(self):
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
931 - def __extract_fdt_nodename(self):
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
945 - def __extract_fdt_string(self, prop_string_pos):
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
958 - def __extract_fdt_prop(self):
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
978 - def __extract_fdt_dt(self):
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 # print "*** %s" % self.__fdt_dt_tag_name.get(tag, '') 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
1006 - def __init__(self, infile):
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
1020 - def __to_nodes(self):
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
1055 - def to_fdt(self):
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