Add a Python version of the libfdt library which contains enough features to support the dtoc tool. This is only a very bare-bones implementation. It requires the 'swig' to build. Signed-off-by: Simon Glass <sjg@chromium.org>master
parent
dbbe2e6401
commit
76bce10d21
@ -0,0 +1,89 @@ |
|||||||
|
/* File: libfdt.i */ |
||||||
|
%module libfdt |
||||||
|
|
||||||
|
%{ |
||||||
|
#define SWIG_FILE_WITH_INIT |
||||||
|
#include "libfdt.h" |
||||||
|
%} |
||||||
|
|
||||||
|
%pythoncode %{ |
||||||
|
def Raise(errnum): |
||||||
|
raise ValueError('Error %s' % fdt_strerror(errnum)) |
||||||
|
|
||||||
|
def Name(fdt, offset): |
||||||
|
name, len = fdt_get_name(fdt, offset) |
||||||
|
return name |
||||||
|
|
||||||
|
def String(fdt, offset): |
||||||
|
offset = fdt32_to_cpu(offset) |
||||||
|
name = fdt_string(fdt, offset) |
||||||
|
return name |
||||||
|
|
||||||
|
def swap32(x): |
||||||
|
return (((x << 24) & 0xFF000000) | |
||||||
|
((x << 8) & 0x00FF0000) | |
||||||
|
((x >> 8) & 0x0000FF00) | |
||||||
|
((x >> 24) & 0x000000FF)) |
||||||
|
|
||||||
|
def fdt32_to_cpu(x): |
||||||
|
return swap32(x) |
||||||
|
|
||||||
|
def Data(prop): |
||||||
|
set_prop(prop) |
||||||
|
return get_prop_data() |
||||||
|
%} |
||||||
|
|
||||||
|
%include "typemaps.i" |
||||||
|
%include "cstring.i" |
||||||
|
|
||||||
|
%typemap(in) void* = char*; |
||||||
|
|
||||||
|
typedef int fdt32_t; |
||||||
|
|
||||||
|
struct fdt_property { |
||||||
|
fdt32_t tag; |
||||||
|
fdt32_t len; |
||||||
|
fdt32_t nameoff; |
||||||
|
char data[0]; |
||||||
|
}; |
||||||
|
|
||||||
|
/* |
||||||
|
* This is a work-around since I'm not sure of a better way to copy out the |
||||||
|
* contents of a string. This is used in dtoc/GetProps(). The intent is to |
||||||
|
* pass in a pointer to a property and access the data field at the end of |
||||||
|
* it. Ideally the Data() function above would be able to do this directly, |
||||||
|
* but I'm not sure how to do that. |
||||||
|
*/ |
||||||
|
#pragma SWIG nowarn=454 |
||||||
|
%inline %{ |
||||||
|
static struct fdt_property *cur_prop; |
||||||
|
|
||||||
|
void set_prop(struct fdt_property *prop) { |
||||||
|
cur_prop = prop; |
||||||
|
} |
||||||
|
%} |
||||||
|
|
||||||
|
%cstring_output_allocate_size(char **s, int *sz, free(*$1)); |
||||||
|
%inline %{ |
||||||
|
void get_prop_data(char **s, int *sz) { |
||||||
|
*sz = fdt32_to_cpu(cur_prop->len); |
||||||
|
*s = (char *)malloc(*sz); |
||||||
|
if (!*s) |
||||||
|
*sz = 0; |
||||||
|
else |
||||||
|
memcpy(*s, cur_prop + 1, *sz); |
||||||
|
} |
||||||
|
%} |
||||||
|
|
||||||
|
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); |
||||||
|
int fdt_path_offset(const void *fdt, const char *path); |
||||||
|
int fdt_first_property_offset(const void *fdt, int nodeoffset); |
||||||
|
int fdt_next_property_offset(const void *fdt, int offset); |
||||||
|
const char *fdt_strerror(int errval); |
||||||
|
const struct fdt_property *fdt_get_property_by_offset(const void *fdt, |
||||||
|
int offset, |
||||||
|
int *OUTPUT); |
||||||
|
const char *fdt_get_name(const void *fdt, int nodeoffset, int *OUTPUT); |
||||||
|
const char *fdt_string(const void *fdt, int stroffset); |
||||||
|
int fdt_first_subnode(const void *fdt, int offset); |
||||||
|
int fdt_next_subnode(const void *fdt, int offset); |
@ -0,0 +1,38 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
|
||||||
|
""" |
||||||
|
setup.py file for SWIG libfdt |
||||||
|
""" |
||||||
|
|
||||||
|
from distutils.core import setup, Extension |
||||||
|
import os |
||||||
|
import sys |
||||||
|
|
||||||
|
# Don't cross-compile - always use the host compiler. |
||||||
|
del os.environ['CROSS_COMPILE'] |
||||||
|
del os.environ['CC'] |
||||||
|
|
||||||
|
progname = sys.argv[0] |
||||||
|
cflags = sys.argv[1] |
||||||
|
files = sys.argv[2:] |
||||||
|
|
||||||
|
if cflags: |
||||||
|
cflags = [flag for flag in cflags.split(' ') if flag] |
||||||
|
else: |
||||||
|
cflags = None |
||||||
|
|
||||||
|
libfdt_module = Extension( |
||||||
|
'_libfdt', |
||||||
|
sources = files, |
||||||
|
extra_compile_args = cflags |
||||||
|
) |
||||||
|
|
||||||
|
sys.argv = [progname, '--quiet', 'build_ext', '--inplace'] |
||||||
|
|
||||||
|
setup (name = 'libfdt', |
||||||
|
version = '0.1', |
||||||
|
author = "SWIG Docs", |
||||||
|
description = """Simple swig libfdt from docs""", |
||||||
|
ext_modules = [libfdt_module], |
||||||
|
py_modules = ["libfdt"], |
||||||
|
) |
@ -0,0 +1,14 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
|
||||||
|
import os |
||||||
|
import sys |
||||||
|
|
||||||
|
our_path = os.path.dirname(os.path.realpath(__file__)) |
||||||
|
sys.path.append(os.path.join(our_path, '../../b/sandbox_spl/tools')) |
||||||
|
|
||||||
|
import libfdt |
||||||
|
|
||||||
|
with open('b/sandbox_spl/u-boot.dtb') as fd: |
||||||
|
fdt = fd.read() |
||||||
|
|
||||||
|
print libfdt.fdt_path_offset(fdt, "/aliases") |
@ -0,0 +1,180 @@ |
|||||||
|
#!/usr/bin/python |
||||||
|
# |
||||||
|
# Copyright (C) 2016 Google, Inc |
||||||
|
# Written by Simon Glass <sjg@chromium.org> |
||||||
|
# |
||||||
|
# SPDX-License-Identifier: GPL-2.0+ |
||||||
|
# |
||||||
|
|
||||||
|
import fdt_util |
||||||
|
import libfdt |
||||||
|
import sys |
||||||
|
|
||||||
|
# This deals with a device tree, presenting it as a list of Node and Prop |
||||||
|
# objects, representing nodes and properties, respectively. |
||||||
|
# |
||||||
|
# This implementation uses a libfdt Python library to access the device tree, |
||||||
|
# so it is fairly efficient. |
||||||
|
|
||||||
|
class Prop: |
||||||
|
"""A device tree property |
||||||
|
|
||||||
|
Properties: |
||||||
|
name: Property name (as per the device tree) |
||||||
|
value: Property value as a string of bytes, or a list of strings of |
||||||
|
bytes |
||||||
|
type: Value type |
||||||
|
""" |
||||||
|
def __init__(self, name, bytes): |
||||||
|
self.name = name |
||||||
|
self.value = None |
||||||
|
if not bytes: |
||||||
|
self.type = fdt_util.TYPE_BOOL |
||||||
|
self.value = True |
||||||
|
return |
||||||
|
self.type, self.value = fdt_util.BytesToValue(bytes) |
||||||
|
|
||||||
|
def GetPhandle(self): |
||||||
|
"""Get a (single) phandle value from a property |
||||||
|
|
||||||
|
Gets the phandle valuie from a property and returns it as an integer |
||||||
|
""" |
||||||
|
return fdt_util.fdt32_to_cpu(self.value[:4]) |
||||||
|
|
||||||
|
def Widen(self, newprop): |
||||||
|
"""Figure out which property type is more general |
||||||
|
|
||||||
|
Given a current property and a new property, this function returns the |
||||||
|
one that is less specific as to type. The less specific property will |
||||||
|
be ble to represent the data in the more specific property. This is |
||||||
|
used for things like: |
||||||
|
|
||||||
|
node1 { |
||||||
|
compatible = "fred"; |
||||||
|
value = <1>; |
||||||
|
}; |
||||||
|
node1 { |
||||||
|
compatible = "fred"; |
||||||
|
value = <1 2>; |
||||||
|
}; |
||||||
|
|
||||||
|
He we want to use an int array for 'value'. The first property |
||||||
|
suggests that a single int is enough, but the second one shows that |
||||||
|
it is not. Calling this function with these two propertes would |
||||||
|
update the current property to be like the second, since it is less |
||||||
|
specific. |
||||||
|
""" |
||||||
|
if newprop.type < self.type: |
||||||
|
self.type = newprop.type |
||||||
|
|
||||||
|
if type(newprop.value) == list and type(self.value) != list: |
||||||
|
self.value = [self.value] |
||||||
|
|
||||||
|
if type(self.value) == list and len(newprop.value) > len(self.value): |
||||||
|
val = fdt_util.GetEmpty(self.type) |
||||||
|
while len(self.value) < len(newprop.value): |
||||||
|
self.value.append(val) |
||||||
|
|
||||||
|
|
||||||
|
class Node: |
||||||
|
"""A device tree node |
||||||
|
|
||||||
|
Properties: |
||||||
|
offset: Integer offset in the device tree |
||||||
|
name: Device tree node tname |
||||||
|
path: Full path to node, along with the node name itself |
||||||
|
_fdt: Device tree object |
||||||
|
subnodes: A list of subnodes for this node, each a Node object |
||||||
|
props: A dict of properties for this node, each a Prop object. |
||||||
|
Keyed by property name |
||||||
|
""" |
||||||
|
def __init__(self, fdt, offset, name, path): |
||||||
|
self.offset = offset |
||||||
|
self.name = name |
||||||
|
self.path = path |
||||||
|
self._fdt = fdt |
||||||
|
self.subnodes = [] |
||||||
|
self.props = {} |
||||||
|
|
||||||
|
def Scan(self): |
||||||
|
"""Scan a node's properties and subnodes |
||||||
|
|
||||||
|
This fills in the props and subnodes properties, recursively |
||||||
|
searching into subnodes so that the entire tree is built. |
||||||
|
""" |
||||||
|
self.props = self._fdt.GetProps(self.path) |
||||||
|
|
||||||
|
offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.offset) |
||||||
|
while offset >= 0: |
||||||
|
sep = '' if self.path[-1] == '/' else '/' |
||||||
|
name = libfdt.Name(self._fdt.GetFdt(), offset) |
||||||
|
path = self.path + sep + name |
||||||
|
node = Node(self._fdt, offset, name, path) |
||||||
|
self.subnodes.append(node) |
||||||
|
|
||||||
|
node.Scan() |
||||||
|
offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset) |
||||||
|
|
||||||
|
|
||||||
|
class Fdt: |
||||||
|
"""Provides simple access to a flat device tree blob. |
||||||
|
|
||||||
|
Properties: |
||||||
|
fname: Filename of fdt |
||||||
|
_root: Root of device tree (a Node object) |
||||||
|
""" |
||||||
|
|
||||||
|
def __init__(self, fname): |
||||||
|
self.fname = fname |
||||||
|
with open(fname) as fd: |
||||||
|
self._fdt = fd.read() |
||||||
|
|
||||||
|
def GetFdt(self): |
||||||
|
"""Get the contents of the FDT |
||||||
|
|
||||||
|
Returns: |
||||||
|
The FDT contents as a string of bytes |
||||||
|
""" |
||||||
|
return self._fdt |
||||||
|
|
||||||
|
def Scan(self): |
||||||
|
"""Scan a device tree, building up a tree of Node objects |
||||||
|
|
||||||
|
This fills in the self._root property |
||||||
|
""" |
||||||
|
self._root = Node(self, 0, '/', '/') |
||||||
|
self._root.Scan() |
||||||
|
|
||||||
|
def GetRoot(self): |
||||||
|
"""Get the root Node of the device tree |
||||||
|
|
||||||
|
Returns: |
||||||
|
The root Node object |
||||||
|
""" |
||||||
|
return self._root |
||||||
|
|
||||||
|
def GetProps(self, node): |
||||||
|
"""Get all properties from a node. |
||||||
|
|
||||||
|
Args: |
||||||
|
node: Full path to node name to look in. |
||||||
|
|
||||||
|
Returns: |
||||||
|
A dictionary containing all the properties, indexed by node name. |
||||||
|
The entries are Prop objects. |
||||||
|
|
||||||
|
Raises: |
||||||
|
ValueError: if the node does not exist. |
||||||
|
""" |
||||||
|
offset = libfdt.fdt_path_offset(self._fdt, node) |
||||||
|
if offset < 0: |
||||||
|
libfdt.Raise(offset) |
||||||
|
props_dict = {} |
||||||
|
poffset = libfdt.fdt_first_property_offset(self._fdt, offset) |
||||||
|
while poffset >= 0: |
||||||
|
dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset) |
||||||
|
prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop)) |
||||||
|
props_dict[prop.name] = prop |
||||||
|
|
||||||
|
poffset = libfdt.fdt_next_property_offset(self._fdt, poffset) |
||||||
|
return props_dict |
Loading…
Reference in new issue