devtree: Update code
parent
8d29c537ca
commit
b684c2a307
@ -1,108 +1,224 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
import ctypes
|
||||
|
||||
FDT_MAGIC = b"\xD0\x0D\xFE\xED"
|
||||
|
||||
class fdt_header(ctypes.BigEndianStructure):
|
||||
_fields_ = [("magic", ctypes.c_uint),
|
||||
("totalsize", ctypes.c_uint),
|
||||
("off_dt_struct", ctypes.c_uint),
|
||||
("off_dt_strings", ctypes.c_uint),
|
||||
("off_mem_rsvmap", ctypes.c_uint),
|
||||
("version", ctypes.c_uint),
|
||||
("last_comp_version", ctypes.c_uint),
|
||||
("boot_cpuid_phys", ctypes.c_uint),
|
||||
("size_dt_strings", ctypes.c_uint),
|
||||
("size_dt_struct", ctypes.c_uint)]
|
||||
|
||||
class fdt_reserve_entry(ctypes.BigEndianStructure):
|
||||
_fields_ = [("address", ctypes.c_uint64),
|
||||
("size", ctypes.c_uint64)]
|
||||
|
||||
class fdt_node_header(ctypes.BigEndianStructure):
|
||||
_fields_ = [("tag", ctypes.c_uint),
|
||||
("name", ctypes.c_char * 128)]
|
||||
|
||||
class fdt_property(ctypes.BigEndianStructure):
|
||||
_fields_ = [("tag", ctypes.c_uint),
|
||||
("len", ctypes.c_uint),
|
||||
("nameoff", ctypes.c_uint),
|
||||
("data", ctypes.c_char)]
|
||||
|
||||
FDT_TAGSIZE = 4
|
||||
|
||||
FDT_BEGIN_NODE = 0x1 # Start node: full name
|
||||
FDT_END_NODE = 0x2 # End node
|
||||
FDT_PROP = 0x3 # Property: name off, size, content
|
||||
FDT_NOP = 0x4 # nop
|
||||
FDT_END = 0x9
|
||||
|
||||
FDT_V1_SIZE = 7 * 4
|
||||
FDT_V2_SIZE = FDT_V1_SIZE + 4
|
||||
FDT_V3_SIZE = FDT_V2_SIZE + 4
|
||||
FDT_V16_SIZE = FDT_V3_SIZE
|
||||
FDT_V17_SIZE = FDT_V16_SIZE + 4
|
||||
|
||||
|
||||
def get_dtb_totalsize(img, pos = 0, check = True):
|
||||
if img[pos:pos+4] != FDT_MAGIC:
|
||||
return -1
|
||||
hdrsize = ctypes.sizeof(fdt_header)
|
||||
dt = fdt_header.from_buffer_copy(img[pos:pos+hdrsize])
|
||||
if not check and dt.totalsize > hdrsize + 128:
|
||||
return dt.totalsize
|
||||
if dt.totalsize > hdrsize + 128:
|
||||
if dt.off_dt_struct > hdrsize and dt.off_dt_struct < dt.totalsize:
|
||||
if dt.off_dt_strings > hdrsize and dt.off_dt_strings < dt.totalsize:
|
||||
if dt.version == 17 and dt.last_comp_version == 16:
|
||||
if dt.boot_cpuid_phys == 0:
|
||||
if dt.size_dt_strings < dt.totalsize and dt.size_dt_struct < dt.totalsize:
|
||||
return dt.totalsize
|
||||
return -1
|
||||
|
||||
def find_dtb(img, pos=0, maxsize = 256000):
|
||||
while True:
|
||||
k = img.find(FDT_MAGIC + b"\x00", pos)
|
||||
if k < 0:
|
||||
break
|
||||
pos = k + 4
|
||||
totalsize = get_dtb_totalsize(img, k, check = True)
|
||||
if totalsize > 0 and totalsize <= maxsize:
|
||||
return k, totalsize
|
||||
return None, None
|
||||
|
||||
def get_dtb(img, pos=0):
|
||||
pos, size = find_dtb(img, pos)
|
||||
return img[pos:pos+size] if pos is not None else None
|
||||
|
||||
def get_dtb_part_info(dtb, part_name):
|
||||
k = dtb.find(b'fixed-partitions\x00')
|
||||
if k <= 0:
|
||||
return None
|
||||
while True:
|
||||
k = dtb.find(b"partition@", k)
|
||||
if k < 0:
|
||||
break
|
||||
k = dtb.find(b"\x00", k) + 1
|
||||
k = (k + 3) & 0xFFFFFFFC
|
||||
k += 12
|
||||
n = dtb.find(b"\x00", k)
|
||||
name = dtb[k:n]
|
||||
name_len = len(name)
|
||||
name = name.decode('latin_1')
|
||||
if name != part_name:
|
||||
continue
|
||||
k += name_len + 1
|
||||
k = (k + 3) & 0xFFFFFFFC
|
||||
k += 12
|
||||
addr = int.from_bytes(dtb[k:k+4], byteorder='big')
|
||||
size = int.from_bytes(dtb[k+4:k+8], byteorder='big')
|
||||
return {'addr': addr, 'size': size, 'name': name}
|
||||
return None
|
||||
|
||||
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
import ctypes
|
||||
|
||||
FDT_MAGIC = b"\xD0\x0D\xFE\xED"
|
||||
|
||||
class fdt_header(ctypes.BigEndianStructure):
|
||||
_fields_ = [("magic", ctypes.c_uint),
|
||||
("totalsize", ctypes.c_uint),
|
||||
("off_dt_struct", ctypes.c_uint),
|
||||
("off_dt_strings", ctypes.c_uint),
|
||||
("off_mem_rsvmap", ctypes.c_uint),
|
||||
("version", ctypes.c_uint),
|
||||
("last_comp_version", ctypes.c_uint),
|
||||
("boot_cpuid_phys", ctypes.c_uint),
|
||||
("size_dt_strings", ctypes.c_uint),
|
||||
("size_dt_struct", ctypes.c_uint)]
|
||||
|
||||
class fdt_reserve_entry(ctypes.BigEndianStructure):
|
||||
_fields_ = [("address", ctypes.c_uint64),
|
||||
("size", ctypes.c_uint64)]
|
||||
|
||||
class fdt_node_header(ctypes.BigEndianStructure):
|
||||
_fields_ = [("tag", ctypes.c_uint),
|
||||
("name", ctypes.c_char * 128)]
|
||||
|
||||
class fdt_property(ctypes.BigEndianStructure):
|
||||
_fields_ = [("tag", ctypes.c_uint),
|
||||
("size", ctypes.c_uint),
|
||||
("nameoff", ctypes.c_uint),
|
||||
("data", ctypes.c_char)]
|
||||
|
||||
FDT_TAGSIZE = 4
|
||||
|
||||
FDT_BEGIN_NODE = 1 # Start node: full name
|
||||
FDT_END_NODE = 2 # End node
|
||||
FDT_PROP = 3 # Property: name off, size, content
|
||||
FDT_NOP = 4
|
||||
FDT_END = 9
|
||||
|
||||
FDT_V1_SIZE = 7 * 4
|
||||
FDT_V2_SIZE = FDT_V1_SIZE + 4
|
||||
FDT_V3_SIZE = FDT_V2_SIZE + 4
|
||||
FDT_V16_SIZE = FDT_V3_SIZE
|
||||
FDT_V17_SIZE = FDT_V16_SIZE + 4
|
||||
|
||||
|
||||
def get_dtb_totalsize(img, pos = 0, check = True):
|
||||
if img[pos:pos+4] != FDT_MAGIC:
|
||||
return -1
|
||||
hdrsize = ctypes.sizeof(fdt_header)
|
||||
dt = fdt_header.from_buffer_copy(img[pos:pos+hdrsize])
|
||||
if not check and dt.totalsize > hdrsize + 128:
|
||||
return dt.totalsize
|
||||
if dt.totalsize > hdrsize + 128:
|
||||
if dt.off_dt_struct > hdrsize and dt.off_dt_struct < dt.totalsize:
|
||||
if dt.off_dt_strings > hdrsize and dt.off_dt_strings < dt.totalsize:
|
||||
if dt.version == 17 and dt.last_comp_version == 16:
|
||||
if dt.boot_cpuid_phys == 0:
|
||||
if dt.size_dt_strings < dt.totalsize and dt.size_dt_struct < dt.totalsize:
|
||||
return dt.totalsize
|
||||
return -1
|
||||
|
||||
def find_dtb(img, pos = 0, maxsize = 256000):
|
||||
while True:
|
||||
k = img.find(FDT_MAGIC, pos)
|
||||
if k < 0:
|
||||
break
|
||||
pos = k + 4
|
||||
totalsize = get_dtb_totalsize(img, k, check = True)
|
||||
if maxsize and totalsize > maxsize:
|
||||
continue
|
||||
if totalsize > 0:
|
||||
return k, totalsize
|
||||
return None, None
|
||||
|
||||
def get_dtb(img, pos = 0, maxsize = 256000):
|
||||
pos, size = find_dtb(img, pos, maxsize)
|
||||
return img[pos:pos+size] if pos is not None else None
|
||||
|
||||
def get_dtb_part_info(dtb, part_name):
|
||||
k = dtb.find(b'fixed-partitions\x00')
|
||||
if k <= 0:
|
||||
return None
|
||||
while True:
|
||||
k = dtb.find(b"partition@", k)
|
||||
if k < 0:
|
||||
break
|
||||
k = dtb.find(b"\x00", k) + 1
|
||||
k = (k + 3) & 0xFFFFFFFC
|
||||
k += 12
|
||||
n = dtb.find(b"\x00", k)
|
||||
name = dtb[k:n]
|
||||
name_len = len(name)
|
||||
name = name.decode('latin_1')
|
||||
if name != part_name:
|
||||
continue
|
||||
k += name_len + 1
|
||||
k = (k + 3) & 0xFFFFFFFC
|
||||
k += 12
|
||||
addr = int.from_bytes(dtb[k:k+4], byteorder='big')
|
||||
size = int.from_bytes(dtb[k+4:k+8], byteorder='big')
|
||||
return {'addr': addr, 'size': size, 'name': name}
|
||||
return None
|
||||
|
||||
def get_fdt_string(img, offset, hdr = None):
|
||||
if not hdr:
|
||||
hdr = fdt_header.from_buffer_copy(img[:ctypes.sizeof(fdt_header)])
|
||||
offset = hdr.off_dt_strings + offset
|
||||
pos = offset
|
||||
while True:
|
||||
if img[pos:pos+1] == b'\x00':
|
||||
break
|
||||
pos += 1
|
||||
return img[offset:pos].decode()
|
||||
|
||||
def roundup4(value):
|
||||
return (value + 3) & 0xFFFFFFFC
|
||||
|
||||
def enum_fdt_nodes(img, hdr, pos, target_path, target_name, res, path = None):
|
||||
while True:
|
||||
tag = int.from_bytes(img[pos:pos+4], byteorder = 'big')
|
||||
if tag == FDT_BEGIN_NODE:
|
||||
node = fdt_node_header.from_buffer_copy( img[ pos:pos+ctypes.sizeof(fdt_node_header) ] )
|
||||
if path is None:
|
||||
if node.name:
|
||||
raise RuntimeError(f'Incorrect FDT root name = {node.name}')
|
||||
path = [ ]
|
||||
else:
|
||||
path.append(node.name.decode())
|
||||
if not target_name:
|
||||
print('/' + '/'.join(path))
|
||||
pos += 4 + roundup4(len(node.name) + 1)
|
||||
pos = enum_fdt_nodes(img, hdr, pos, target_path, target_name, res, path)
|
||||
if pos == 0:
|
||||
return 0 # EOF
|
||||
continue
|
||||
if tag == FDT_PROP:
|
||||
prop = fdt_property.from_buffer_copy( img[ pos:pos+ctypes.sizeof(fdt_property) ] )
|
||||
name = get_fdt_string(img, prop.nameoff, hdr)
|
||||
pos += 12
|
||||
if not target_name:
|
||||
if prop.size <= 30:
|
||||
data = img[pos:pos+prop.size]
|
||||
print(f' {name} = {data}')
|
||||
else:
|
||||
data = img[pos:pos+30]
|
||||
print(f' {name} = [len:{prop.size}] {data}')
|
||||
elif name == target_name and len(path) == len(target_path):
|
||||
kk = 0
|
||||
for i, dn in enumerate(path):
|
||||
if target_path[i].endswith('*'):
|
||||
if not dn.startswith(target_path[i][:-1]):
|
||||
break
|
||||
elif dn != target_path[i]:
|
||||
break
|
||||
kk += 1
|
||||
if kk == len(path):
|
||||
res.append(img[pos:pos+prop.size])
|
||||
return 0 # EOF
|
||||
pos += roundup4(prop.size)
|
||||
continue
|
||||
if tag == FDT_NOP:
|
||||
pos += 4
|
||||
continue
|
||||
if tag == FDT_END_NODE:
|
||||
if path:
|
||||
path.pop()
|
||||
pos += 4
|
||||
return pos
|
||||
if tag == FDT_END:
|
||||
return 0 # EOF
|
||||
raise RuntimeError(f'Incorrect FDT tag id = 0x{tag:X}')
|
||||
|
||||
def get_fdt_prop(img, target_path = None, target_name = None):
|
||||
hdr = fdt_header.from_buffer_copy( img[0:ctypes.sizeof(fdt_header) ] )
|
||||
#print(f'MAGIC = 0x{hdr.magic:X}')
|
||||
#print(f'off_dt_strings = 0x{hdr.off_dt_strings:X}')
|
||||
#print(f'size_dt_strings = 0x{hdr.size_dt_strings:X}')
|
||||
pos = ctypes.sizeof(fdt_header) + ctypes.sizeof(fdt_reserve_entry)
|
||||
node = fdt_node_header.from_buffer_copy( img[ pos:pos+ctypes.sizeof(fdt_node_header) ] )
|
||||
if node.tag != FDT_BEGIN_NODE or node.name:
|
||||
return None
|
||||
if target_path and isinstance(target_path, str):
|
||||
target_path = target_path.strip('/')
|
||||
target_path = target_path.split('/')
|
||||
if not target_path[0]:
|
||||
target_path = [ ]
|
||||
if not target_path:
|
||||
target_path = [ ]
|
||||
res = [ ]
|
||||
enum_fdt_nodes(img, hdr, pos, target_path, target_name, res)
|
||||
return res[0] if res else None
|
||||
|
||||
if __name__ == "__main__":
|
||||
img_fn = None
|
||||
if len(sys.argv) > 1:
|
||||
img_fn = sys.argv[1]
|
||||
|
||||
if not img_fn or not os.path.exists(img_fn):
|
||||
print(f'ERROR: file "{img_fn}" not found!')
|
||||
sys.exit(1)
|
||||
|
||||
with open(img_fn, 'rb') as file:
|
||||
image = file.read()
|
||||
|
||||
fdt = get_dtb(image, maxsize = None)
|
||||
if not fdt:
|
||||
print(f'ERROR: file "{img_fn}" not contain FDT image!')
|
||||
sys.exit(1)
|
||||
|
||||
target_path = '/images/kernel*/'
|
||||
#target_name = 'os'
|
||||
target_name = None
|
||||
prop = get_fdt_prop(fdt, target_path, target_name)
|
||||
if target_name:
|
||||
print(f'RESULT: {target_path}{target_name} = {prop}')
|
||||
|
||||
print('==== Finish ====')
|
||||
|
||||
|
Loading…
Reference in New Issue