mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
Merge git://git.denx.de/u-boot-fdt
This commit is contained in:
commit
dd31be21bf
24 changed files with 3062 additions and 2960 deletions
17
Makefile
17
Makefile
|
@ -1116,7 +1116,7 @@ cmd_ldr = $(LD) $(LDFLAGS_$(@F)) \
|
|||
|
||||
u-boot.rom: u-boot-x86-16bit.bin u-boot.bin \
|
||||
$(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \
|
||||
$(if $(CONFIG_HAVE_REFCODE),refcode.bin) FORCE
|
||||
$(if $(CONFIG_HAVE_REFCODE),refcode.bin) checkbinman FORCE
|
||||
$(call if_changed,binman)
|
||||
|
||||
OBJCOPYFLAGS_u-boot-x86-16bit.bin := -O binary -j .start16 -j .resetvec
|
||||
|
@ -1125,7 +1125,8 @@ u-boot-x86-16bit.bin: u-boot FORCE
|
|||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_SUNXI),)
|
||||
u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE
|
||||
u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb \
|
||||
checkbinman FORCE
|
||||
$(call if_changed,binman)
|
||||
endif
|
||||
|
||||
|
@ -1354,6 +1355,18 @@ $(version_h): include/config/uboot.release FORCE
|
|||
$(timestamp_h): $(srctree)/Makefile FORCE
|
||||
$(call filechk,timestamp.h)
|
||||
|
||||
checkbinman: tools
|
||||
@if ! ( echo 'import libfdt' | ( PYTHONPATH=tools python )); then \
|
||||
echo >&2; \
|
||||
echo >&2 '*** binman needs the Python libfdt library.'; \
|
||||
echo >&2 '*** Either install it on your system, or try:'; \
|
||||
echo >&2 '***'; \
|
||||
echo >&2 '*** sudo apt-get install swig libpython-dev'; \
|
||||
echo >&2 '***'; \
|
||||
echo >&2 '*** to have U-Boot build its own version.'; \
|
||||
false; \
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_cpp_lds = LDS $@
|
||||
cmd_cpp_lds = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) \
|
||||
|
|
|
@ -150,7 +150,8 @@ int pci_bar_show(struct udevice *dev)
|
|||
if ((!is_64 && size_low) || (is_64 && size)) {
|
||||
size = ~size + 1;
|
||||
printf(" %d %#016llx %#016llx %d %s %s\n",
|
||||
bar_id, base, size, is_64 ? 64 : 32,
|
||||
bar_id, (unsigned long long)base,
|
||||
(unsigned long long)size, is_64 ? 64 : 32,
|
||||
is_io ? "I/O" : "MEM",
|
||||
prefetchable ? "Prefetchable" : "");
|
||||
}
|
||||
|
|
112
include/fdt.h
112
include/fdt.h
|
@ -1,111 +1 @@
|
|||
#ifndef _FDT_H
|
||||
#define _FDT_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct fdt_header {
|
||||
fdt32_t magic; /* magic word FDT_MAGIC */
|
||||
fdt32_t totalsize; /* total size of DT block */
|
||||
fdt32_t off_dt_struct; /* offset to structure */
|
||||
fdt32_t off_dt_strings; /* offset to strings */
|
||||
fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
|
||||
fdt32_t version; /* format version */
|
||||
fdt32_t last_comp_version; /* last compatible version */
|
||||
|
||||
/* version 2 fields below */
|
||||
fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
|
||||
booting on */
|
||||
/* version 3 fields below */
|
||||
fdt32_t size_dt_strings; /* size of the strings block */
|
||||
|
||||
/* version 17 fields below */
|
||||
fdt32_t size_dt_struct; /* size of the structure block */
|
||||
};
|
||||
|
||||
struct fdt_reserve_entry {
|
||||
fdt64_t address;
|
||||
fdt64_t size;
|
||||
};
|
||||
|
||||
struct fdt_node_header {
|
||||
fdt32_t tag;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct fdt_property {
|
||||
fdt32_t tag;
|
||||
fdt32_t len;
|
||||
fdt32_t nameoff;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
#endif /* !__ASSEMBLY */
|
||||
|
||||
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
|
||||
#define FDT_TAGSIZE sizeof(fdt32_t)
|
||||
|
||||
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
|
||||
#define FDT_END_NODE 0x2 /* End node */
|
||||
#define FDT_PROP 0x3 /* Property: name off,
|
||||
size, content */
|
||||
#define FDT_NOP 0x4 /* nop */
|
||||
#define FDT_END 0x9
|
||||
|
||||
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
|
||||
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
|
||||
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
|
||||
#define FDT_V16_SIZE FDT_V3_SIZE
|
||||
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
|
||||
|
||||
#endif /* _FDT_H */
|
||||
#include <../lib/libfdt/fdt.h>
|
||||
|
|
2138
include/libfdt.h
2138
include/libfdt.h
File diff suppressed because it is too large
Load diff
|
@ -1169,7 +1169,8 @@ int fdtdec_setup_memory_size(void)
|
|||
}
|
||||
|
||||
gd->ram_size = (phys_size_t)(res.end - res.start + 1);
|
||||
debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
|
||||
debug("%s: Initial DRAM size %llx\n", __func__,
|
||||
(unsigned long long)gd->ram_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
67
lib/libfdt/fdt.h
Normal file
67
lib/libfdt/fdt.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
#ifndef _FDT_H
|
||||
#define _FDT_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct fdt_header {
|
||||
fdt32_t magic; /* magic word FDT_MAGIC */
|
||||
fdt32_t totalsize; /* total size of DT block */
|
||||
fdt32_t off_dt_struct; /* offset to structure */
|
||||
fdt32_t off_dt_strings; /* offset to strings */
|
||||
fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
|
||||
fdt32_t version; /* format version */
|
||||
fdt32_t last_comp_version; /* last compatible version */
|
||||
|
||||
/* version 2 fields below */
|
||||
fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
|
||||
booting on */
|
||||
/* version 3 fields below */
|
||||
fdt32_t size_dt_strings; /* size of the strings block */
|
||||
|
||||
/* version 17 fields below */
|
||||
fdt32_t size_dt_struct; /* size of the structure block */
|
||||
};
|
||||
|
||||
struct fdt_reserve_entry {
|
||||
fdt64_t address;
|
||||
fdt64_t size;
|
||||
};
|
||||
|
||||
struct fdt_node_header {
|
||||
fdt32_t tag;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct fdt_property {
|
||||
fdt32_t tag;
|
||||
fdt32_t len;
|
||||
fdt32_t nameoff;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
#endif /* !__ASSEMBLY */
|
||||
|
||||
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
|
||||
#define FDT_TAGSIZE sizeof(fdt32_t)
|
||||
|
||||
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
|
||||
#define FDT_END_NODE 0x2 /* End node */
|
||||
#define FDT_PROP 0x3 /* Property: name off,
|
||||
size, content */
|
||||
#define FDT_NOP 0x4 /* nop */
|
||||
#define FDT_END 0x9
|
||||
|
||||
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
|
||||
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
|
||||
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
|
||||
#define FDT_V16_SIZE FDT_V3_SIZE
|
||||
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
|
||||
|
||||
#endif /* _FDT_H */
|
2144
lib/libfdt/libfdt.h
Normal file
2144
lib/libfdt/libfdt.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,113 +0,0 @@
|
|||
/* 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);
|
||||
}
|
||||
%}
|
||||
|
||||
%typemap(in) (const void *) {
|
||||
if (!PyByteArray_Check($input)) {
|
||||
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument "
|
||||
"$argnum"" of type '" "$type""'");
|
||||
}
|
||||
$1 = (void *) PyByteArray_AsString($input);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
%typemap(in) (void *) {
|
||||
if (!PyByteArray_Check($input)) {
|
||||
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument "
|
||||
"$argnum"" of type '" "$type""'");
|
||||
}
|
||||
$1 = PyByteArray_AsString($input);
|
||||
}
|
||||
|
||||
int fdt_delprop(void *fdt, int nodeoffset, const char *name);
|
||||
|
||||
const char *fdt_strerror(int errval);
|
||||
int fdt_pack(void *fdt);
|
||||
|
||||
int fdt_totalsize(const void *fdt);
|
||||
int fdt_off_dt_struct(const void *fdt);
|
389
lib/libfdt/pylibfdt/libfdt.i
Normal file
389
lib/libfdt/pylibfdt/libfdt.i
Normal file
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* pylibfdt - Flat Device Tree manipulation in Python
|
||||
* Copyright (C) 2017 Google, Inc.
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
|
||||
*/
|
||||
|
||||
%module libfdt
|
||||
|
||||
%{
|
||||
#define SWIG_FILE_WITH_INIT
|
||||
#include "libfdt.h"
|
||||
%}
|
||||
|
||||
%pythoncode %{
|
||||
|
||||
import struct
|
||||
|
||||
# Error codes, corresponding to FDT_ERR_... in libfdt.h
|
||||
(NOTFOUND,
|
||||
EXISTS,
|
||||
NOSPACE,
|
||||
BADOFFSET,
|
||||
BADPATH,
|
||||
BADPHANDLE,
|
||||
BADSTATE,
|
||||
TRUNCATED,
|
||||
BADMAGIC,
|
||||
BADVERSION,
|
||||
BADSTRUCTURE,
|
||||
BADLAYOUT,
|
||||
INTERNAL,
|
||||
BADNCELLS,
|
||||
BADVALUE,
|
||||
BADOVERLAY,
|
||||
NOPHANDLES) = QUIET_ALL = range(1, 18)
|
||||
# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
|
||||
# altogether. All # functions passed this value will return an error instead
|
||||
# of raising an exception.
|
||||
|
||||
# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
|
||||
# instead of raising an exception.
|
||||
QUIET_NOTFOUND = (NOTFOUND,)
|
||||
|
||||
|
||||
class FdtException(Exception):
|
||||
"""An exception caused by an error such as one of the codes above"""
|
||||
def __init__(self, err):
|
||||
self.err = err
|
||||
|
||||
def __str__(self):
|
||||
return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
|
||||
|
||||
def strerror(fdt_err):
|
||||
"""Get the string for an error number
|
||||
|
||||
Args:
|
||||
fdt_err: Error number (-ve)
|
||||
|
||||
Returns:
|
||||
String containing the associated error
|
||||
"""
|
||||
return fdt_strerror(fdt_err)
|
||||
|
||||
def check_err(val, quiet=()):
|
||||
"""Raise an error if the return value is -ve
|
||||
|
||||
This is used to check for errors returned by libfdt C functions.
|
||||
|
||||
Args:
|
||||
val: Return value from a libfdt function
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
val if val >= 0
|
||||
|
||||
Raises
|
||||
FdtException if val < 0
|
||||
"""
|
||||
if val < 0:
|
||||
if -val not in quiet:
|
||||
raise FdtException(val)
|
||||
return val
|
||||
|
||||
def check_err_null(val, quiet=()):
|
||||
"""Raise an error if the return value is NULL
|
||||
|
||||
This is used to check for a NULL return value from certain libfdt C
|
||||
functions
|
||||
|
||||
Args:
|
||||
val: Return value from a libfdt function
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
val if val is a list, None if not
|
||||
|
||||
Raises
|
||||
FdtException if val indicates an error was reported and the error
|
||||
is not in @quiet.
|
||||
"""
|
||||
# Normally a list is returned which contains the data and its length.
|
||||
# If we get just an integer error code, it means the function failed.
|
||||
if not isinstance(val, list):
|
||||
if -val not in quiet:
|
||||
raise FdtException(val)
|
||||
return val
|
||||
|
||||
class Fdt:
|
||||
"""Device tree class, supporting all operations
|
||||
|
||||
The Fdt object is created is created from a device tree binary file,
|
||||
e.g. with something like:
|
||||
|
||||
fdt = Fdt(open("filename.dtb").read())
|
||||
|
||||
Operations can then be performed using the methods in this class. Each
|
||||
method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
|
||||
|
||||
All methods raise an FdtException if an error occurs. To avoid this
|
||||
behaviour a 'quiet' parameter is provided for some functions. This
|
||||
defaults to empty, but you can pass a list of errors that you expect.
|
||||
If one of these errors occurs, the function will return an error number
|
||||
(e.g. -NOTFOUND).
|
||||
"""
|
||||
def __init__(self, data):
|
||||
self._fdt = bytearray(data)
|
||||
check_err(fdt_check_header(self._fdt));
|
||||
|
||||
def path_offset(self, path, quiet=()):
|
||||
"""Get the offset for a given path
|
||||
|
||||
Args:
|
||||
path: Path to the required node, e.g. '/node@3/subnode@1'
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
Node offset
|
||||
|
||||
Raises
|
||||
FdtException if the path is not valid or not found
|
||||
"""
|
||||
return check_err(fdt_path_offset(self._fdt, path), quiet)
|
||||
|
||||
def first_property_offset(self, nodeoffset, quiet=()):
|
||||
"""Get the offset of the first property in a node offset
|
||||
|
||||
Args:
|
||||
nodeoffset: Offset to the node to check
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
Offset of the first property
|
||||
|
||||
Raises
|
||||
FdtException if the associated node has no properties, or some
|
||||
other error occurred
|
||||
"""
|
||||
return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
|
||||
quiet)
|
||||
|
||||
def next_property_offset(self, prop_offset, quiet=()):
|
||||
"""Get the next property in a node
|
||||
|
||||
Args:
|
||||
prop_offset: Offset of the previous property
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
Offset of the next property
|
||||
|
||||
Raises:
|
||||
FdtException if the associated node has no more properties, or
|
||||
some other error occurred
|
||||
"""
|
||||
return check_err(fdt_next_property_offset(self._fdt, prop_offset),
|
||||
quiet)
|
||||
|
||||
def get_name(self, nodeoffset):
|
||||
"""Get the name of a node
|
||||
|
||||
Args:
|
||||
nodeoffset: Offset of node to check
|
||||
|
||||
Returns:
|
||||
Node name
|
||||
|
||||
Raises:
|
||||
FdtException on error (e.g. nodeoffset is invalid)
|
||||
"""
|
||||
return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
|
||||
|
||||
def get_property_by_offset(self, prop_offset, quiet=()):
|
||||
"""Obtains a property that can be examined
|
||||
|
||||
Args:
|
||||
prop_offset: Offset of property (e.g. from first_property_offset())
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
Property object, or None if not found
|
||||
|
||||
Raises:
|
||||
FdtException on error (e.g. invalid prop_offset or device
|
||||
tree format)
|
||||
"""
|
||||
pdata = check_err_null(
|
||||
fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
|
||||
if isinstance(pdata, (int)):
|
||||
return pdata
|
||||
return Property(pdata[0], pdata[1])
|
||||
|
||||
def first_subnode(self, nodeoffset, quiet=()):
|
||||
"""Find the first subnode of a parent node
|
||||
|
||||
Args:
|
||||
nodeoffset: Node offset of parent node
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
The offset of the first subnode, if any
|
||||
|
||||
Raises:
|
||||
FdtException if no subnode found or other error occurs
|
||||
"""
|
||||
return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
|
||||
|
||||
def next_subnode(self, nodeoffset, quiet=()):
|
||||
"""Find the next subnode
|
||||
|
||||
Args:
|
||||
nodeoffset: Node offset of previous subnode
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
The offset of the next subnode, if any
|
||||
|
||||
Raises:
|
||||
FdtException if no more subnode found or other error occurs
|
||||
"""
|
||||
return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
|
||||
|
||||
def totalsize(self):
|
||||
"""Return the total size of the device tree
|
||||
|
||||
Returns:
|
||||
Total tree size in bytes
|
||||
"""
|
||||
return check_err(fdt_totalsize(self._fdt))
|
||||
|
||||
def off_dt_struct(self):
|
||||
"""Return the start of the device tree struct area
|
||||
|
||||
Returns:
|
||||
Start offset of struct area
|
||||
"""
|
||||
return check_err(fdt_off_dt_struct(self._fdt))
|
||||
|
||||
def pack(self, quiet=()):
|
||||
"""Pack the device tree to remove unused space
|
||||
|
||||
This adjusts the tree in place.
|
||||
|
||||
Args:
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Raises:
|
||||
FdtException if any error occurs
|
||||
"""
|
||||
return check_err(fdt_pack(self._fdt), quiet)
|
||||
|
||||
def delprop(self, nodeoffset, prop_name):
|
||||
"""Delete a property from a node
|
||||
|
||||
Args:
|
||||
nodeoffset: Node offset containing property to delete
|
||||
prop_name: Name of property to delete
|
||||
|
||||
Raises:
|
||||
FdtError if the property does not exist, or another error occurs
|
||||
"""
|
||||
return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
|
||||
|
||||
def getprop(self, nodeoffset, prop_name, quiet=()):
|
||||
"""Get a property from a node
|
||||
|
||||
Args:
|
||||
nodeoffset: Node offset containing property to get
|
||||
prop_name: Name of property to get
|
||||
quiet: Errors to ignore (empty to raise on all errors)
|
||||
|
||||
Returns:
|
||||
Value of property as a bytearray, or -ve error number
|
||||
|
||||
Raises:
|
||||
FdtError if any error occurs (e.g. the property is not found)
|
||||
"""
|
||||
pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
|
||||
quiet)
|
||||
if isinstance(pdata, (int)):
|
||||
return pdata
|
||||
return bytearray(pdata[0])
|
||||
|
||||
|
||||
class Property:
|
||||
"""Holds a device tree property name and value.
|
||||
|
||||
This holds a copy of a property taken from the device tree. It does not
|
||||
reference the device tree, so if anything changes in the device tree,
|
||||
a Property object will remain valid.
|
||||
|
||||
Properties:
|
||||
name: Property name
|
||||
value: Proper value as a bytearray
|
||||
"""
|
||||
def __init__(self, name, value):
|
||||
self.name = name
|
||||
self.value = value
|
||||
%}
|
||||
|
||||
%rename(fdt_property) fdt_property_func;
|
||||
|
||||
typedef int fdt32_t;
|
||||
|
||||
%include "libfdt/fdt.h"
|
||||
|
||||
%include "typemaps.i"
|
||||
|
||||
/* Most functions don't change the device tree, so use a const void * */
|
||||
%typemap(in) (const void *)(const void *fdt) {
|
||||
if (!PyByteArray_Check($input)) {
|
||||
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
|
||||
"', argument " "$argnum"" of type '" "$type""'");
|
||||
}
|
||||
$1 = (void *)PyByteArray_AsString($input);
|
||||
fdt = $1;
|
||||
fdt = fdt; /* avoid unused variable warning */
|
||||
}
|
||||
|
||||
/* Some functions do change the device tree, so use void * */
|
||||
%typemap(in) (void *)(const void *fdt) {
|
||||
if (!PyByteArray_Check($input)) {
|
||||
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
|
||||
"', argument " "$argnum"" of type '" "$type""'");
|
||||
}
|
||||
$1 = PyByteArray_AsString($input);
|
||||
fdt = $1;
|
||||
fdt = fdt; /* avoid unused variable warning */
|
||||
}
|
||||
|
||||
%typemap(out) (struct fdt_property *) {
|
||||
PyObject *buff;
|
||||
|
||||
if ($1) {
|
||||
resultobj = PyString_FromString(
|
||||
fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
|
||||
buff = PyByteArray_FromStringAndSize(
|
||||
(const char *)($1 + 1), fdt32_to_cpu($1->len));
|
||||
resultobj = SWIG_Python_AppendOutput(resultobj, buff);
|
||||
}
|
||||
}
|
||||
|
||||
%apply int *OUTPUT { int *lenp };
|
||||
|
||||
/* typemap used for fdt_getprop() */
|
||||
%typemap(out) (const void *) {
|
||||
if (!$1)
|
||||
$result = Py_None;
|
||||
else
|
||||
$result = Py_BuildValue("s#", $1, *arg4);
|
||||
}
|
||||
|
||||
/* We have both struct fdt_property and a function fdt_property() */
|
||||
%warnfilter(302) fdt_property;
|
||||
|
||||
/* These are macros in the header so have to be redefined here */
|
||||
int fdt_magic(const void *fdt);
|
||||
int fdt_totalsize(const void *fdt);
|
||||
int fdt_off_dt_struct(const void *fdt);
|
||||
int fdt_off_dt_strings(const void *fdt);
|
||||
int fdt_off_mem_rsvmap(const void *fdt);
|
||||
int fdt_version(const void *fdt);
|
||||
int fdt_last_comp_version(const void *fdt);
|
||||
int fdt_boot_cpuid_phys(const void *fdt);
|
||||
int fdt_size_dt_strings(const void *fdt);
|
||||
int fdt_size_dt_struct(const void *fdt);
|
||||
|
||||
%include <../libfdt/libfdt.h>
|
123
lib/libfdt/pylibfdt/setup.py
Executable file
123
lib/libfdt/pylibfdt/setup.py
Executable file
|
@ -0,0 +1,123 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
setup.py file for SWIG libfdt
|
||||
Copyright (C) 2017 Google, Inc.
|
||||
Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
|
||||
|
||||
Files to be built into the extension are provided in SOURCES
|
||||
C flags to use are provided in CPPFLAGS
|
||||
Object file directory is provided in OBJDIR
|
||||
Version is provided in VERSION
|
||||
|
||||
If these variables are not given they are parsed from the Makefiles. This
|
||||
allows this script to be run stand-alone, e.g.:
|
||||
|
||||
./pylibfdt/setup.py install [--prefix=...]
|
||||
"""
|
||||
|
||||
from distutils.core import setup, Extension
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Decodes a Makefile assignment line into key and value (and plus for +=)
|
||||
RE_KEY_VALUE = re.compile('(?P<key>\w+) *(?P<plus>[+])?= *(?P<value>.*)$')
|
||||
|
||||
|
||||
def ParseMakefile(fname):
|
||||
"""Parse a Makefile to obtain its variables.
|
||||
|
||||
This collects variable assigments of the form:
|
||||
|
||||
VAR = value
|
||||
VAR += more
|
||||
|
||||
It does not pick out := assignments, as these are not needed here. It does
|
||||
handle line continuation.
|
||||
|
||||
Returns a dict:
|
||||
key: Variable name (e.g. 'VAR')
|
||||
value: Variable value (e.g. 'value more')
|
||||
"""
|
||||
makevars = {}
|
||||
with open(fname) as fd:
|
||||
prev_text = '' # Continuation text from previous line(s)
|
||||
for line in fd.read().splitlines():
|
||||
if line and line[-1] == '\\': # Deal with line continuation
|
||||
prev_text += line[:-1]
|
||||
continue
|
||||
elif prev_text:
|
||||
line = prev_text + line
|
||||
prev_text = '' # Continuation is now used up
|
||||
m = RE_KEY_VALUE.match(line)
|
||||
if m:
|
||||
value = m.group('value') or ''
|
||||
key = m.group('key')
|
||||
|
||||
# Appending to a variable inserts a space beforehand
|
||||
if 'plus' in m.groupdict() and key in makevars:
|
||||
makevars[key] += ' ' + value
|
||||
else:
|
||||
makevars[key] = value
|
||||
return makevars
|
||||
|
||||
def GetEnvFromMakefiles():
|
||||
"""Scan the Makefiles to obtain the settings we need.
|
||||
|
||||
This assumes that this script is being run from the top-level directory,
|
||||
not the pylibfdt directory.
|
||||
|
||||
Returns:
|
||||
Tuple with:
|
||||
List of swig options
|
||||
Version string
|
||||
List of files to build
|
||||
List of extra C preprocessor flags needed
|
||||
Object directory to use (always '')
|
||||
"""
|
||||
basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
|
||||
swig_opts = ['-I%s' % basedir]
|
||||
makevars = ParseMakefile(os.path.join(basedir, 'Makefile'))
|
||||
version = '%s.%s.%s' % (makevars['VERSION'], makevars['PATCHLEVEL'],
|
||||
makevars['SUBLEVEL'])
|
||||
makevars = ParseMakefile(os.path.join(basedir, 'libfdt', 'Makefile.libfdt'))
|
||||
files = makevars['LIBFDT_SRCS'].split()
|
||||
files = [os.path.join(basedir, 'libfdt', fname) for fname in files]
|
||||
files.append('pylibfdt/libfdt.i')
|
||||
cflags = ['-I%s' % basedir, '-I%s/libfdt' % basedir]
|
||||
objdir = ''
|
||||
return swig_opts, version, files, cflags, objdir
|
||||
|
||||
|
||||
progname = sys.argv[0]
|
||||
files = os.environ.get('SOURCES', '').split()
|
||||
cflags = os.environ.get('CPPFLAGS', '').split()
|
||||
objdir = os.environ.get('OBJDIR')
|
||||
version = os.environ.get('VERSION')
|
||||
swig_opts = os.environ.get('SWIG_OPTS', '').split()
|
||||
|
||||
# If we were called directly rather than through our Makefile (which is often
|
||||
# the case with Python module installation), read the settings from the
|
||||
# Makefile.
|
||||
if not all((swig_opts, version, files, cflags, objdir)):
|
||||
swig_opts, version, files, cflags, objdir = GetEnvFromMakefiles()
|
||||
|
||||
libfdt_module = Extension(
|
||||
'_libfdt',
|
||||
sources = files,
|
||||
extra_compile_args = cflags,
|
||||
swig_opts = swig_opts,
|
||||
)
|
||||
|
||||
setup(
|
||||
name='libfdt',
|
||||
version= version,
|
||||
author='Simon Glass <sjg@chromium.org>',
|
||||
description='Python binding for libfdt',
|
||||
ext_modules=[libfdt_module],
|
||||
package_dir={'': objdir},
|
||||
py_modules=['pylibfdt/libfdt'],
|
||||
)
|
|
@ -1,38 +0,0 @@
|
|||
#!/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', '--force']
|
||||
|
||||
setup (name = 'libfdt',
|
||||
version = '0.1',
|
||||
author = "SWIG Docs",
|
||||
description = """Simple swig libfdt from docs""",
|
||||
ext_modules = [libfdt_module],
|
||||
py_modules = ["libfdt"],
|
||||
)
|
|
@ -257,14 +257,12 @@ PHONY += dts_dir
|
|||
dts_dir:
|
||||
$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
|
||||
|
||||
include/generated/dt-structs.h: $(obj)/$(SPL_BIN).dtb dts_dir dtoc
|
||||
include/generated/dt-structs.h: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
|
||||
$(call if_changed,dtoch)
|
||||
|
||||
$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir dtoc
|
||||
$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir checkdtoc
|
||||
$(call if_changed,dtocc)
|
||||
|
||||
dtoc: #$(objtree)/tools/_libfdt.so
|
||||
|
||||
ifdef CONFIG_SAMSUNG
|
||||
ifdef CONFIG_VAR_SIZE_SPL
|
||||
VAR_SIZE_PARAM = --vs
|
||||
|
@ -357,6 +355,17 @@ ifneq ($(cmd_files),)
|
|||
include $(cmd_files)
|
||||
endif
|
||||
|
||||
checkdtoc: tools
|
||||
@if ! ( echo 'import libfdt' | ( PYTHONPATH=tools python )); then \
|
||||
echo '*** dtoc needs the Python libfdt library. Either '; \
|
||||
echo '*** install it on your system, or try:'; \
|
||||
echo '***'; \
|
||||
echo '*** sudo apt-get install swig libpython-dev'; \
|
||||
echo '***'; \
|
||||
echo '*** to have U-Boot build its own version.'; \
|
||||
false; \
|
||||
fi
|
||||
|
||||
PHONY += FORCE
|
||||
FORCE:
|
||||
|
||||
|
|
|
@ -60,9 +60,21 @@ hostprogs-$(CONFIG_FIT_SIGNATURE) += fit_info fit_check_sign
|
|||
|
||||
FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := common/image-sig.o
|
||||
# Flattened device tree objects
|
||||
LIBFDT_OBJS := $(addprefix lib/libfdt/, \
|
||||
fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o \
|
||||
fdt_region.o fdt_sw.o)
|
||||
LIBFDT_CSRCS := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c \
|
||||
fdt_empty_tree.c fdt_addresses.c fdt_overlay.c \
|
||||
fdt_region.c
|
||||
|
||||
# Unfortunately setup.py below cannot handle srctree being ".." which it often
|
||||
# is. It fails with an error like:
|
||||
# Fatal error: can't create build/temp.linux-x86_64-2.7/../lib/libfdt/fdt.o:
|
||||
# No such file or directory
|
||||
# To fix this, use an absolute path.
|
||||
libfdt_tree := $(shell readlink -f $(srctree)/lib/libfdt)
|
||||
|
||||
LIBFDT_SRCS := $(addprefix $(libfdt_tree)/, $(LIBFDT_CSRCS))
|
||||
LIBFDT_SWIG := $(addprefix $(libfdt_tree)/, pylibfdt/libfdt.i)
|
||||
LIBFDT_OBJS := $(addprefix lib/libfdt/, $(patsubst %.c, %.o, $(LIBFDT_CSRCS)))
|
||||
|
||||
RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \
|
||||
rsa-sign.o rsa-verify.o rsa-checksum.o \
|
||||
rsa-mod-exp.o)
|
||||
|
@ -112,22 +124,22 @@ 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
|
||||
|
||||
# Build a libfdt Python module if swig is available
|
||||
# Use 'sudo apt-get install swig libpython-dev' to enable this
|
||||
hostprogs-y += \
|
||||
$(if $(shell which swig 2> /dev/null),_libfdt.so)
|
||||
_libfdt.so-sharedobjs += $(LIBFDT_OBJS)
|
||||
libfdt:
|
||||
|
||||
tools/_libfdt.so: $(patsubst %.o,%.c,$(LIBFDT_OBJS)) tools/libfdt_wrap.c
|
||||
LDFLAGS="$(HOSTLDFLAGS)" CFLAGS= ${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?
|
||||
# Unfortunately setup.py (or actually the Python distutil implementation)
|
||||
# puts files into the same directory as the .i file. We cannot touch the source
|
||||
# directory, so we copy the .i file into the tools/ build subdirectory before
|
||||
# calling setup. This directory is safe to write to. This ensures that we get
|
||||
# all three files in $(obj)/tools: _libfdt.so, libfdt.py and libfdt_wrap.c
|
||||
# The latter is a temporary file which we could actually remove.
|
||||
tools/_libfdt.so: $(LIBFDT_SRCS) $(LIBFDT_SWIG)
|
||||
cp $(LIBFDT_SWIG) tools/.
|
||||
unset CC; \
|
||||
unset CROSS_COMPILE; \
|
||||
LDFLAGS="$(HOSTLDFLAGS)" CFLAGS= VERSION="u-boot-$(UBOOTVERSION)" \
|
||||
CPPFLAGS="$(_hostc_flags)" OBJDIR=tools \
|
||||
SOURCES="$(LIBFDT_SRCS) tools/libfdt.i" \
|
||||
SWIG_OPTS="-I$(srctree)/lib/libfdt -I$(srctree)/lib" \
|
||||
$(libfdt_tree)/pylibfdt/setup.py --quiet build_ext \
|
||||
--build-lib tools
|
||||
|
||||
ifneq ($(CONFIG_MX23)$(CONFIG_MX28),)
|
||||
# Add CONFIG_MXS into host CFLAGS, so we can check whether or not register
|
||||
|
@ -216,6 +228,10 @@ clean-dirs := lib common
|
|||
|
||||
always := $(hostprogs-y)
|
||||
|
||||
# Build a libfdt Python module if swig is available
|
||||
# Use 'sudo apt-get install swig libpython-dev' to enable this
|
||||
always += $(if $(shell which swig 2> /dev/null),_libfdt.so)
|
||||
|
||||
# Generated LCD/video logo
|
||||
LOGO_H = $(objtree)/include/bmp_logo.h
|
||||
LOGO_DATA_H = $(objtree)/include/bmp_logo_data.h
|
||||
|
|
|
@ -21,6 +21,9 @@ sys.path.append(os.path.join(our_path, '../patman'))
|
|||
sys.path.append(os.path.join(our_path, '../dtoc'))
|
||||
sys.path.append(os.path.join(our_path, '../'))
|
||||
|
||||
# Bring in the libfdt module
|
||||
sys.path.append('tools')
|
||||
|
||||
# Also allow entry-type modules to be brought in from the etype directory.
|
||||
sys.path.append(os.path.join(our_path, 'etype'))
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import sys
|
|||
import tools
|
||||
|
||||
import command
|
||||
import fdt_select
|
||||
import fdt
|
||||
import fdt_util
|
||||
from image import Image
|
||||
import tout
|
||||
|
@ -40,15 +40,15 @@ def _ReadImageDesc(binman_node):
|
|||
images['image'] = Image('image', binman_node)
|
||||
return images
|
||||
|
||||
def _FindBinmanNode(fdt):
|
||||
def _FindBinmanNode(dtb):
|
||||
"""Find the 'binman' node in the device tree
|
||||
|
||||
Args:
|
||||
fdt: Fdt object to scan
|
||||
dtb: Fdt object to scan
|
||||
Returns:
|
||||
Node object of /binman node, or None if not found
|
||||
"""
|
||||
for node in fdt.GetRoot().subnodes:
|
||||
for node in dtb.GetRoot().subnodes:
|
||||
if node.name == 'binman':
|
||||
return node
|
||||
return None
|
||||
|
@ -92,8 +92,8 @@ def Binman(options, args):
|
|||
try:
|
||||
tools.SetInputDirs(options.indir)
|
||||
tools.PrepareOutputDir(options.outdir, options.preserve)
|
||||
fdt = fdt_select.FdtScan(dtb_fname)
|
||||
node = _FindBinmanNode(fdt)
|
||||
dtb = fdt.FdtScan(dtb_fname)
|
||||
node = _FindBinmanNode(dtb)
|
||||
if not node:
|
||||
raise ValueError("Device tree '%s' does not have a 'binman' "
|
||||
"node" % dtb_fname)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# Entry-type module for U-Boot device tree with the microcode removed
|
||||
#
|
||||
|
||||
import fdt_select
|
||||
import fdt
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
import tools
|
||||
|
@ -44,9 +44,8 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
|||
fd.write(self.data)
|
||||
|
||||
# Remove the microcode
|
||||
fdt = fdt_select.FdtScan(fname)
|
||||
fdt.Scan()
|
||||
ucode = fdt.GetNode('/microcode')
|
||||
dtb = fdt.FdtScan(fname)
|
||||
ucode = dtb.GetNode('/microcode')
|
||||
if not ucode:
|
||||
raise self.Raise("No /microcode node found in '%s'" % fname)
|
||||
|
||||
|
@ -57,20 +56,15 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
|||
data_prop = node.props.get('data')
|
||||
if data_prop:
|
||||
self.ucode_data += ''.join(data_prop.bytes)
|
||||
if not self.collate:
|
||||
poffset = data_prop.GetOffset()
|
||||
if poffset is None:
|
||||
# We cannot obtain a property offset. Collate instead.
|
||||
self.collate = True
|
||||
else:
|
||||
# Find the offset in the device tree of the ucode data
|
||||
self.ucode_offset = poffset + 12
|
||||
self.ucode_size = len(data_prop.bytes)
|
||||
if self.collate:
|
||||
prop = node.DeleteProp('data')
|
||||
else:
|
||||
# Find the offset in the device tree of the ucode data
|
||||
self.ucode_offset = data_prop.GetOffset() + 12
|
||||
self.ucode_size = len(data_prop.bytes)
|
||||
if self.collate:
|
||||
fdt.Pack()
|
||||
fdt.Flush()
|
||||
dtb.Pack()
|
||||
dtb.Flush()
|
||||
|
||||
# Make this file the contents of this entry
|
||||
self._pathname = fname
|
||||
|
|
|
@ -11,7 +11,8 @@ import sys
|
|||
import tempfile
|
||||
import unittest
|
||||
|
||||
from fdt_select import FdtScan
|
||||
import fdt
|
||||
from fdt import FdtScan
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
|
@ -28,21 +29,56 @@ class TestFdt(unittest.TestCase):
|
|||
def GetCompiled(self, fname):
|
||||
return fdt_util.EnsureCompiled(self.TestFile(fname))
|
||||
|
||||
def _DeleteProp(self, fdt):
|
||||
node = fdt.GetNode('/microcode/update@0')
|
||||
def _DeleteProp(self, dt):
|
||||
node = dt.GetNode('/microcode/update@0')
|
||||
node.DeleteProp('data')
|
||||
|
||||
def testFdtNormal(self):
|
||||
fname = self.GetCompiled('34_x86_ucode.dts')
|
||||
fdt = FdtScan(fname)
|
||||
self._DeleteProp(fdt)
|
||||
dt = FdtScan(fname)
|
||||
self._DeleteProp(dt)
|
||||
|
||||
def testFdtFallback(self):
|
||||
fname = self.GetCompiled('34_x86_ucode.dts')
|
||||
fdt = FdtScan(fname, True)
|
||||
fdt.GetProp('/microcode/update@0', 'data')
|
||||
self.assertEqual('fred',
|
||||
fdt.GetProp('/microcode/update@0', 'none', default='fred'))
|
||||
self.assertEqual('12345678 12345679',
|
||||
fdt.GetProp('/microcode/update@0', 'data', typespec='x'))
|
||||
self._DeleteProp(fdt)
|
||||
def testFdtNormalProp(self):
|
||||
fname = self.GetCompiled('45_prop_test.dts')
|
||||
dt = FdtScan(fname)
|
||||
node = dt.GetNode('/binman/intel-me')
|
||||
self.assertEquals('intel-me', node.name)
|
||||
val = fdt_util.GetString(node, 'filename')
|
||||
self.assertEquals(str, type(val))
|
||||
self.assertEquals('me.bin', val)
|
||||
|
||||
prop = node.props['intval']
|
||||
self.assertEquals(fdt.TYPE_INT, prop.type)
|
||||
self.assertEquals(3, fdt_util.GetInt(node, 'intval'))
|
||||
|
||||
prop = node.props['intarray']
|
||||
self.assertEquals(fdt.TYPE_INT, prop.type)
|
||||
self.assertEquals(list, type(prop.value))
|
||||
self.assertEquals(2, len(prop.value))
|
||||
self.assertEquals([5, 6],
|
||||
[fdt_util.fdt32_to_cpu(val) for val in prop.value])
|
||||
|
||||
prop = node.props['byteval']
|
||||
self.assertEquals(fdt.TYPE_BYTE, prop.type)
|
||||
self.assertEquals(chr(8), prop.value)
|
||||
|
||||
prop = node.props['bytearray']
|
||||
self.assertEquals(fdt.TYPE_BYTE, prop.type)
|
||||
self.assertEquals(list, type(prop.value))
|
||||
self.assertEquals(str, type(prop.value[0]))
|
||||
self.assertEquals(3, len(prop.value))
|
||||
self.assertEquals([chr(1), '#', '4'], prop.value)
|
||||
|
||||
prop = node.props['longbytearray']
|
||||
self.assertEquals(fdt.TYPE_INT, prop.type)
|
||||
self.assertEquals(0x090a0b0c, fdt_util.GetInt(node, 'longbytearray'))
|
||||
|
||||
prop = node.props['stringval']
|
||||
self.assertEquals(fdt.TYPE_STRING, prop.type)
|
||||
self.assertEquals('message2', fdt_util.GetString(node, 'stringval'))
|
||||
|
||||
prop = node.props['stringarray']
|
||||
self.assertEquals(fdt.TYPE_STRING, prop.type)
|
||||
self.assertEquals(list, type(prop.value))
|
||||
self.assertEquals(3, len(prop.value))
|
||||
self.assertEquals(['another', 'multi-word', 'message'], prop.value)
|
||||
|
|
|
@ -21,7 +21,7 @@ import cmdline
|
|||
import command
|
||||
import control
|
||||
import entry
|
||||
import fdt_select
|
||||
import fdt
|
||||
import fdt_util
|
||||
import tools
|
||||
import tout
|
||||
|
@ -658,8 +658,8 @@ class TestFunctional(unittest.TestCase):
|
|||
fname = tools.GetOutputFilename('test.dtb')
|
||||
with open(fname, 'wb') as fd:
|
||||
fd.write(second)
|
||||
fdt = fdt_select.FdtScan(fname)
|
||||
ucode = fdt.GetNode('/microcode')
|
||||
dtb = fdt.FdtScan(fname)
|
||||
ucode = dtb.GetNode('/microcode')
|
||||
self.assertTrue(ucode)
|
||||
for node in ucode.subnodes:
|
||||
self.assertFalse(node.props.get('data'))
|
||||
|
@ -683,7 +683,7 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertEqual('nodtb with microcode' + pos_and_size +
|
||||
' somewhere in here', first)
|
||||
|
||||
def _RunPackUbootSingleMicrocode(self, collate):
|
||||
def _RunPackUbootSingleMicrocode(self):
|
||||
"""Test that x86 microcode can be handled correctly
|
||||
|
||||
We expect to see the following in the image, in order:
|
||||
|
@ -695,8 +695,6 @@ class TestFunctional(unittest.TestCase):
|
|||
# We need the libfdt library to run this test since only that allows
|
||||
# finding the offset of a property. This is required by
|
||||
# Entry_u_boot_dtb_with_ucode.ObtainContents().
|
||||
if not fdt_select.have_libfdt:
|
||||
return
|
||||
data = self._DoReadFile('35_x86_single_ucode.dts', True)
|
||||
|
||||
second = data[len(U_BOOT_NODTB_DATA):]
|
||||
|
@ -705,34 +703,22 @@ class TestFunctional(unittest.TestCase):
|
|||
third = second[fdt_len:]
|
||||
second = second[:fdt_len]
|
||||
|
||||
if not collate:
|
||||
ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
|
||||
self.assertIn(ucode_data, second)
|
||||
ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
|
||||
ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
|
||||
self.assertIn(ucode_data, second)
|
||||
ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
|
||||
|
||||
# Check that the microcode pointer was inserted. It should match the
|
||||
# expected position and size
|
||||
pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
|
||||
len(ucode_data))
|
||||
first = data[:len(U_BOOT_NODTB_DATA)]
|
||||
self.assertEqual('nodtb with microcode' + pos_and_size +
|
||||
' somewhere in here', first)
|
||||
# Check that the microcode pointer was inserted. It should match the
|
||||
# expected position and size
|
||||
pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
|
||||
len(ucode_data))
|
||||
first = data[:len(U_BOOT_NODTB_DATA)]
|
||||
self.assertEqual('nodtb with microcode' + pos_and_size +
|
||||
' somewhere in here', first)
|
||||
|
||||
def testPackUbootSingleMicrocode(self):
|
||||
"""Test that x86 microcode can be handled correctly with fdt_normal.
|
||||
"""
|
||||
self._RunPackUbootSingleMicrocode(False)
|
||||
|
||||
def testPackUbootSingleMicrocodeFallback(self):
|
||||
"""Test that x86 microcode can be handled correctly with fdt_fallback.
|
||||
|
||||
This only supports collating the microcode.
|
||||
"""
|
||||
try:
|
||||
old_val = fdt_select.UseFallback(True)
|
||||
self._RunPackUbootSingleMicrocode(True)
|
||||
finally:
|
||||
fdt_select.UseFallback(old_val)
|
||||
self._RunPackUbootSingleMicrocode()
|
||||
|
||||
def testUBootImg(self):
|
||||
"""Test that u-boot.img can be put in a file"""
|
||||
|
@ -763,14 +749,12 @@ class TestFunctional(unittest.TestCase):
|
|||
def testMicrocodeWithoutPtrInElf(self):
|
||||
"""Test that a U-Boot binary without the microcode symbol is detected"""
|
||||
# ELF file without a '_dt_ucode_base_size' symbol
|
||||
if not fdt_select.have_libfdt:
|
||||
return
|
||||
try:
|
||||
with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
|
||||
TestFunctional._MakeInputFile('u-boot', fd.read())
|
||||
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._RunPackUbootSingleMicrocode(False)
|
||||
self._RunPackUbootSingleMicrocode()
|
||||
self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
|
||||
"_dt_ucode_base_size symbol in u-boot", str(e.exception))
|
||||
|
||||
|
|
23
tools/binman/test/45_prop_test.dts
Normal file
23
tools/binman/test/45_prop_test.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <16>;
|
||||
intel-me {
|
||||
filename = "me.bin";
|
||||
pos-unset;
|
||||
intval = <3>;
|
||||
intarray = <5 6>;
|
||||
byteval = [08];
|
||||
bytearray = [01 23 34];
|
||||
longbytearray = [09 0a 0b 0c];
|
||||
stringval = "message2";
|
||||
stringarray = "another", "multi-word", "message";
|
||||
};
|
||||
};
|
||||
};
|
|
@ -17,7 +17,6 @@ our_path = os.path.dirname(os.path.realpath(__file__))
|
|||
sys.path.append(os.path.join(our_path, '../patman'))
|
||||
|
||||
import fdt
|
||||
import fdt_select
|
||||
import fdt_util
|
||||
|
||||
# When we see these properties we ignore them - i.e. do not create a structure member
|
||||
|
@ -170,7 +169,7 @@ class DtbPlatdata:
|
|||
Once this is done, self.fdt.GetRoot() can be called to obtain the
|
||||
device tree root node, and progress from there.
|
||||
"""
|
||||
self.fdt = fdt_select.FdtScan(self._dtb_fname)
|
||||
self.fdt = fdt.FdtScan(self._dtb_fname)
|
||||
|
||||
def ScanNode(self, root):
|
||||
for node in root.subnodes:
|
||||
|
|
|
@ -10,12 +10,15 @@ import struct
|
|||
import sys
|
||||
|
||||
import fdt_util
|
||||
import libfdt
|
||||
|
||||
# This deals with a device tree, presenting it as an assortment of Node and
|
||||
# Prop objects, representing nodes and properties, respectively. This file
|
||||
# contains the base classes and defines the high-level API. Most of the
|
||||
# implementation is in the FdtFallback and FdtNormal subclasses. See
|
||||
# fdt_select.py for how to create an Fdt object.
|
||||
# contains the base classes and defines the high-level API. You can use
|
||||
# FdtScan() as a convenience function to create and scan an Fdt.
|
||||
|
||||
# This implementation uses a libfdt Python library to access the device tree,
|
||||
# so it is fairly efficient.
|
||||
|
||||
# A list of types we support
|
||||
(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
|
||||
|
@ -25,7 +28,7 @@ def CheckErr(errnum, msg):
|
|||
raise ValueError('Error %d: %s: %s' %
|
||||
(errnum, libfdt.fdt_strerror(errnum), msg))
|
||||
|
||||
class PropBase:
|
||||
class Prop:
|
||||
"""A device tree property
|
||||
|
||||
Properties:
|
||||
|
@ -34,11 +37,17 @@ class PropBase:
|
|||
bytes
|
||||
type: Value type
|
||||
"""
|
||||
def __init__(self, node, offset, name):
|
||||
def __init__(self, node, offset, name, bytes):
|
||||
self._node = node
|
||||
self._offset = offset
|
||||
self.name = name
|
||||
self.value = None
|
||||
self.bytes = str(bytes)
|
||||
if not bytes:
|
||||
self.type = TYPE_BOOL
|
||||
self.value = True
|
||||
return
|
||||
self.type, self.value = self.BytesToValue(bytes)
|
||||
|
||||
def GetPhandle(self):
|
||||
"""Get a (single) phandle value from a property
|
||||
|
@ -96,6 +105,7 @@ class PropBase:
|
|||
TYPE_INT: a byte-swapped integer stored as a 4-byte string
|
||||
TYPE_BYTE: a byte stored as a single-byte string
|
||||
"""
|
||||
bytes = str(bytes)
|
||||
size = len(bytes)
|
||||
strings = bytes.split('\0')
|
||||
is_string = True
|
||||
|
@ -147,15 +157,12 @@ class PropBase:
|
|||
def GetOffset(self):
|
||||
"""Get the offset of a property
|
||||
|
||||
This can be implemented by subclasses.
|
||||
|
||||
Returns:
|
||||
The offset of the property (struct fdt_property) within the
|
||||
file, or None if not known.
|
||||
The offset of the property (struct fdt_property) within the file
|
||||
"""
|
||||
return None
|
||||
return self._node._fdt.GetStructOffset(self._offset)
|
||||
|
||||
class NodeBase:
|
||||
class Node:
|
||||
"""A device tree node
|
||||
|
||||
Properties:
|
||||
|
@ -188,25 +195,65 @@ class NodeBase:
|
|||
return subnode
|
||||
return None
|
||||
|
||||
def Scan(self):
|
||||
"""Scan the subnodes of a node
|
||||
def Offset(self):
|
||||
"""Returns the offset of a node, after checking the cache
|
||||
|
||||
This should be implemented by subclasses
|
||||
This should be used instead of self._offset directly, to ensure that
|
||||
the cache does not contain invalid offsets.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
self._fdt.CheckCache()
|
||||
return self._offset
|
||||
|
||||
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)
|
||||
|
||||
offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
|
||||
while offset >= 0:
|
||||
sep = '' if self.path[-1] == '/' else '/'
|
||||
name = self._fdt._fdt_obj.get_name(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)
|
||||
|
||||
def Refresh(self, my_offset):
|
||||
"""Fix up the _offset for each node, recursively
|
||||
|
||||
Note: This does not take account of property offsets - these will not
|
||||
be updated.
|
||||
"""
|
||||
if self._offset != my_offset:
|
||||
#print '%s: %d -> %d\n' % (self.path, self._offset, my_offset)
|
||||
self._offset = my_offset
|
||||
offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
|
||||
for subnode in self.subnodes:
|
||||
subnode.Refresh(offset)
|
||||
offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
|
||||
|
||||
def DeleteProp(self, prop_name):
|
||||
"""Delete a property of a node
|
||||
|
||||
This should be implemented by subclasses
|
||||
The property is deleted and the offset cache is invalidated.
|
||||
|
||||
Args:
|
||||
prop_name: Name of the property to delete
|
||||
Raises:
|
||||
ValueError if the property does not exist
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
CheckErr(libfdt.fdt_delprop(self._fdt.GetFdt(), self.Offset(), prop_name),
|
||||
"Node '%s': delete property: '%s'" % (self.path, prop_name))
|
||||
del self.props[prop_name]
|
||||
self._fdt.Invalidate()
|
||||
|
||||
class Fdt:
|
||||
"""Provides simple access to a flat device tree blob.
|
||||
"""Provides simple access to a flat device tree blob using libfdts.
|
||||
|
||||
Properties:
|
||||
fname: Filename of fdt
|
||||
|
@ -214,6 +261,13 @@ class Fdt:
|
|||
"""
|
||||
def __init__(self, fname):
|
||||
self._fname = fname
|
||||
self._cached_offsets = False
|
||||
if self._fname:
|
||||
self._fname = fdt_util.EnsureCompiled(self._fname)
|
||||
|
||||
with open(self._fname) as fd:
|
||||
self._fdt = bytearray(fd.read())
|
||||
self._fdt_obj = libfdt.Fdt(self._fdt)
|
||||
|
||||
def Scan(self, root='/'):
|
||||
"""Scan a device tree, building up a tree of Node objects
|
||||
|
@ -255,15 +309,100 @@ class Fdt:
|
|||
"""Flush device tree changes back to the file
|
||||
|
||||
If the device tree has changed in memory, write it back to the file.
|
||||
Subclasses can implement this if needed.
|
||||
"""
|
||||
pass
|
||||
with open(self._fname, 'wb') as fd:
|
||||
fd.write(self._fdt)
|
||||
|
||||
def Pack(self):
|
||||
"""Pack the device tree down to its minimum size
|
||||
|
||||
When nodes and properties shrink or are deleted, wasted space can
|
||||
build up in the device tree binary. Subclasses can implement this
|
||||
to remove that spare space.
|
||||
build up in the device tree binary.
|
||||
"""
|
||||
pass
|
||||
CheckErr(libfdt.fdt_pack(self._fdt), 'pack')
|
||||
fdt_len = libfdt.fdt_totalsize(self._fdt)
|
||||
del self._fdt[fdt_len:]
|
||||
|
||||
def GetFdt(self):
|
||||
"""Get the contents of the FDT
|
||||
|
||||
Returns:
|
||||
The FDT contents as a string of bytes
|
||||
"""
|
||||
return self._fdt
|
||||
|
||||
def CheckErr(errnum, msg):
|
||||
if errnum:
|
||||
raise ValueError('Error %d: %s: %s' %
|
||||
(errnum, libfdt.fdt_strerror(errnum), msg))
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
props_dict = {}
|
||||
poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset)
|
||||
while poffset >= 0:
|
||||
p = self._fdt_obj.get_property_by_offset(poffset)
|
||||
prop = Prop(node, poffset, p.name, p.value)
|
||||
props_dict[prop.name] = prop
|
||||
|
||||
poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
|
||||
return props_dict
|
||||
|
||||
def Invalidate(self):
|
||||
"""Mark our offset cache as invalid"""
|
||||
self._cached_offsets = False
|
||||
|
||||
def CheckCache(self):
|
||||
"""Refresh the offset cache if needed"""
|
||||
if self._cached_offsets:
|
||||
return
|
||||
self.Refresh()
|
||||
self._cached_offsets = True
|
||||
|
||||
def Refresh(self):
|
||||
"""Refresh the offset cache"""
|
||||
self._root.Refresh(0)
|
||||
|
||||
def GetStructOffset(self, offset):
|
||||
"""Get the file offset of a given struct offset
|
||||
|
||||
Args:
|
||||
offset: Offset within the 'struct' region of the device tree
|
||||
Returns:
|
||||
Position of @offset within the device tree binary
|
||||
"""
|
||||
return libfdt.fdt_off_dt_struct(self._fdt) + offset
|
||||
|
||||
@classmethod
|
||||
def Node(self, fdt, offset, name, path):
|
||||
"""Create a new node
|
||||
|
||||
This is used by Fdt.Scan() to create a new node using the correct
|
||||
class.
|
||||
|
||||
Args:
|
||||
fdt: Fdt object
|
||||
offset: Offset of node
|
||||
name: Node name
|
||||
path: Full path to node
|
||||
"""
|
||||
node = Node(fdt, offset, name, path)
|
||||
return node
|
||||
|
||||
def FdtScan(fname):
|
||||
"""Returns a new Fdt object from the implementation we are using"""
|
||||
dtb = Fdt(fname)
|
||||
dtb.Scan()
|
||||
return dtb
|
||||
|
|
|
@ -1,181 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
import command
|
||||
import fdt
|
||||
from fdt import Fdt, NodeBase, PropBase
|
||||
import fdt_util
|
||||
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 the fdtget tool to access the device tree, so it
|
||||
# is not very efficient for larger trees. The tool is called once for each
|
||||
# node and property in the tree.
|
||||
|
||||
class Prop(PropBase):
|
||||
"""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, node, name, byte_list_str):
|
||||
PropBase.__init__(self, node, 0, name)
|
||||
if not byte_list_str.strip():
|
||||
self.type = fdt.TYPE_BOOL
|
||||
return
|
||||
self.bytes = [chr(int(byte, 16))
|
||||
for byte in byte_list_str.strip().split(' ')]
|
||||
self.type, self.value = self.BytesToValue(''.join(self.bytes))
|
||||
|
||||
|
||||
class Node(NodeBase):
|
||||
"""A device tree node
|
||||
|
||||
Properties:
|
||||
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):
|
||||
NodeBase.__init__(self, fdt, offset, name, path)
|
||||
|
||||
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.
|
||||
"""
|
||||
for name, byte_list_str in self._fdt.GetProps(self.path).items():
|
||||
prop = Prop(self, name, byte_list_str)
|
||||
self.props[name] = prop
|
||||
|
||||
for name in self._fdt.GetSubNodes(self.path):
|
||||
sep = '' if self.path[-1] == '/' else '/'
|
||||
path = self.path + sep + name
|
||||
node = Node(self._fdt, 0, name, path)
|
||||
self.subnodes.append(node)
|
||||
|
||||
node.Scan()
|
||||
|
||||
def DeleteProp(self, prop_name):
|
||||
"""Delete a property of a node
|
||||
|
||||
The property is deleted using fdtput.
|
||||
|
||||
Args:
|
||||
prop_name: Name of the property to delete
|
||||
Raises:
|
||||
CommandError if the property does not exist
|
||||
"""
|
||||
args = [self._fdt._fname, '-d', self.path, prop_name]
|
||||
command.Output('fdtput', *args)
|
||||
del self.props[prop_name]
|
||||
|
||||
class FdtFallback(Fdt):
|
||||
"""Provides simple access to a flat device tree blob using fdtget/fdtput
|
||||
|
||||
Properties:
|
||||
See superclass
|
||||
"""
|
||||
|
||||
def __init__(self, fname):
|
||||
Fdt.__init__(self, fname)
|
||||
if self._fname:
|
||||
self._fname = fdt_util.EnsureCompiled(self._fname)
|
||||
|
||||
def GetSubNodes(self, node):
|
||||
"""Returns a list of sub-nodes of a given node
|
||||
|
||||
Args:
|
||||
node: Node name to return children from
|
||||
|
||||
Returns:
|
||||
List of children in the node (each a string node name)
|
||||
|
||||
Raises:
|
||||
CmdError: if the node does not exist.
|
||||
"""
|
||||
out = command.Output('fdtget', self._fname, '-l', node)
|
||||
return out.strip().splitlines()
|
||||
|
||||
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 simply strings - no decoding of lists or numbers
|
||||
is done.
|
||||
|
||||
Raises:
|
||||
CmdError: if the node does not exist.
|
||||
"""
|
||||
out = command.Output('fdtget', self._fname, node, '-p')
|
||||
props = out.strip().splitlines()
|
||||
props_dict = {}
|
||||
for prop in props:
|
||||
name = prop
|
||||
props_dict[prop] = self.GetProp(node, name)
|
||||
return props_dict
|
||||
|
||||
def GetProp(self, node, prop, default=None, typespec=None):
|
||||
"""Get a property from a device tree.
|
||||
|
||||
This looks up the given node and property, and returns the value as a
|
||||
string,
|
||||
|
||||
If the node or property does not exist, this will return the default
|
||||
value.
|
||||
|
||||
Args:
|
||||
node: Full path to node to look up.
|
||||
prop: Property name to look up.
|
||||
default: Default value to return if nothing is present in the fdt,
|
||||
or None to raise in this case. This will be converted to a
|
||||
string.
|
||||
typespec: Type character to use (None for default, 's' for string)
|
||||
|
||||
Returns:
|
||||
string containing the property value.
|
||||
|
||||
Raises:
|
||||
CmdError: if the property does not exist and no default is provided.
|
||||
"""
|
||||
args = [self._fname, node, prop, '-t', 'bx']
|
||||
if default is not None:
|
||||
args += ['-d', str(default)]
|
||||
if typespec is not None:
|
||||
args += ['-t', typespec]
|
||||
out = command.Output('fdtget', *args)
|
||||
return out.strip()
|
||||
|
||||
@classmethod
|
||||
def Node(self, fdt, offset, name, path):
|
||||
"""Create a new node
|
||||
|
||||
This is used by Fdt.Scan() to create a new node using the correct
|
||||
class.
|
||||
|
||||
Args:
|
||||
fdt: Fdt object
|
||||
offset: Offset of node
|
||||
name: Node name
|
||||
path: Full path to node
|
||||
"""
|
||||
node = Node(fdt, offset, name, path)
|
||||
return node
|
|
@ -1,225 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
import struct
|
||||
import sys
|
||||
|
||||
import fdt
|
||||
from fdt import Fdt, NodeBase, PropBase
|
||||
import fdt_util
|
||||
import libfdt
|
||||
|
||||
# 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.
|
||||
|
||||
def CheckErr(errnum, msg):
|
||||
if errnum:
|
||||
raise ValueError('Error %d: %s: %s' %
|
||||
(errnum, libfdt.fdt_strerror(errnum), msg))
|
||||
|
||||
class Prop(PropBase):
|
||||
"""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, node, offset, name, bytes):
|
||||
PropBase.__init__(self, node, offset, name)
|
||||
self.bytes = bytes
|
||||
if not bytes:
|
||||
self.type = fdt.TYPE_BOOL
|
||||
self.value = True
|
||||
return
|
||||
self.type, self.value = self.BytesToValue(bytes)
|
||||
|
||||
def GetOffset(self):
|
||||
"""Get the offset of a property
|
||||
|
||||
Returns:
|
||||
The offset of the property (struct fdt_property) within the file
|
||||
"""
|
||||
return self._node._fdt.GetStructOffset(self._offset)
|
||||
|
||||
class Node(NodeBase):
|
||||
"""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):
|
||||
NodeBase.__init__(self, fdt, offset, name, path)
|
||||
|
||||
def Offset(self):
|
||||
"""Returns the offset of a node, after checking the cache
|
||||
|
||||
This should be used instead of self._offset directly, to ensure that
|
||||
the cache does not contain invalid offsets.
|
||||
"""
|
||||
self._fdt.CheckCache()
|
||||
return self._offset
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
def Refresh(self, my_offset):
|
||||
"""Fix up the _offset for each node, recursively
|
||||
|
||||
Note: This does not take account of property offsets - these will not
|
||||
be updated.
|
||||
"""
|
||||
if self._offset != my_offset:
|
||||
#print '%s: %d -> %d\n' % (self.path, self._offset, my_offset)
|
||||
self._offset = my_offset
|
||||
offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
|
||||
for subnode in self.subnodes:
|
||||
subnode.Refresh(offset)
|
||||
offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
|
||||
|
||||
def DeleteProp(self, prop_name):
|
||||
"""Delete a property of a node
|
||||
|
||||
The property is deleted and the offset cache is invalidated.
|
||||
|
||||
Args:
|
||||
prop_name: Name of the property to delete
|
||||
Raises:
|
||||
ValueError if the property does not exist
|
||||
"""
|
||||
CheckErr(libfdt.fdt_delprop(self._fdt.GetFdt(), self.Offset(), prop_name),
|
||||
"Node '%s': delete property: '%s'" % (self.path, prop_name))
|
||||
del self.props[prop_name]
|
||||
self._fdt.Invalidate()
|
||||
|
||||
class FdtNormal(Fdt):
|
||||
"""Provides simple access to a flat device tree blob using libfdt.
|
||||
|
||||
Properties:
|
||||
_fdt: Device tree contents (bytearray)
|
||||
_cached_offsets: True if all the nodes have a valid _offset property,
|
||||
False if something has changed to invalidate the offsets
|
||||
"""
|
||||
def __init__(self, fname):
|
||||
Fdt.__init__(self, fname)
|
||||
self._cached_offsets = False
|
||||
if self._fname:
|
||||
self._fname = fdt_util.EnsureCompiled(self._fname)
|
||||
|
||||
with open(self._fname) as fd:
|
||||
self._fdt = bytearray(fd.read())
|
||||
|
||||
def GetFdt(self):
|
||||
"""Get the contents of the FDT
|
||||
|
||||
Returns:
|
||||
The FDT contents as a string of bytes
|
||||
"""
|
||||
return self._fdt
|
||||
|
||||
def Flush(self):
|
||||
"""Flush device tree changes back to the file"""
|
||||
with open(self._fname, 'wb') as fd:
|
||||
fd.write(self._fdt)
|
||||
|
||||
def Pack(self):
|
||||
"""Pack the device tree down to its minimum size"""
|
||||
CheckErr(libfdt.fdt_pack(self._fdt), 'pack')
|
||||
fdt_len = libfdt.fdt_totalsize(self._fdt)
|
||||
del self._fdt[fdt_len:]
|
||||
|
||||
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.
|
||||
"""
|
||||
props_dict = {}
|
||||
poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset)
|
||||
while poffset >= 0:
|
||||
dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
|
||||
prop = Prop(node, poffset, 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
|
||||
|
||||
def Invalidate(self):
|
||||
"""Mark our offset cache as invalid"""
|
||||
self._cached_offsets = False
|
||||
|
||||
def CheckCache(self):
|
||||
"""Refresh the offset cache if needed"""
|
||||
if self._cached_offsets:
|
||||
return
|
||||
self.Refresh()
|
||||
self._cached_offsets = True
|
||||
|
||||
def Refresh(self):
|
||||
"""Refresh the offset cache"""
|
||||
self._root.Refresh(0)
|
||||
|
||||
def GetStructOffset(self, offset):
|
||||
"""Get the file offset of a given struct offset
|
||||
|
||||
Args:
|
||||
offset: Offset within the 'struct' region of the device tree
|
||||
Returns:
|
||||
Position of @offset within the device tree binary
|
||||
"""
|
||||
return libfdt.fdt_off_dt_struct(self._fdt) + offset
|
||||
|
||||
@classmethod
|
||||
def Node(self, fdt, offset, name, path):
|
||||
"""Create a new node
|
||||
|
||||
This is used by Fdt.Scan() to create a new node using the correct
|
||||
class.
|
||||
|
||||
Args:
|
||||
fdt: Fdt object
|
||||
offset: Offset of node
|
||||
name: Node name
|
||||
path: Full path to node
|
||||
"""
|
||||
node = Node(fdt, offset, name, path)
|
||||
return node
|
|
@ -1,36 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
import fdt_fallback
|
||||
|
||||
# Bring in either the normal fdt library (which relies on libfdt) or the
|
||||
# fallback one (which uses fdtget and is slower). Both provide the same
|
||||
# interface for this file to use.
|
||||
try:
|
||||
import fdt_normal
|
||||
have_libfdt = True
|
||||
except ImportError:
|
||||
have_libfdt = False
|
||||
|
||||
force_fallback = False
|
||||
|
||||
def FdtScan(fname, _force_fallback=False):
|
||||
"""Returns a new Fdt object from the implementation we are using"""
|
||||
if have_libfdt and not force_fallback and not _force_fallback:
|
||||
dtb = fdt_normal.FdtNormal(fname)
|
||||
else:
|
||||
dtb = fdt_fallback.FdtFallback(fname)
|
||||
dtb.Scan()
|
||||
return dtb
|
||||
|
||||
def UseFallback(fallback):
|
||||
global force_fallback
|
||||
|
||||
old_val = force_fallback
|
||||
force_fallback = fallback
|
||||
return old_val
|
Loading…
Reference in a new issue