dm: Add a more efficient libfdt library
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>
This commit is contained in:
parent
dbbe2e6401
commit
76bce10d21
89
lib/libfdt/libfdt.swig
Normal file
89
lib/libfdt/libfdt.swig
Normal file
@ -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);
|
38
lib/libfdt/setup.py
Normal file
38
lib/libfdt/setup.py
Normal file
@ -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"],
|
||||
)
|
14
lib/libfdt/test_libfdt.py
Normal file
14
lib/libfdt/test_libfdt.py
Normal file
@ -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")
|
@ -28,12 +28,16 @@ __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
|
||||
# C code
|
||||
# Executables compiled from a single .c file
|
||||
host-csingle := $(foreach m,$(__hostprogs), \
|
||||
$(if $($(m)-objs)$($(m)-cxxobjs),,$(m)))
|
||||
$(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-sharedobjs),,$(m)))
|
||||
|
||||
# C executables linked based on several .o files
|
||||
host-cmulti := $(foreach m,$(__hostprogs),\
|
||||
$(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
|
||||
|
||||
# Shared object libraries
|
||||
host-shared := $(foreach m,$(__hostprogs),\
|
||||
$(if $($(m)-sharedobjs),$(m))))
|
||||
|
||||
# Object (.o) files compiled from .c files
|
||||
host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
|
||||
|
||||
@ -59,6 +63,7 @@ host-cmulti := $(addprefix $(obj)/,$(host-cmulti))
|
||||
host-cobjs := $(addprefix $(obj)/,$(host-cobjs))
|
||||
host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti))
|
||||
host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs))
|
||||
host-shared := $(addprefix $(obj)/,$(host-shared))
|
||||
host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
|
||||
|
||||
obj-dirs += $(host-objdirs)
|
||||
@ -128,4 +133,4 @@ $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
|
||||
$(call if_changed_dep,host-cxxobjs)
|
||||
|
||||
targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\
|
||||
$(host-cxxmulti) $(host-cxxobjs)
|
||||
$(host-cxxmulti) $(host-cxxobjs) $(host-shared)
|
||||
|
@ -107,6 +107,17 @@ mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o
|
||||
fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o
|
||||
fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
|
||||
|
||||
hostprogs-$(CONFIG_SPL_OF_PLATDATA) += _libfdt.so
|
||||
_libfdt.so-sharedobjs += $(LIBFDT_OBJS)
|
||||
libfdt:
|
||||
|
||||
tools/_libfdt.so: $(patsubst %.o,%.c,$(LIBFDT_OBJS)) tools/libfdt_wrap.c
|
||||
python $(srctree)/lib/libfdt/setup.py "$(_hostc_flags)" $^
|
||||
mv _libfdt.so $@
|
||||
|
||||
tools/libfdt_wrap.c: $(srctree)/lib/libfdt/libfdt.swig
|
||||
swig -python -o $@ $<
|
||||
|
||||
# TODO(sjg@chromium.org): Is this correct on Mac OS?
|
||||
|
||||
ifneq ($(CONFIG_MX23)$(CONFIG_MX28),)
|
||||
|
180
tools/dtoc/fdt.py
Normal file
180
tools/dtoc/fdt.py
Normal file
@ -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
Block a user