ANDROID: Merge upstream ed310803ea
(v1.6.1)
Upgrade to the latest master from
git://git.kernel.org/pub/scm/utils/dtc/dtc.git.
at commit ed310803ea
.
Bug: 221191119
Bug: 222320399
Bug: 230794395
Bug: 234413190
Change-Id: I6cc623e217641d7db3d4f2c4873cda472da08ef4
This commit is contained in:
commit
9c26cc838f
81 changed files with 1691 additions and 576 deletions
|
@ -1,9 +1,9 @@
|
||||||
env:
|
env:
|
||||||
CIRRUS_CLONE_DEPTH: 1
|
CIRRUS_CLONE_DEPTH: 1
|
||||||
|
|
||||||
freebsd_12_task:
|
freebsd_13_task:
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image: freebsd-12-1-release-amd64
|
image: freebsd-13-0-release-amd64
|
||||||
install_script:
|
install_script:
|
||||||
pkg install -y bison gmake pkgconf
|
pkg install -y bison gmake pkgconf
|
||||||
build_script:
|
build_script:
|
||||||
|
|
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -8,6 +8,7 @@
|
||||||
*.tab.[ch]
|
*.tab.[ch]
|
||||||
lex.yy.c
|
lex.yy.c
|
||||||
*.lex.c
|
*.lex.c
|
||||||
|
.*.swp
|
||||||
/dtc
|
/dtc
|
||||||
/fdtdump
|
/fdtdump
|
||||||
/convert-dtsv0
|
/convert-dtsv0
|
||||||
|
@ -17,3 +18,11 @@ lex.yy.c
|
||||||
/fdtoverlay
|
/fdtoverlay
|
||||||
/patches
|
/patches
|
||||||
/.pc
|
/.pc
|
||||||
|
|
||||||
|
# cscope files
|
||||||
|
cscope.*
|
||||||
|
ncscope.*
|
||||||
|
|
||||||
|
.eggs/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
|
|
@ -45,7 +45,7 @@ The gitweb interface for the upstream repository is:
|
||||||
|
|
||||||
Patches should be sent to the maintainers:
|
Patches should be sent to the maintainers:
|
||||||
David Gibson <david@gibson.dropbear.id.au>
|
David Gibson <david@gibson.dropbear.id.au>
|
||||||
Jon Loeliger <jdl@jdl.com>
|
Jon Loeliger <loeliger@gmail.com>
|
||||||
and CCed to <devicetree-compiler@vger.kernel.org>.
|
and CCed to <devicetree-compiler@vger.kernel.org>.
|
||||||
|
|
||||||
2) Description
|
2) Description
|
||||||
|
@ -712,7 +712,7 @@ The syntax of the fdtget command is:
|
||||||
|
|
||||||
where options are:
|
where options are:
|
||||||
|
|
||||||
<type> s=string, i=int, u=unsigned, x=hex
|
<type> s=string, i=int, u=unsigned, x=hex, r=raw
|
||||||
Optional modifier prefix:
|
Optional modifier prefix:
|
||||||
hh or b=byte, h=2 byte, l=4 byte (default)
|
hh or b=byte, h=2 byte, l=4 byte (default)
|
||||||
|
|
||||||
|
|
11
MANIFEST.in
Normal file
11
MANIFEST.in
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||||
|
|
||||||
|
global-exclude *
|
||||||
|
include README
|
||||||
|
include GPL
|
||||||
|
include BSD-2-Clause
|
||||||
|
include setup.py
|
||||||
|
include pylibfdt/libfdt.i
|
||||||
|
include libfdt/libfdt.h
|
||||||
|
include libfdt/fdt.h
|
||||||
|
include libfdt/libfdt_env.h
|
5
Makefile
5
Makefile
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
VERSION = 1
|
VERSION = 1
|
||||||
PATCHLEVEL = 6
|
PATCHLEVEL = 6
|
||||||
SUBLEVEL = 0
|
SUBLEVEL = 1
|
||||||
EXTRAVERSION =
|
EXTRAVERSION =
|
||||||
LOCAL_VERSION =
|
LOCAL_VERSION =
|
||||||
CONFIG_LOCALVERSION =
|
CONFIG_LOCALVERSION =
|
||||||
|
@ -21,7 +21,7 @@ CONFIG_LOCALVERSION =
|
||||||
ASSUME_MASK ?= 0
|
ASSUME_MASK ?= 0
|
||||||
|
|
||||||
CPPFLAGS = -I libfdt -I . -DFDT_ASSUME_MASK=$(ASSUME_MASK)
|
CPPFLAGS = -I libfdt -I . -DFDT_ASSUME_MASK=$(ASSUME_MASK)
|
||||||
WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
|
WARNINGS = -Wall -Wpointer-arith -Wcast-qual -Wnested-externs -Wsign-compare \
|
||||||
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow
|
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow
|
||||||
CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS) $(EXTRA_CFLAGS)
|
CFLAGS = -g -Os $(SHAREDLIB_CFLAGS) -Werror $(WARNINGS) $(EXTRA_CFLAGS)
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ ifeq ($(NO_YAML),1)
|
||||||
CFLAGS += -DNO_YAML
|
CFLAGS += -DNO_YAML
|
||||||
else
|
else
|
||||||
LDLIBS_dtc += $(shell $(PKG_CONFIG) --libs yaml-0.1)
|
LDLIBS_dtc += $(shell $(PKG_CONFIG) --libs yaml-0.1)
|
||||||
|
CFLAGS += $(shell $(PKG_CONFIG) --cflags yaml-0.1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(HOSTOS),darwin)
|
ifeq ($(HOSTOS),darwin)
|
||||||
|
|
31
README
31
README
|
@ -5,7 +5,7 @@ utility library for reading and manipulating the binary format.
|
||||||
DTC and LIBFDT are maintained by:
|
DTC and LIBFDT are maintained by:
|
||||||
|
|
||||||
David Gibson <david@gibson.dropbear.id.au>
|
David Gibson <david@gibson.dropbear.id.au>
|
||||||
Jon Loeliger <jdl@jdl.com>
|
Jon Loeliger <loeliger@gmail.com>
|
||||||
|
|
||||||
|
|
||||||
Python library
|
Python library
|
||||||
|
@ -48,18 +48,24 @@ If you add new features, please check code coverage:
|
||||||
# Open 'htmlcov/index.html' in your browser
|
# Open 'htmlcov/index.html' in your browser
|
||||||
|
|
||||||
|
|
||||||
To install the library via the normal setup.py method, use:
|
The library can be installed with pip from a local source tree:
|
||||||
|
|
||||||
./pylibfdt/setup.py install [--prefix=/path/to/install_dir]
|
pip install . [--user|--prefix=/path/to/install_dir]
|
||||||
|
|
||||||
If --prefix is not provided, the default prefix is used, typically '/usr'
|
Or directly from a remote git repo:
|
||||||
or '/usr/local'. See Python's distutils documentation for details. You can
|
|
||||||
also install via the Makefile if you like, but the above is more common.
|
pip install git+git://git.kernel.org/pub/scm/utils/dtc/dtc.git@main
|
||||||
|
|
||||||
|
The install depends on libfdt shared library being installed on the host system
|
||||||
|
first. Generally, using --user or --prefix is not necessary and pip will use the
|
||||||
|
default location for the Python installation which varies if the user is root or
|
||||||
|
not.
|
||||||
|
|
||||||
|
You can also install everything via make if you like, but pip is recommended.
|
||||||
|
|
||||||
To install both libfdt and pylibfdt you can use:
|
To install both libfdt and pylibfdt you can use:
|
||||||
|
|
||||||
make install [SETUP_PREFIX=/path/to/install_dir] \
|
make install [PREFIX=/path/to/install_dir]
|
||||||
[PREFIX=/path/to/install_dir]
|
|
||||||
|
|
||||||
To disable building the python library, even if swig and Python are available,
|
To disable building the python library, even if swig and Python are available,
|
||||||
use:
|
use:
|
||||||
|
@ -71,6 +77,15 @@ More work remains to support all of libfdt, including access to numeric
|
||||||
values.
|
values.
|
||||||
|
|
||||||
|
|
||||||
|
Adding a new function to libfdt.h
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
The shared library uses libfdt/version.lds to list the exported functions, so
|
||||||
|
add your new function there. Check that your function works with pylibfdt. If
|
||||||
|
it cannot be supported, put the declaration in libfdt.h behind #ifndef SWIG so
|
||||||
|
that swig ignores it.
|
||||||
|
|
||||||
|
|
||||||
Tests
|
Tests
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
235
checks.c
235
checks.c
|
@ -143,6 +143,14 @@ static void check_nodes_props(struct check *c, struct dt_info *dti, struct node
|
||||||
check_nodes_props(c, dti, child);
|
check_nodes_props(c, dti, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_multiple_of(int multiple, int divisor)
|
||||||
|
{
|
||||||
|
if (divisor == 0)
|
||||||
|
return multiple == 0;
|
||||||
|
else
|
||||||
|
return (multiple % divisor) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool run_check(struct check *c, struct dt_info *dti)
|
static bool run_check(struct check *c, struct dt_info *dti)
|
||||||
{
|
{
|
||||||
struct node *dt = dti->dt;
|
struct node *dt = dti->dt;
|
||||||
|
@ -297,19 +305,20 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
|
||||||
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
|
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
|
||||||
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
#define DIGITS "0123456789"
|
#define DIGITS "0123456789"
|
||||||
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
|
#define NODECHARS LOWERCASE UPPERCASE DIGITS ",._+-@"
|
||||||
|
#define PROPCHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
|
||||||
#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-"
|
#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-"
|
||||||
|
|
||||||
static void check_node_name_chars(struct check *c, struct dt_info *dti,
|
static void check_node_name_chars(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
int n = strspn(node->name, c->data);
|
size_t n = strspn(node->name, c->data);
|
||||||
|
|
||||||
if (n < strlen(node->name))
|
if (n < strlen(node->name))
|
||||||
FAIL(c, dti, node, "Bad character '%c' in node name",
|
FAIL(c, dti, node, "Bad character '%c' in node name",
|
||||||
node->name[n]);
|
node->name[n]);
|
||||||
}
|
}
|
||||||
ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
|
ERROR(node_name_chars, check_node_name_chars, NODECHARS);
|
||||||
|
|
||||||
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
|
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
|
@ -330,6 +339,20 @@ static void check_node_name_format(struct check *c, struct dt_info *dti,
|
||||||
}
|
}
|
||||||
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
|
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
|
||||||
|
|
||||||
|
static void check_node_name_vs_property_name(struct check *c,
|
||||||
|
struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
if (!node->parent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (get_property(node->parent, node->name)) {
|
||||||
|
FAIL(c, dti, node, "node name and property name conflict");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WARNING(node_name_vs_property_name, check_node_name_vs_property_name,
|
||||||
|
NULL, &node_name_chars);
|
||||||
|
|
||||||
static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
|
static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
|
@ -363,14 +386,14 @@ static void check_property_name_chars(struct check *c, struct dt_info *dti,
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
|
||||||
for_each_property(node, prop) {
|
for_each_property(node, prop) {
|
||||||
int n = strspn(prop->name, c->data);
|
size_t n = strspn(prop->name, c->data);
|
||||||
|
|
||||||
if (n < strlen(prop->name))
|
if (n < strlen(prop->name))
|
||||||
FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name",
|
FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name",
|
||||||
prop->name[n]);
|
prop->name[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
|
ERROR(property_name_chars, check_property_name_chars, PROPCHARS);
|
||||||
|
|
||||||
static void check_property_name_chars_strict(struct check *c,
|
static void check_property_name_chars_strict(struct check *c,
|
||||||
struct dt_info *dti,
|
struct dt_info *dti,
|
||||||
|
@ -380,7 +403,7 @@ static void check_property_name_chars_strict(struct check *c,
|
||||||
|
|
||||||
for_each_property(node, prop) {
|
for_each_property(node, prop) {
|
||||||
const char *name = prop->name;
|
const char *name = prop->name;
|
||||||
int n = strspn(name, c->data);
|
size_t n = strspn(name, c->data);
|
||||||
|
|
||||||
if (n == strlen(prop->name))
|
if (n == strlen(prop->name))
|
||||||
continue;
|
continue;
|
||||||
|
@ -497,7 +520,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
|
||||||
|
|
||||||
phandle = propval_cell(prop);
|
phandle = propval_cell(prop);
|
||||||
|
|
||||||
if ((phandle == 0) || (phandle == -1)) {
|
if (!phandle_is_valid(phandle)) {
|
||||||
FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property",
|
FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property",
|
||||||
phandle, prop->name);
|
phandle, prop->name);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -556,7 +579,7 @@ static void check_name_properties(struct check *c, struct dt_info *dti,
|
||||||
if (!prop)
|
if (!prop)
|
||||||
return; /* No name property, that's fine */
|
return; /* No name property, that's fine */
|
||||||
|
|
||||||
if ((prop->val.len != node->basenamelen+1)
|
if ((prop->val.len != node->basenamelen + 1U)
|
||||||
|| (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
|
|| (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
|
||||||
FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead"
|
FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead"
|
||||||
" of base node name)", prop->val.val);
|
" of base node name)", prop->val.val);
|
||||||
|
@ -657,7 +680,6 @@ ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &pa
|
||||||
*/
|
*/
|
||||||
WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
|
WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
|
||||||
WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
|
WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
|
||||||
WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
|
|
||||||
|
|
||||||
WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
|
WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
|
||||||
WARNING_IF_NOT_STRING(model_is_string, "model");
|
WARNING_IF_NOT_STRING(model_is_string, "model");
|
||||||
|
@ -672,8 +694,7 @@ static void check_names_is_string_list(struct check *c, struct dt_info *dti,
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
|
||||||
for_each_property(node, prop) {
|
for_each_property(node, prop) {
|
||||||
const char *s = strrchr(prop->name, '-');
|
if (!strends(prop->name, "-names"))
|
||||||
if (!s || !streq(s, "-names"))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
c->data = prop->name;
|
c->data = prop->name;
|
||||||
|
@ -753,7 +774,7 @@ static void check_reg_format(struct check *c, struct dt_info *dti,
|
||||||
size_cells = node_size_cells(node->parent);
|
size_cells = node_size_cells(node->parent);
|
||||||
entrylen = (addr_cells + size_cells) * sizeof(cell_t);
|
entrylen = (addr_cells + size_cells) * sizeof(cell_t);
|
||||||
|
|
||||||
if (!entrylen || (prop->val.len % entrylen) != 0)
|
if (!is_multiple_of(prop->val.len, entrylen))
|
||||||
FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) "
|
FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) "
|
||||||
"(#address-cells == %d, #size-cells == %d)",
|
"(#address-cells == %d, #size-cells == %d)",
|
||||||
prop->val.len, addr_cells, size_cells);
|
prop->val.len, addr_cells, size_cells);
|
||||||
|
@ -794,7 +815,7 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
|
||||||
"#size-cells (%d) differs from %s (%d)",
|
"#size-cells (%d) differs from %s (%d)",
|
||||||
ranges, c_size_cells, node->parent->fullpath,
|
ranges, c_size_cells, node->parent->fullpath,
|
||||||
p_size_cells);
|
p_size_cells);
|
||||||
} else if ((prop->val.len % entrylen) != 0) {
|
} else if (!is_multiple_of(prop->val.len, entrylen)) {
|
||||||
FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) "
|
FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) "
|
||||||
"(parent #address-cells == %d, child #address-cells == %d, "
|
"(parent #address-cells == %d, child #address-cells == %d, "
|
||||||
"#size-cells == %d)", ranges, prop->val.len,
|
"#size-cells == %d)", ranges, prop->val.len,
|
||||||
|
@ -871,7 +892,7 @@ static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struc
|
||||||
} else {
|
} else {
|
||||||
cells = (cell_t *)prop->val.val;
|
cells = (cell_t *)prop->val.val;
|
||||||
min_bus = fdt32_to_cpu(cells[0]);
|
min_bus = fdt32_to_cpu(cells[0]);
|
||||||
max_bus = fdt32_to_cpu(cells[0]);
|
max_bus = fdt32_to_cpu(cells[1]);
|
||||||
}
|
}
|
||||||
if ((bus_num < min_bus) || (bus_num > max_bus))
|
if ((bus_num < min_bus) || (bus_num > max_bus))
|
||||||
FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)",
|
FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)",
|
||||||
|
@ -891,10 +912,8 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no
|
||||||
return;
|
return;
|
||||||
|
|
||||||
prop = get_property(node, "reg");
|
prop = get_property(node, "reg");
|
||||||
if (!prop) {
|
if (!prop)
|
||||||
FAIL(c, dti, node, "missing PCI reg property");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
cells = (cell_t *)prop->val.val;
|
cells = (cell_t *)prop->val.val;
|
||||||
if (cells[1] || cells[2])
|
if (cells[1] || cells[2])
|
||||||
|
@ -1369,9 +1388,9 @@ static void check_property_phandle_args(struct check *c,
|
||||||
const struct provider *provider)
|
const struct provider *provider)
|
||||||
{
|
{
|
||||||
struct node *root = dti->dt;
|
struct node *root = dti->dt;
|
||||||
int cell, cellsize = 0;
|
unsigned int cell, cellsize = 0;
|
||||||
|
|
||||||
if (prop->val.len % sizeof(cell_t)) {
|
if (!is_multiple_of(prop->val.len, sizeof(cell_t))) {
|
||||||
FAIL_PROP(c, dti, node, prop,
|
FAIL_PROP(c, dti, node, prop,
|
||||||
"property size (%d) is invalid, expected multiple of %zu",
|
"property size (%d) is invalid, expected multiple of %zu",
|
||||||
prop->val.len, sizeof(cell_t));
|
prop->val.len, sizeof(cell_t));
|
||||||
|
@ -1381,14 +1400,15 @@ static void check_property_phandle_args(struct check *c,
|
||||||
for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) {
|
for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) {
|
||||||
struct node *provider_node;
|
struct node *provider_node;
|
||||||
struct property *cellprop;
|
struct property *cellprop;
|
||||||
int phandle;
|
cell_t phandle;
|
||||||
|
unsigned int expected;
|
||||||
|
|
||||||
phandle = propval_cell_n(prop, cell);
|
phandle = propval_cell_n(prop, cell);
|
||||||
/*
|
/*
|
||||||
* Some bindings use a cell value 0 or -1 to skip over optional
|
* Some bindings use a cell value 0 or -1 to skip over optional
|
||||||
* entries when each index position has a specific definition.
|
* entries when each index position has a specific definition.
|
||||||
*/
|
*/
|
||||||
if (phandle == 0 || phandle == -1) {
|
if (!phandle_is_valid(phandle)) {
|
||||||
/* Give up if this is an overlay with external references */
|
/* Give up if this is an overlay with external references */
|
||||||
if (dti->dtsflags & DTSF_PLUGIN)
|
if (dti->dtsflags & DTSF_PLUGIN)
|
||||||
break;
|
break;
|
||||||
|
@ -1431,10 +1451,12 @@ static void check_property_phandle_args(struct check *c,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) {
|
expected = (cell + cellsize + 1) * sizeof(cell_t);
|
||||||
|
if ((expected <= cell) || prop->val.len < expected) {
|
||||||
FAIL_PROP(c, dti, node, prop,
|
FAIL_PROP(c, dti, node, prop,
|
||||||
"property size (%d) too small for cell size %d",
|
"property size (%d) too small for cell size %u",
|
||||||
prop->val.len, cellsize);
|
prop->val.len, cellsize);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1454,7 +1476,8 @@ static void check_provider_cells_property(struct check *c,
|
||||||
}
|
}
|
||||||
#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
|
#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
|
||||||
static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
|
static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
|
||||||
WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references);
|
WARNING_IF_NOT_CELL(nm##_is_cell, cells_name); \
|
||||||
|
WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &nm##_is_cell, &phandle_references);
|
||||||
|
|
||||||
WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells");
|
WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells");
|
||||||
WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells");
|
WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells");
|
||||||
|
@ -1475,24 +1498,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sen
|
||||||
|
|
||||||
static bool prop_is_gpio(struct property *prop)
|
static bool prop_is_gpio(struct property *prop)
|
||||||
{
|
{
|
||||||
char *str;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* *-gpios and *-gpio can appear in property names,
|
* *-gpios and *-gpio can appear in property names,
|
||||||
* so skip over any false matches (only one known ATM)
|
* so skip over any false matches (only one known ATM)
|
||||||
*/
|
*/
|
||||||
if (strstr(prop->name, "nr-gpio"))
|
if (strends(prop->name, ",nr-gpios"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
str = strrchr(prop->name, '-');
|
return strends(prop->name, "-gpios") ||
|
||||||
if (str)
|
streq(prop->name, "gpios") ||
|
||||||
str++;
|
strends(prop->name, "-gpio") ||
|
||||||
else
|
streq(prop->name, "gpio");
|
||||||
str = prop->name;
|
|
||||||
if (!(streq(str, "gpios") || streq(str, "gpio")))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_gpios_property(struct check *c,
|
static void check_gpios_property(struct check *c,
|
||||||
|
@ -1527,13 +1543,10 @@ static void check_deprecated_gpio_property(struct check *c,
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
|
||||||
for_each_property(node, prop) {
|
for_each_property(node, prop) {
|
||||||
char *str;
|
|
||||||
|
|
||||||
if (!prop_is_gpio(prop))
|
if (!prop_is_gpio(prop))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
str = strstr(prop->name, "gpio");
|
if (!strends(prop->name, "gpio"))
|
||||||
if (!streq(str, "gpio"))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
FAIL_PROP(c, dti, node, prop,
|
FAIL_PROP(c, dti, node, prop,
|
||||||
|
@ -1563,21 +1576,106 @@ static void check_interrupt_provider(struct check *c,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
bool irq_provider = node_is_interrupt_provider(node);
|
||||||
if (!node_is_interrupt_provider(node))
|
|
||||||
return;
|
|
||||||
|
|
||||||
prop = get_property(node, "#interrupt-cells");
|
prop = get_property(node, "#interrupt-cells");
|
||||||
if (!prop)
|
if (irq_provider && !prop) {
|
||||||
FAIL(c, dti, node,
|
FAIL(c, dti, node,
|
||||||
"Missing #interrupt-cells in interrupt provider");
|
"Missing '#interrupt-cells' in interrupt provider");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
prop = get_property(node, "#address-cells");
|
if (!irq_provider && prop) {
|
||||||
if (!prop)
|
|
||||||
FAIL(c, dti, node,
|
FAIL(c, dti, node,
|
||||||
"Missing #address-cells in interrupt provider");
|
"'#interrupt-cells' found, but node is not an interrupt provider");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WARNING(interrupt_provider, check_interrupt_provider, NULL);
|
WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell);
|
||||||
|
|
||||||
|
static void check_interrupt_map(struct check *c,
|
||||||
|
struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
struct node *root = dti->dt;
|
||||||
|
struct property *prop, *irq_map_prop;
|
||||||
|
size_t cellsize, cell, map_cells;
|
||||||
|
|
||||||
|
irq_map_prop = get_property(node, "interrupt-map");
|
||||||
|
if (!irq_map_prop)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (node->addr_cells < 0) {
|
||||||
|
FAIL(c, dti, node,
|
||||||
|
"Missing '#address-cells' in interrupt-map provider");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cellsize = node_addr_cells(node);
|
||||||
|
cellsize += propval_cell(get_property(node, "#interrupt-cells"));
|
||||||
|
|
||||||
|
prop = get_property(node, "interrupt-map-mask");
|
||||||
|
if (prop && (prop->val.len != (cellsize * sizeof(cell_t))))
|
||||||
|
FAIL_PROP(c, dti, node, prop,
|
||||||
|
"property size (%d) is invalid, expected %zu",
|
||||||
|
prop->val.len, cellsize * sizeof(cell_t));
|
||||||
|
|
||||||
|
if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) {
|
||||||
|
FAIL_PROP(c, dti, node, irq_map_prop,
|
||||||
|
"property size (%d) is invalid, expected multiple of %zu",
|
||||||
|
irq_map_prop->val.len, sizeof(cell_t));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_cells = irq_map_prop->val.len / sizeof(cell_t);
|
||||||
|
for (cell = 0; cell < map_cells; ) {
|
||||||
|
struct node *provider_node;
|
||||||
|
struct property *cellprop;
|
||||||
|
int phandle;
|
||||||
|
size_t parent_cellsize;
|
||||||
|
|
||||||
|
if ((cell + cellsize) >= map_cells) {
|
||||||
|
FAIL_PROP(c, dti, node, irq_map_prop,
|
||||||
|
"property size (%d) too small, expected > %zu",
|
||||||
|
irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cell += cellsize;
|
||||||
|
|
||||||
|
phandle = propval_cell_n(irq_map_prop, cell);
|
||||||
|
if (!phandle_is_valid(phandle)) {
|
||||||
|
/* Give up if this is an overlay with external references */
|
||||||
|
if (!(dti->dtsflags & DTSF_PLUGIN))
|
||||||
|
FAIL_PROP(c, dti, node, irq_map_prop,
|
||||||
|
"Cell %zu is not a phandle(%d)",
|
||||||
|
cell, phandle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
provider_node = get_node_by_phandle(root, phandle);
|
||||||
|
if (!provider_node) {
|
||||||
|
FAIL_PROP(c, dti, node, irq_map_prop,
|
||||||
|
"Could not get phandle(%d) node for (cell %zu)",
|
||||||
|
phandle, cell);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cellprop = get_property(provider_node, "#interrupt-cells");
|
||||||
|
if (cellprop) {
|
||||||
|
parent_cellsize = propval_cell(cellprop);
|
||||||
|
} else {
|
||||||
|
FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])",
|
||||||
|
provider_node->fullpath, cell);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cellprop = get_property(provider_node, "#address-cells");
|
||||||
|
if (cellprop)
|
||||||
|
parent_cellsize += propval_cell(cellprop);
|
||||||
|
|
||||||
|
cell += 1 + parent_cellsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider);
|
||||||
|
|
||||||
static void check_interrupts_property(struct check *c,
|
static void check_interrupts_property(struct check *c,
|
||||||
struct dt_info *dti,
|
struct dt_info *dti,
|
||||||
|
@ -1586,13 +1684,13 @@ static void check_interrupts_property(struct check *c,
|
||||||
struct node *root = dti->dt;
|
struct node *root = dti->dt;
|
||||||
struct node *irq_node = NULL, *parent = node;
|
struct node *irq_node = NULL, *parent = node;
|
||||||
struct property *irq_prop, *prop = NULL;
|
struct property *irq_prop, *prop = NULL;
|
||||||
int irq_cells, phandle;
|
cell_t irq_cells, phandle;
|
||||||
|
|
||||||
irq_prop = get_property(node, "interrupts");
|
irq_prop = get_property(node, "interrupts");
|
||||||
if (!irq_prop)
|
if (!irq_prop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (irq_prop->val.len % sizeof(cell_t))
|
if (!is_multiple_of(irq_prop->val.len, sizeof(cell_t)))
|
||||||
FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu",
|
FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu",
|
||||||
irq_prop->val.len, sizeof(cell_t));
|
irq_prop->val.len, sizeof(cell_t));
|
||||||
|
|
||||||
|
@ -1605,7 +1703,7 @@ static void check_interrupts_property(struct check *c,
|
||||||
prop = get_property(parent, "interrupt-parent");
|
prop = get_property(parent, "interrupt-parent");
|
||||||
if (prop) {
|
if (prop) {
|
||||||
phandle = propval_cell(prop);
|
phandle = propval_cell(prop);
|
||||||
if ((phandle == 0) || (phandle == -1)) {
|
if (!phandle_is_valid(phandle)) {
|
||||||
/* Give up if this is an overlay with
|
/* Give up if this is an overlay with
|
||||||
* external references */
|
* external references */
|
||||||
if (dti->dtsflags & DTSF_PLUGIN)
|
if (dti->dtsflags & DTSF_PLUGIN)
|
||||||
|
@ -1641,7 +1739,7 @@ static void check_interrupts_property(struct check *c,
|
||||||
}
|
}
|
||||||
|
|
||||||
irq_cells = propval_cell(prop);
|
irq_cells = propval_cell(prop);
|
||||||
if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) {
|
if (!is_multiple_of(irq_prop->val.len, irq_cells * sizeof(cell_t))) {
|
||||||
FAIL_PROP(c, dti, node, prop,
|
FAIL_PROP(c, dti, node, prop,
|
||||||
"size is (%d), expected multiple of %d",
|
"size is (%d), expected multiple of %d",
|
||||||
irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)));
|
irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)));
|
||||||
|
@ -1752,7 +1850,7 @@ WARNING(graph_port, check_graph_port, NULL, &graph_nodes);
|
||||||
static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
|
static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
|
||||||
struct node *endpoint)
|
struct node *endpoint)
|
||||||
{
|
{
|
||||||
int phandle;
|
cell_t phandle;
|
||||||
struct node *node;
|
struct node *node;
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
|
|
||||||
|
@ -1762,7 +1860,7 @@ static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
|
||||||
|
|
||||||
phandle = propval_cell(prop);
|
phandle = propval_cell(prop);
|
||||||
/* Give up if this is an overlay with external references */
|
/* Give up if this is an overlay with external references */
|
||||||
if (phandle == 0 || phandle == -1)
|
if (!phandle_is_valid(phandle))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node = get_node_by_phandle(dti->dt, phandle);
|
node = get_node_by_phandle(dti->dt, phandle);
|
||||||
|
@ -1798,7 +1896,7 @@ WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
|
||||||
static struct check *check_table[] = {
|
static struct check *check_table[] = {
|
||||||
&duplicate_node_names, &duplicate_property_names,
|
&duplicate_node_names, &duplicate_property_names,
|
||||||
&node_name_chars, &node_name_format, &property_name_chars,
|
&node_name_chars, &node_name_format, &property_name_chars,
|
||||||
&name_is_string, &name_properties,
|
&name_is_string, &name_properties, &node_name_vs_property_name,
|
||||||
|
|
||||||
&duplicate_label,
|
&duplicate_label,
|
||||||
|
|
||||||
|
@ -1806,7 +1904,7 @@ static struct check *check_table[] = {
|
||||||
&phandle_references, &path_references,
|
&phandle_references, &path_references,
|
||||||
&omit_unused_nodes,
|
&omit_unused_nodes,
|
||||||
|
|
||||||
&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
|
&address_cells_is_cell, &size_cells_is_cell,
|
||||||
&device_type_is_string, &model_is_string, &status_is_string,
|
&device_type_is_string, &model_is_string, &status_is_string,
|
||||||
&label_is_string,
|
&label_is_string,
|
||||||
|
|
||||||
|
@ -1841,26 +1939,43 @@ static struct check *check_table[] = {
|
||||||
&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
|
&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
|
||||||
|
|
||||||
&clocks_property,
|
&clocks_property,
|
||||||
|
&clocks_is_cell,
|
||||||
&cooling_device_property,
|
&cooling_device_property,
|
||||||
|
&cooling_device_is_cell,
|
||||||
&dmas_property,
|
&dmas_property,
|
||||||
|
&dmas_is_cell,
|
||||||
&hwlocks_property,
|
&hwlocks_property,
|
||||||
|
&hwlocks_is_cell,
|
||||||
&interrupts_extended_property,
|
&interrupts_extended_property,
|
||||||
|
&interrupts_extended_is_cell,
|
||||||
&io_channels_property,
|
&io_channels_property,
|
||||||
|
&io_channels_is_cell,
|
||||||
&iommus_property,
|
&iommus_property,
|
||||||
|
&iommus_is_cell,
|
||||||
&mboxes_property,
|
&mboxes_property,
|
||||||
|
&mboxes_is_cell,
|
||||||
&msi_parent_property,
|
&msi_parent_property,
|
||||||
|
&msi_parent_is_cell,
|
||||||
&mux_controls_property,
|
&mux_controls_property,
|
||||||
|
&mux_controls_is_cell,
|
||||||
&phys_property,
|
&phys_property,
|
||||||
|
&phys_is_cell,
|
||||||
&power_domains_property,
|
&power_domains_property,
|
||||||
|
&power_domains_is_cell,
|
||||||
&pwms_property,
|
&pwms_property,
|
||||||
|
&pwms_is_cell,
|
||||||
&resets_property,
|
&resets_property,
|
||||||
|
&resets_is_cell,
|
||||||
&sound_dai_property,
|
&sound_dai_property,
|
||||||
|
&sound_dai_is_cell,
|
||||||
&thermal_sensors_property,
|
&thermal_sensors_property,
|
||||||
|
&thermal_sensors_is_cell,
|
||||||
|
|
||||||
&deprecated_gpio_property,
|
&deprecated_gpio_property,
|
||||||
&gpios_property,
|
&gpios_property,
|
||||||
&interrupts_property,
|
&interrupts_property,
|
||||||
&interrupt_provider,
|
&interrupt_provider,
|
||||||
|
&interrupt_map,
|
||||||
|
|
||||||
&alias_paths,
|
&alias_paths,
|
||||||
|
|
||||||
|
@ -1884,7 +1999,7 @@ static void enable_warning_error(struct check *c, bool warn, bool error)
|
||||||
|
|
||||||
static void disable_warning_error(struct check *c, bool warn, bool error)
|
static void disable_warning_error(struct check *c, bool warn, bool error)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* Lowering level, also lower it for things this is the prereq
|
/* Lowering level, also lower it for things this is the prereq
|
||||||
* for */
|
* for */
|
||||||
|
@ -1905,7 +2020,7 @@ static void disable_warning_error(struct check *c, bool warn, bool error)
|
||||||
|
|
||||||
void parse_checks_option(bool warn, bool error, const char *arg)
|
void parse_checks_option(bool warn, bool error, const char *arg)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
const char *name = arg;
|
const char *name = arg;
|
||||||
bool enable = true;
|
bool enable = true;
|
||||||
|
|
||||||
|
@ -1932,7 +2047,7 @@ void parse_checks_option(bool warn, bool error, const char *arg)
|
||||||
|
|
||||||
void process_checks(bool force, struct dt_info *dti)
|
void process_checks(bool force, struct dt_info *dti)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
|
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
|
||||||
|
|
|
@ -94,7 +94,7 @@ static const struct {
|
||||||
<INITIAL>[0-9a-fA-F]+ {
|
<INITIAL>[0-9a-fA-F]+ {
|
||||||
unsigned long long val;
|
unsigned long long val;
|
||||||
int obase = 16, width = 0;
|
int obase = 16, width = 0;
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
val = strtoull(yytext, NULL, cbase);
|
val = strtoull(yytext, NULL, cbase);
|
||||||
|
|
||||||
|
|
6
data.c
6
data.c
|
@ -21,10 +21,10 @@ void data_free(struct data d)
|
||||||
free(d.val);
|
free(d.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct data data_grow_for(struct data d, int xlen)
|
struct data data_grow_for(struct data d, unsigned int xlen)
|
||||||
{
|
{
|
||||||
struct data nd;
|
struct data nd;
|
||||||
int newsize;
|
unsigned int newsize;
|
||||||
|
|
||||||
if (xlen == 0)
|
if (xlen == 0)
|
||||||
return d;
|
return d;
|
||||||
|
@ -84,7 +84,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
|
||||||
while (!feof(f) && (d.len < maxlen)) {
|
while (!feof(f) && (d.len < maxlen)) {
|
||||||
size_t chunksize, ret;
|
size_t chunksize, ret;
|
||||||
|
|
||||||
if (maxlen == -1)
|
if (maxlen == (size_t)-1)
|
||||||
chunksize = 4096;
|
chunksize = 4096;
|
||||||
else
|
else
|
||||||
chunksize = maxlen - d.len;
|
chunksize = maxlen - d.len;
|
||||||
|
|
|
@ -57,7 +57,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
|
||||||
push_input_file(name);
|
push_input_file(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
|
<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* {
|
||||||
char *line, *fnstart, *fnend;
|
char *line, *fnstart, *fnend;
|
||||||
struct data fn;
|
struct data fn;
|
||||||
/* skip text before line # */
|
/* skip text before line # */
|
||||||
|
@ -200,7 +200,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
|
||||||
return DT_LABEL_REF;
|
return DT_LABEL_REF;
|
||||||
}
|
}
|
||||||
|
|
||||||
<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
|
<*>"&{"{PATHCHAR}*\} { /* new-style path reference */
|
||||||
yytext[yyleng-1] = '\0';
|
yytext[yyleng-1] = '\0';
|
||||||
DPRINT("Ref: %s\n", yytext+2);
|
DPRINT("Ref: %s\n", yytext+2);
|
||||||
yylval.labelref = xstrdup(yytext+2);
|
yylval.labelref = xstrdup(yytext+2);
|
||||||
|
|
17
dtc-parser.y
17
dtc-parser.y
|
@ -23,6 +23,12 @@ extern void yyerror(char const *s);
|
||||||
|
|
||||||
extern struct dt_info *parser_output;
|
extern struct dt_info *parser_output;
|
||||||
extern bool treesource_error;
|
extern bool treesource_error;
|
||||||
|
|
||||||
|
static bool is_ref_relative(const char *ref)
|
||||||
|
{
|
||||||
|
return ref[0] != '/' && strchr(&ref[1], '/');
|
||||||
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
|
@ -169,6 +175,8 @@ devicetree:
|
||||||
*/
|
*/
|
||||||
if (!($<flags>-1 & DTSF_PLUGIN))
|
if (!($<flags>-1 & DTSF_PLUGIN))
|
||||||
ERROR(&@2, "Label or path %s not found", $1);
|
ERROR(&@2, "Label or path %s not found", $1);
|
||||||
|
else if (is_ref_relative($1))
|
||||||
|
ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
|
||||||
$$ = add_orphan_node(
|
$$ = add_orphan_node(
|
||||||
name_node(build_node(NULL, NULL, NULL),
|
name_node(build_node(NULL, NULL, NULL),
|
||||||
""),
|
""),
|
||||||
|
@ -178,6 +186,9 @@ devicetree:
|
||||||
{
|
{
|
||||||
struct node *target = get_node_by_ref($1, $3);
|
struct node *target = get_node_by_ref($1, $3);
|
||||||
|
|
||||||
|
if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3))
|
||||||
|
ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
add_label(&target->labels, $2);
|
add_label(&target->labels, $2);
|
||||||
merge_nodes(target, $4);
|
merge_nodes(target, $4);
|
||||||
|
@ -193,6 +204,8 @@ devicetree:
|
||||||
* so $-1 is what we want (plugindecl)
|
* so $-1 is what we want (plugindecl)
|
||||||
*/
|
*/
|
||||||
if ($<flags>-1 & DTSF_PLUGIN) {
|
if ($<flags>-1 & DTSF_PLUGIN) {
|
||||||
|
if (is_ref_relative($2))
|
||||||
|
ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
|
||||||
add_orphan_node($1, $3, $2);
|
add_orphan_node($1, $3, $2);
|
||||||
} else {
|
} else {
|
||||||
struct node *target = get_node_by_ref($1, $2);
|
struct node *target = get_node_by_ref($1, $2);
|
||||||
|
@ -481,8 +494,8 @@ integer_rela:
|
||||||
;
|
;
|
||||||
|
|
||||||
integer_shift:
|
integer_shift:
|
||||||
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
|
integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; }
|
||||||
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
|
| integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; }
|
||||||
| integer_add
|
| integer_add
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
6
dtc.c
6
dtc.c
|
@ -12,7 +12,7 @@
|
||||||
* Command line options
|
* Command line options
|
||||||
*/
|
*/
|
||||||
int quiet; /* Level of quietness */
|
int quiet; /* Level of quietness */
|
||||||
int reservenum; /* Number of memory reservation slots */
|
unsigned int reservenum;/* Number of memory reservation slots */
|
||||||
int minsize; /* Minimum blob size */
|
int minsize; /* Minimum blob size */
|
||||||
int padsize; /* Additional padding to blob */
|
int padsize; /* Additional padding to blob */
|
||||||
int alignsize; /* Additional padding to blob accroding to the alignsize */
|
int alignsize; /* Additional padding to blob accroding to the alignsize */
|
||||||
|
@ -122,6 +122,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
|
||||||
return "dts";
|
return "dts";
|
||||||
if (!strcasecmp(s, ".yaml"))
|
if (!strcasecmp(s, ".yaml"))
|
||||||
return "yaml";
|
return "yaml";
|
||||||
|
if (!strcasecmp(s, ".dtbo"))
|
||||||
|
return "dtb";
|
||||||
if (!strcasecmp(s, ".dtb"))
|
if (!strcasecmp(s, ".dtb"))
|
||||||
return "dtb";
|
return "dtb";
|
||||||
return fallback;
|
return fallback;
|
||||||
|
@ -195,7 +197,7 @@ int main(int argc, char *argv[])
|
||||||
depname = optarg;
|
depname = optarg;
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
reservenum = strtol(optarg, NULL, 0);
|
reservenum = strtoul(optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
minsize = strtol(optarg, NULL, 0);
|
minsize = strtol(optarg, NULL, 0);
|
||||||
|
|
48
dtc.h
48
dtc.h
|
@ -35,7 +35,7 @@
|
||||||
* Command line options
|
* Command line options
|
||||||
*/
|
*/
|
||||||
extern int quiet; /* Level of quietness */
|
extern int quiet; /* Level of quietness */
|
||||||
extern int reservenum; /* Number of memory reservation slots */
|
extern unsigned int reservenum; /* Number of memory reservation slots */
|
||||||
extern int minsize; /* Minimum blob size */
|
extern int minsize; /* Minimum blob size */
|
||||||
extern int padsize; /* Additional padding to blob */
|
extern int padsize; /* Additional padding to blob */
|
||||||
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
|
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
|
||||||
|
@ -51,6 +51,11 @@ extern int annotate; /* annotate .dts with input source location */
|
||||||
|
|
||||||
typedef uint32_t cell_t;
|
typedef uint32_t cell_t;
|
||||||
|
|
||||||
|
static inline bool phandle_is_valid(cell_t phandle)
|
||||||
|
{
|
||||||
|
return phandle != 0 && phandle != ~0U;
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint16_t dtb_ld16(const void *p)
|
static inline uint16_t dtb_ld16(const void *p)
|
||||||
{
|
{
|
||||||
const uint8_t *bp = (const uint8_t *)p;
|
const uint8_t *bp = (const uint8_t *)p;
|
||||||
|
@ -86,6 +91,16 @@ static inline uint64_t dtb_ld64(const void *p)
|
||||||
#define streq(a, b) (strcmp((a), (b)) == 0)
|
#define streq(a, b) (strcmp((a), (b)) == 0)
|
||||||
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
|
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
|
||||||
#define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0))
|
#define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0))
|
||||||
|
static inline bool strends(const char *str, const char *suffix)
|
||||||
|
{
|
||||||
|
unsigned int len, suffix_len;
|
||||||
|
|
||||||
|
len = strlen(str);
|
||||||
|
suffix_len = strlen(suffix);
|
||||||
|
if (len < suffix_len)
|
||||||
|
return false;
|
||||||
|
return streq(str + len - suffix_len, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||||
|
|
||||||
|
@ -101,17 +116,23 @@ enum markertype {
|
||||||
TYPE_UINT64,
|
TYPE_UINT64,
|
||||||
TYPE_STRING,
|
TYPE_STRING,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline bool is_type_marker(enum markertype type)
|
||||||
|
{
|
||||||
|
return type >= TYPE_UINT8;
|
||||||
|
}
|
||||||
|
|
||||||
extern const char *markername(enum markertype markertype);
|
extern const char *markername(enum markertype markertype);
|
||||||
|
|
||||||
struct marker {
|
struct marker {
|
||||||
enum markertype type;
|
enum markertype type;
|
||||||
int offset;
|
unsigned int offset;
|
||||||
char *ref;
|
char *ref;
|
||||||
struct marker *next;
|
struct marker *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct data {
|
struct data {
|
||||||
int len;
|
unsigned int len;
|
||||||
char *val;
|
char *val;
|
||||||
struct marker *markers;
|
struct marker *markers;
|
||||||
};
|
};
|
||||||
|
@ -125,11 +146,26 @@ struct data {
|
||||||
for_each_marker(m) \
|
for_each_marker(m) \
|
||||||
if ((m)->type == (t))
|
if ((m)->type == (t))
|
||||||
|
|
||||||
size_t type_marker_length(struct marker *m);
|
static inline struct marker *next_type_marker(struct marker *m)
|
||||||
|
{
|
||||||
|
for_each_marker(m)
|
||||||
|
if (is_type_marker(m->type))
|
||||||
|
break;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t type_marker_length(struct marker *m)
|
||||||
|
{
|
||||||
|
struct marker *next = next_type_marker(m->next);
|
||||||
|
|
||||||
|
if (next)
|
||||||
|
return next->offset - m->offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void data_free(struct data d);
|
void data_free(struct data d);
|
||||||
|
|
||||||
struct data data_grow_for(struct data d, int xlen);
|
struct data data_grow_for(struct data d, unsigned int xlen);
|
||||||
|
|
||||||
struct data data_copy_mem(const char *mem, int len);
|
struct data data_copy_mem(const char *mem, int len);
|
||||||
struct data data_copy_escape_string(const char *s, int len);
|
struct data data_copy_escape_string(const char *s, int len);
|
||||||
|
@ -253,7 +289,7 @@ void append_to_property(struct node *node,
|
||||||
const char *get_unitname(struct node *node);
|
const char *get_unitname(struct node *node);
|
||||||
struct property *get_property(struct node *node, const char *propname);
|
struct property *get_property(struct node *node, const char *propname);
|
||||||
cell_t propval_cell(struct property *prop);
|
cell_t propval_cell(struct property *prop);
|
||||||
cell_t propval_cell_n(struct property *prop, int n);
|
cell_t propval_cell_n(struct property *prop, unsigned int n);
|
||||||
struct property *get_property_by_label(struct node *tree, const char *label,
|
struct property *get_property_by_label(struct node *tree, const char *label,
|
||||||
struct node **node);
|
struct node **node);
|
||||||
struct marker *get_marker_label(struct node *tree, const char *label,
|
struct marker *get_marker_label(struct node *tree, const char *label,
|
||||||
|
|
10
fdtdump.c
10
fdtdump.c
|
@ -18,10 +18,10 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define FDT_MAGIC_SIZE 4
|
#define FDT_MAGIC_SIZE 4
|
||||||
#define MAX_VERSION 17
|
#define MAX_VERSION 17U
|
||||||
|
|
||||||
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
||||||
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
|
#define PALIGN(p, a) ((void *)(ALIGN((uintptr_t)(p), (a))))
|
||||||
#define GET_CELL(p) (p += 4, *((const fdt32_t *)(p-4)))
|
#define GET_CELL(p) (p += 4, *((const fdt32_t *)(p-4)))
|
||||||
|
|
||||||
static const char *tagname(uint32_t tag)
|
static const char *tagname(uint32_t tag)
|
||||||
|
@ -163,7 +163,7 @@ static const char * const usage_opts_help[] = {
|
||||||
USAGE_COMMON_OPTS_HELP
|
USAGE_COMMON_OPTS_HELP
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool valid_header(char *p, off_t len)
|
static bool valid_header(char *p, size_t len)
|
||||||
{
|
{
|
||||||
if (len < sizeof(struct fdt_header) ||
|
if (len < sizeof(struct fdt_header) ||
|
||||||
fdt_magic(p) != FDT_MAGIC ||
|
fdt_magic(p) != FDT_MAGIC ||
|
||||||
|
@ -217,7 +217,7 @@ int main(int argc, char *argv[])
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
char *endp = buf + len;
|
char *endp = buf + len;
|
||||||
|
|
||||||
fdt_set_magic(smagic, FDT_MAGIC);
|
fdt32_st(smagic, FDT_MAGIC);
|
||||||
|
|
||||||
/* poor man's memmem */
|
/* poor man's memmem */
|
||||||
while ((endp - p) >= FDT_MAGIC_SIZE) {
|
while ((endp - p) >= FDT_MAGIC_SIZE) {
|
||||||
|
@ -235,7 +235,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
if (!p || endp - p < sizeof(struct fdt_header))
|
if (!p || (size_t)(endp - p) < sizeof(struct fdt_header))
|
||||||
die("%s: could not locate fdt magic\n", file);
|
die("%s: could not locate fdt magic\n", file);
|
||||||
printf("%s: found fdt at offset %#tx\n", file, p - buf);
|
printf("%s: found fdt at offset %#tx\n", file, p - buf);
|
||||||
buf = p;
|
buf = p;
|
||||||
|
|
15
fdtget.c
15
fdtget.c
|
@ -62,8 +62,14 @@ static int show_cell_list(struct display_info *disp, const char *data, int len,
|
||||||
for (i = 0; i < len; i += size, p += size) {
|
for (i = 0; i < len; i += size, p += size) {
|
||||||
if (i)
|
if (i)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
value = size == 4 ? fdt32_ld((const fdt32_t *)p) :
|
switch (size) {
|
||||||
size == 2 ? (*p << 8) | p[1] : *p;
|
case 4: value = fdt32_ld((const fdt32_t *)p); break;
|
||||||
|
case 2: value = fdt16_ld((const fdt16_t *)p); break;
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
value = *p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
printf(fmt, value);
|
printf(fmt, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +97,11 @@ static int show_data(struct display_info *disp, const char *data, int len)
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (disp->type == 'r') {
|
||||||
|
fwrite(data, 1, len, stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
is_string = (disp->type) == 's' ||
|
is_string = (disp->type) == 's' ||
|
||||||
(!disp->type && util_is_printable_string(data, len));
|
(!disp->type && util_is_printable_string(data, len));
|
||||||
if (is_string) {
|
if (is_string) {
|
||||||
|
|
2
fdtput.c
2
fdtput.c
|
@ -433,6 +433,8 @@ int main(int argc, char *argv[])
|
||||||
if (utilfdt_decode_type(optarg, &disp.type,
|
if (utilfdt_decode_type(optarg, &disp.type,
|
||||||
&disp.size))
|
&disp.size))
|
||||||
usage("Invalid type string");
|
usage("Invalid type string");
|
||||||
|
if (disp.type == 'r')
|
||||||
|
usage("Unsupported raw data type");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
|
|
19
flattree.c
19
flattree.c
|
@ -124,7 +124,8 @@ static void asm_emit_cell(void *e, cell_t val)
|
||||||
{
|
{
|
||||||
FILE *f = e;
|
FILE *f = e;
|
||||||
|
|
||||||
fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
|
fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n"
|
||||||
|
"\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n",
|
||||||
(val >> 24) & 0xff, (val >> 16) & 0xff,
|
(val >> 24) & 0xff, (val >> 16) & 0xff,
|
||||||
(val >> 8) & 0xff, val & 0xff);
|
(val >> 8) & 0xff, val & 0xff);
|
||||||
}
|
}
|
||||||
|
@ -134,9 +135,9 @@ static void asm_emit_string(void *e, const char *str, int len)
|
||||||
FILE *f = e;
|
FILE *f = e;
|
||||||
|
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
fprintf(f, "\t.string\t\"%.*s\"\n", len, str);
|
fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str);
|
||||||
else
|
else
|
||||||
fprintf(f, "\t.string\t\"%s\"\n", str);
|
fprintf(f, "\t.asciz\t\"%s\"\n", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void asm_emit_align(void *e, int a)
|
static void asm_emit_align(void *e, int a)
|
||||||
|
@ -149,7 +150,7 @@ static void asm_emit_align(void *e, int a)
|
||||||
static void asm_emit_data(void *e, struct data d)
|
static void asm_emit_data(void *e, struct data d)
|
||||||
{
|
{
|
||||||
FILE *f = e;
|
FILE *f = e;
|
||||||
int off = 0;
|
unsigned int off = 0;
|
||||||
struct marker *m = d.markers;
|
struct marker *m = d.markers;
|
||||||
|
|
||||||
for_each_marker_of_type(m, LABEL)
|
for_each_marker_of_type(m, LABEL)
|
||||||
|
@ -219,7 +220,7 @@ static struct emitter asm_emitter = {
|
||||||
|
|
||||||
static int stringtable_insert(struct data *d, const char *str)
|
static int stringtable_insert(struct data *d, const char *str)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* FIXME: do this more efficiently? */
|
/* FIXME: do this more efficiently? */
|
||||||
|
|
||||||
|
@ -295,7 +296,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
|
||||||
{
|
{
|
||||||
struct reserve_info *re;
|
struct reserve_info *re;
|
||||||
struct data d = empty_data;
|
struct data d = empty_data;
|
||||||
int j;
|
unsigned int j;
|
||||||
|
|
||||||
for (re = reservelist; re; re = re->next) {
|
for (re = reservelist; re; re = re->next) {
|
||||||
d = data_append_re(d, re->address, re->size);
|
d = data_append_re(d, re->address, re->size);
|
||||||
|
@ -345,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt,
|
||||||
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
|
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
|
||||||
{
|
{
|
||||||
struct version_info *vi = NULL;
|
struct version_info *vi = NULL;
|
||||||
int i;
|
unsigned int i;
|
||||||
struct data blob = empty_data;
|
struct data blob = empty_data;
|
||||||
struct data reservebuf = empty_data;
|
struct data reservebuf = empty_data;
|
||||||
struct data dtbuf = empty_data;
|
struct data dtbuf = empty_data;
|
||||||
|
@ -438,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
|
||||||
|
|
||||||
while (p < (strbuf.val + strbuf.len)) {
|
while (p < (strbuf.val + strbuf.len)) {
|
||||||
len = strlen(p);
|
len = strlen(p);
|
||||||
fprintf(f, "\t.string \"%s\"\n", p);
|
fprintf(f, "\t.asciz \"%s\"\n", p);
|
||||||
p += len+1;
|
p += len+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -446,7 +447,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
|
||||||
void dt_to_asm(FILE *f, struct dt_info *dti, int version)
|
void dt_to_asm(FILE *f, struct dt_info *dti, int version)
|
||||||
{
|
{
|
||||||
struct version_info *vi = NULL;
|
struct version_info *vi = NULL;
|
||||||
int i;
|
unsigned int i;
|
||||||
struct data strbuf = empty_data;
|
struct data strbuf = empty_data;
|
||||||
struct reserve_info *re;
|
struct reserve_info *re;
|
||||||
const char *symprefix = "dt";
|
const char *symprefix = "dt";
|
||||||
|
|
39
libfdt/fdt.c
39
libfdt/fdt.c
|
@ -22,6 +22,10 @@ int32_t fdt_ro_probe_(const void *fdt)
|
||||||
if (can_assume(VALID_DTB))
|
if (can_assume(VALID_DTB))
|
||||||
return totalsize;
|
return totalsize;
|
||||||
|
|
||||||
|
/* The device tree must be at an 8-byte aligned address */
|
||||||
|
if ((uintptr_t)fdt & 7)
|
||||||
|
return -FDT_ERR_ALIGNMENT;
|
||||||
|
|
||||||
if (fdt_magic(fdt) == FDT_MAGIC) {
|
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||||
/* Complete tree */
|
/* Complete tree */
|
||||||
if (!can_assume(LATEST)) {
|
if (!can_assume(LATEST)) {
|
||||||
|
@ -86,6 +90,10 @@ int fdt_check_header(const void *fdt)
|
||||||
{
|
{
|
||||||
size_t hdrsize;
|
size_t hdrsize;
|
||||||
|
|
||||||
|
/* The device tree must be at an 8-byte aligned address */
|
||||||
|
if ((uintptr_t)fdt & 7)
|
||||||
|
return -FDT_ERR_ALIGNMENT;
|
||||||
|
|
||||||
if (fdt_magic(fdt) != FDT_MAGIC)
|
if (fdt_magic(fdt) != FDT_MAGIC)
|
||||||
return -FDT_ERR_BADMAGIC;
|
return -FDT_ERR_BADMAGIC;
|
||||||
if (!can_assume(LATEST)) {
|
if (!can_assume(LATEST)) {
|
||||||
|
@ -134,16 +142,20 @@ int fdt_check_header(const void *fdt)
|
||||||
|
|
||||||
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|
||||||
{
|
{
|
||||||
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
|
unsigned int uoffset = offset;
|
||||||
|
unsigned int absoffset = offset + fdt_off_dt_struct(fdt);
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (!can_assume(VALID_INPUT))
|
if (!can_assume(VALID_INPUT))
|
||||||
if ((absoffset < offset)
|
if ((absoffset < uoffset)
|
||||||
|| ((absoffset + len) < absoffset)
|
|| ((absoffset + len) < absoffset)
|
||||||
|| (absoffset + len) > fdt_totalsize(fdt))
|
|| (absoffset + len) > fdt_totalsize(fdt))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
|
if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
|
||||||
if (((offset + len) < offset)
|
if (((uoffset + len) < uoffset)
|
||||||
|| ((offset + len) > fdt_size_dt_struct(fdt)))
|
|| ((offset + len) > fdt_size_dt_struct(fdt)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -206,10 +218,11 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||||
|
|
||||||
int fdt_check_node_offset_(const void *fdt, int offset)
|
int fdt_check_node_offset_(const void *fdt, int offset)
|
||||||
{
|
{
|
||||||
if (can_assume(VALID_INPUT))
|
if (!can_assume(VALID_INPUT)
|
||||||
return offset;
|
&& ((offset < 0) || (offset % FDT_TAGSIZE)))
|
||||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
return -FDT_ERR_BADOFFSET;
|
||||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
|
|
||||||
|
if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)
|
||||||
return -FDT_ERR_BADOFFSET;
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -217,8 +230,11 @@ int fdt_check_node_offset_(const void *fdt, int offset)
|
||||||
|
|
||||||
int fdt_check_prop_offset_(const void *fdt, int offset)
|
int fdt_check_prop_offset_(const void *fdt, int offset)
|
||||||
{
|
{
|
||||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
if (!can_assume(VALID_INPUT)
|
||||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
|
&& ((offset < 0) || (offset % FDT_TAGSIZE)))
|
||||||
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
|
||||||
|
if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)
|
||||||
return -FDT_ERR_BADOFFSET;
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -306,9 +322,12 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
|
||||||
|
|
||||||
int fdt_move(const void *fdt, void *buf, int bufsize)
|
int fdt_move(const void *fdt, void *buf, int bufsize)
|
||||||
{
|
{
|
||||||
|
if (!can_assume(VALID_INPUT) && bufsize < 0)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
FDT_RO_PROBE(fdt);
|
FDT_RO_PROBE(fdt);
|
||||||
|
|
||||||
if (fdt_totalsize(fdt) > bufsize)
|
if (fdt_totalsize(fdt) > (unsigned int)bufsize)
|
||||||
return -FDT_ERR_NOSPACE;
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
memmove(buf, fdt, fdt_totalsize(fdt));
|
memmove(buf, fdt, fdt_totalsize(fdt));
|
||||||
|
|
|
@ -73,7 +73,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
|
||||||
/* check validity of address */
|
/* check validity of address */
|
||||||
prop = data;
|
prop = data;
|
||||||
if (addr_cells == 1) {
|
if (addr_cells == 1) {
|
||||||
if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
|
if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size))
|
||||||
return -FDT_ERR_BADVALUE;
|
return -FDT_ERR_BADVALUE;
|
||||||
|
|
||||||
fdt32_st(prop, (uint32_t)addr);
|
fdt32_st(prop, (uint32_t)addr);
|
||||||
|
|
|
@ -19,9 +19,12 @@ int fdt_check_full(const void *fdt, size_t bufsize)
|
||||||
unsigned int depth = 0;
|
unsigned int depth = 0;
|
||||||
const void *prop;
|
const void *prop;
|
||||||
const char *propname;
|
const char *propname;
|
||||||
|
bool expect_end = false;
|
||||||
|
|
||||||
if (bufsize < FDT_V1_SIZE)
|
if (bufsize < FDT_V1_SIZE)
|
||||||
return -FDT_ERR_TRUNCATED;
|
return -FDT_ERR_TRUNCATED;
|
||||||
|
if (bufsize < fdt_header_size(fdt))
|
||||||
|
return -FDT_ERR_TRUNCATED;
|
||||||
err = fdt_check_header(fdt);
|
err = fdt_check_header(fdt);
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -39,6 +42,10 @@ int fdt_check_full(const void *fdt, size_t bufsize)
|
||||||
if (nextoffset < 0)
|
if (nextoffset < 0)
|
||||||
return nextoffset;
|
return nextoffset;
|
||||||
|
|
||||||
|
/* If we see two root nodes, something is wrong */
|
||||||
|
if (expect_end && tag != FDT_END)
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case FDT_NOP:
|
case FDT_NOP:
|
||||||
break;
|
break;
|
||||||
|
@ -52,12 +59,24 @@ int fdt_check_full(const void *fdt, size_t bufsize)
|
||||||
depth++;
|
depth++;
|
||||||
if (depth > INT_MAX)
|
if (depth > INT_MAX)
|
||||||
return -FDT_ERR_BADSTRUCTURE;
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
|
||||||
|
/* The root node must have an empty name */
|
||||||
|
if (depth == 1) {
|
||||||
|
const char *name;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
name = fdt_get_name(fdt, offset, &len);
|
||||||
|
if (*name || len)
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FDT_END_NODE:
|
case FDT_END_NODE:
|
||||||
if (depth == 0)
|
if (depth == 0)
|
||||||
return -FDT_ERR_BADSTRUCTURE;
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
depth--;
|
depth--;
|
||||||
|
if (depth == 0)
|
||||||
|
expect_end = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FDT_PROP:
|
case FDT_PROP:
|
||||||
|
|
|
@ -40,37 +40,22 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
|
||||||
return fdt32_to_cpu(*val);
|
return fdt32_to_cpu(*val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int fdt_overlay_target_offset(const void *fdt, const void *fdto,
|
||||||
* overlay_get_target - retrieves the offset of a fragment's target
|
int fragment_offset, char const **pathp)
|
||||||
* @fdt: Base device tree blob
|
|
||||||
* @fdto: Device tree overlay blob
|
|
||||||
* @fragment: node offset of the fragment in the overlay
|
|
||||||
* @pathp: pointer which receives the path of the target (or NULL)
|
|
||||||
*
|
|
||||||
* overlay_get_target() retrieves the target offset in the base
|
|
||||||
* device tree of a fragment, no matter how the actual targeting is
|
|
||||||
* done (through a phandle or a path)
|
|
||||||
*
|
|
||||||
* returns:
|
|
||||||
* the targeted node offset in the base device tree
|
|
||||||
* Negative error code on error
|
|
||||||
*/
|
|
||||||
static int overlay_get_target(const void *fdt, const void *fdto,
|
|
||||||
int fragment, char const **pathp)
|
|
||||||
{
|
{
|
||||||
uint32_t phandle;
|
uint32_t phandle;
|
||||||
const char *path = NULL;
|
const char *path = NULL;
|
||||||
int path_len = 0, ret;
|
int path_len = 0, ret;
|
||||||
|
|
||||||
/* Try first to do a phandle based lookup */
|
/* Try first to do a phandle based lookup */
|
||||||
phandle = overlay_get_target_phandle(fdto, fragment);
|
phandle = overlay_get_target_phandle(fdto, fragment_offset);
|
||||||
if (phandle == (uint32_t)-1)
|
if (phandle == (uint32_t)-1)
|
||||||
return -FDT_ERR_BADPHANDLE;
|
return -FDT_ERR_BADPHANDLE;
|
||||||
|
|
||||||
/* no phandle, try path */
|
/* no phandle, try path */
|
||||||
if (!phandle) {
|
if (!phandle) {
|
||||||
/* And then a path based lookup */
|
/* And then a path based lookup */
|
||||||
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
|
path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len);
|
||||||
if (path)
|
if (path)
|
||||||
ret = fdt_path_offset(fdt, path);
|
ret = fdt_path_offset(fdt, path);
|
||||||
else
|
else
|
||||||
|
@ -241,6 +226,7 @@ static int overlay_update_local_node_references(void *fdto,
|
||||||
|
|
||||||
if (fixup_len % sizeof(uint32_t))
|
if (fixup_len % sizeof(uint32_t))
|
||||||
return -FDT_ERR_BADOVERLAY;
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
fixup_len /= sizeof(uint32_t);
|
||||||
|
|
||||||
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
|
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
|
||||||
if (!tree_val) {
|
if (!tree_val) {
|
||||||
|
@ -250,7 +236,7 @@ static int overlay_update_local_node_references(void *fdto,
|
||||||
return tree_len;
|
return tree_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
|
for (i = 0; i < fixup_len; i++) {
|
||||||
fdt32_t adj_val;
|
fdt32_t adj_val;
|
||||||
uint32_t poffset;
|
uint32_t poffset;
|
||||||
|
|
||||||
|
@ -635,7 +621,7 @@ static int overlay_merge(void *fdt, void *fdto)
|
||||||
if (overlay < 0)
|
if (overlay < 0)
|
||||||
return overlay;
|
return overlay;
|
||||||
|
|
||||||
target = overlay_get_target(fdt, fdto, fragment, NULL);
|
target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
|
||||||
if (target < 0)
|
if (target < 0)
|
||||||
return target;
|
return target;
|
||||||
|
|
||||||
|
@ -778,7 +764,7 @@ static int overlay_symbol_update(void *fdt, void *fdto)
|
||||||
return -FDT_ERR_BADOVERLAY;
|
return -FDT_ERR_BADOVERLAY;
|
||||||
|
|
||||||
/* get the target of the fragment */
|
/* get the target of the fragment */
|
||||||
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
|
ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
target = ret;
|
target = ret;
|
||||||
|
@ -800,7 +786,7 @@ static int overlay_symbol_update(void *fdt, void *fdto)
|
||||||
|
|
||||||
if (!target_path) {
|
if (!target_path) {
|
||||||
/* again in case setprop_placeholder changed it */
|
/* again in case setprop_placeholder changed it */
|
||||||
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
|
ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
target = ret;
|
target = ret;
|
||||||
|
|
|
@ -53,7 +53,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
|
||||||
|
|
||||||
err = -FDT_ERR_BADOFFSET;
|
err = -FDT_ERR_BADOFFSET;
|
||||||
absoffset = stroffset + fdt_off_dt_strings(fdt);
|
absoffset = stroffset + fdt_off_dt_strings(fdt);
|
||||||
if (absoffset >= totalsize)
|
if (absoffset >= (unsigned)totalsize)
|
||||||
goto fail;
|
goto fail;
|
||||||
len = totalsize - absoffset;
|
len = totalsize - absoffset;
|
||||||
|
|
||||||
|
@ -61,17 +61,19 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
|
||||||
if (stroffset < 0)
|
if (stroffset < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
||||||
if (stroffset >= fdt_size_dt_strings(fdt))
|
if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
|
||||||
goto fail;
|
goto fail;
|
||||||
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
|
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
|
||||||
len = fdt_size_dt_strings(fdt) - stroffset;
|
len = fdt_size_dt_strings(fdt) - stroffset;
|
||||||
}
|
}
|
||||||
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
||||||
if ((stroffset >= 0)
|
unsigned int sw_stroffset = -stroffset;
|
||||||
|| (stroffset < -fdt_size_dt_strings(fdt)))
|
|
||||||
|
if ((stroffset >= 0) ||
|
||||||
|
(sw_stroffset > fdt_size_dt_strings(fdt)))
|
||||||
goto fail;
|
goto fail;
|
||||||
if ((-stroffset) < len)
|
if (sw_stroffset < len)
|
||||||
len = -stroffset;
|
len = sw_stroffset;
|
||||||
} else {
|
} else {
|
||||||
err = -FDT_ERR_INTERNAL;
|
err = -FDT_ERR_INTERNAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -157,8 +159,8 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
|
||||||
|
|
||||||
static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
|
static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
|
||||||
{
|
{
|
||||||
int offset = n * sizeof(struct fdt_reserve_entry);
|
unsigned int offset = n * sizeof(struct fdt_reserve_entry);
|
||||||
int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
|
unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
|
||||||
|
|
||||||
if (!can_assume(VALID_INPUT)) {
|
if (!can_assume(VALID_INPUT)) {
|
||||||
if (absoffset < fdt_off_mem_rsvmap(fdt))
|
if (absoffset < fdt_off_mem_rsvmap(fdt))
|
||||||
|
@ -179,8 +181,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||||
if (!can_assume(VALID_INPUT) && !re)
|
if (!can_assume(VALID_INPUT) && !re)
|
||||||
return -FDT_ERR_BADOFFSET;
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
|
||||||
*address = fdt64_ld(&re->address);
|
*address = fdt64_ld_(&re->address);
|
||||||
*size = fdt64_ld(&re->size);
|
*size = fdt64_ld_(&re->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +192,7 @@ int fdt_num_mem_rsv(const void *fdt)
|
||||||
const struct fdt_reserve_entry *re;
|
const struct fdt_reserve_entry *re;
|
||||||
|
|
||||||
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
|
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
|
||||||
if (fdt64_ld(&re->size) == 0)
|
if (fdt64_ld_(&re->size) == 0)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return -FDT_ERR_TRUNCATED;
|
return -FDT_ERR_TRUNCATED;
|
||||||
|
@ -368,7 +370,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
|
||||||
prop = fdt_offset_ptr_(fdt, offset);
|
prop = fdt_offset_ptr_(fdt, offset);
|
||||||
|
|
||||||
if (lenp)
|
if (lenp)
|
||||||
*lenp = fdt32_ld(&prop->len);
|
*lenp = fdt32_ld_(&prop->len);
|
||||||
|
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
@ -406,7 +408,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
|
||||||
offset = -FDT_ERR_INTERNAL;
|
offset = -FDT_ERR_INTERNAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
|
if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff),
|
||||||
name, namelen)) {
|
name, namelen)) {
|
||||||
if (poffset)
|
if (poffset)
|
||||||
*poffset = offset;
|
*poffset = offset;
|
||||||
|
@ -459,7 +461,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||||
|
|
||||||
/* Handle realignment */
|
/* Handle realignment */
|
||||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
|
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
|
||||||
(poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
|
(poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
|
||||||
return prop->data + 4;
|
return prop->data + 4;
|
||||||
return prop->data;
|
return prop->data;
|
||||||
}
|
}
|
||||||
|
@ -477,22 +479,22 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||||
int namelen;
|
int namelen;
|
||||||
|
|
||||||
if (!can_assume(VALID_INPUT)) {
|
if (!can_assume(VALID_INPUT)) {
|
||||||
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
|
name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
|
||||||
&namelen);
|
&namelen);
|
||||||
|
*namep = name;
|
||||||
if (!name) {
|
if (!name) {
|
||||||
if (lenp)
|
if (lenp)
|
||||||
*lenp = namelen;
|
*lenp = namelen;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*namep = name;
|
|
||||||
} else {
|
} else {
|
||||||
*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
|
*namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle realignment */
|
/* Handle realignment */
|
||||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
|
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
|
||||||
(offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
|
(offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
|
||||||
return prop->data + 4;
|
return prop->data + 4;
|
||||||
return prop->data;
|
return prop->data;
|
||||||
}
|
}
|
||||||
|
@ -517,7 +519,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fdt32_ld(php);
|
return fdt32_ld_(php);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *fdt_get_alias_namelen(const void *fdt,
|
const char *fdt_get_alias_namelen(const void *fdt,
|
||||||
|
@ -680,7 +682,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
|
||||||
{
|
{
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
if ((phandle == 0) || (phandle == -1))
|
if ((phandle == 0) || (phandle == ~0U))
|
||||||
return -FDT_ERR_BADPHANDLE;
|
return -FDT_ERR_BADPHANDLE;
|
||||||
|
|
||||||
FDT_RO_PROBE(fdt);
|
FDT_RO_PROBE(fdt);
|
||||||
|
|
|
@ -59,7 +59,7 @@ static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
|
||||||
|
|
||||||
if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
|
if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
|
||||||
return -FDT_ERR_BADOFFSET;
|
return -FDT_ERR_BADOFFSET;
|
||||||
if ((p < (char *)fdt) || (dsize + newlen < oldlen))
|
if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen))
|
||||||
return -FDT_ERR_BADOFFSET;
|
return -FDT_ERR_BADOFFSET;
|
||||||
if (dsize - oldlen + newlen > fdt_totalsize(fdt))
|
if (dsize - oldlen + newlen > fdt_totalsize(fdt))
|
||||||
return -FDT_ERR_NOSPACE;
|
return -FDT_ERR_NOSPACE;
|
||||||
|
@ -349,7 +349,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||||||
return offset;
|
return offset;
|
||||||
|
|
||||||
/* Try to place the new node after the parent's properties */
|
/* Try to place the new node after the parent's properties */
|
||||||
fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
|
tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
|
||||||
|
/* the fdt_subnode_offset_namelen() should ensure this never hits */
|
||||||
|
if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE))
|
||||||
|
return -FDT_ERR_INTERNAL;
|
||||||
do {
|
do {
|
||||||
offset = nextoffset;
|
offset = nextoffset;
|
||||||
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
tag = fdt_next_tag(fdt, offset, &nextoffset);
|
||||||
|
@ -391,7 +394,9 @@ int fdt_del_node(void *fdt, int nodeoffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdt_packblocks_(const char *old, char *new,
|
static void fdt_packblocks_(const char *old, char *new,
|
||||||
int mem_rsv_size, int struct_size)
|
int mem_rsv_size,
|
||||||
|
int struct_size,
|
||||||
|
int strings_size)
|
||||||
{
|
{
|
||||||
int mem_rsv_off, struct_off, strings_off;
|
int mem_rsv_off, struct_off, strings_off;
|
||||||
|
|
||||||
|
@ -406,8 +411,7 @@ static void fdt_packblocks_(const char *old, char *new,
|
||||||
fdt_set_off_dt_struct(new, struct_off);
|
fdt_set_off_dt_struct(new, struct_off);
|
||||||
fdt_set_size_dt_struct(new, struct_size);
|
fdt_set_size_dt_struct(new, struct_size);
|
||||||
|
|
||||||
memmove(new + strings_off, old + fdt_off_dt_strings(old),
|
memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size);
|
||||||
fdt_size_dt_strings(old));
|
|
||||||
fdt_set_off_dt_strings(new, strings_off);
|
fdt_set_off_dt_strings(new, strings_off);
|
||||||
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
|
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
|
||||||
}
|
}
|
||||||
|
@ -428,12 +432,14 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||||
|
|
||||||
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
||||||
struct_size = fdt_size_dt_struct(fdt);
|
struct_size = fdt_size_dt_struct(fdt);
|
||||||
} else {
|
} else if (fdt_version(fdt) == 16) {
|
||||||
struct_size = 0;
|
struct_size = 0;
|
||||||
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
|
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
|
||||||
;
|
;
|
||||||
if (struct_size < 0)
|
if (struct_size < 0)
|
||||||
return struct_size;
|
return struct_size;
|
||||||
|
} else {
|
||||||
|
return -FDT_ERR_BADVERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can_assume(LIBFDT_ORDER) ||
|
if (can_assume(LIBFDT_ORDER) ||
|
||||||
|
@ -465,7 +471,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||||
return -FDT_ERR_NOSPACE;
|
return -FDT_ERR_NOSPACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
|
fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size,
|
||||||
|
fdt_size_dt_strings(fdt));
|
||||||
memmove(buf, tmp, newsize);
|
memmove(buf, tmp, newsize);
|
||||||
|
|
||||||
fdt_set_magic(buf, FDT_MAGIC);
|
fdt_set_magic(buf, FDT_MAGIC);
|
||||||
|
@ -485,7 +492,8 @@ int fdt_pack(void *fdt)
|
||||||
|
|
||||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||||
* sizeof(struct fdt_reserve_entry);
|
* sizeof(struct fdt_reserve_entry);
|
||||||
fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
|
fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt),
|
||||||
|
fdt_size_dt_strings(fdt));
|
||||||
fdt_set_totalsize(fdt, fdt_data_size_(fdt));
|
fdt_set_totalsize(fdt, fdt_data_size_(fdt));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -39,8 +39,9 @@ static struct fdt_errtabent fdt_errtable[] = {
|
||||||
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
|
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
|
||||||
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
|
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
|
||||||
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
|
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
|
||||||
|
FDT_ERRTABENT(FDT_ERR_ALIGNMENT),
|
||||||
};
|
};
|
||||||
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
|
#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])))
|
||||||
|
|
||||||
const char *fdt_strerror(int errval)
|
const char *fdt_strerror(int errval)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +49,7 @@ const char *fdt_strerror(int errval)
|
||||||
return "<valid offset/length>";
|
return "<valid offset/length>";
|
||||||
else if (errval == 0)
|
else if (errval == 0)
|
||||||
return "<no error>";
|
return "<no error>";
|
||||||
else if (errval > -FDT_ERRTABSIZE) {
|
else if (-errval < FDT_ERRTABSIZE) {
|
||||||
const char *s = fdt_errtable[-errval].str;
|
const char *s = fdt_errtable[-errval].str;
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
|
|
|
@ -93,8 +93,8 @@ static inline uint32_t sw_flags(void *fdt)
|
||||||
|
|
||||||
static void *fdt_grab_space_(void *fdt, size_t len)
|
static void *fdt_grab_space_(void *fdt, size_t len)
|
||||||
{
|
{
|
||||||
int offset = fdt_size_dt_struct(fdt);
|
unsigned int offset = fdt_size_dt_struct(fdt);
|
||||||
int spaceleft;
|
unsigned int spaceleft;
|
||||||
|
|
||||||
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
|
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
|
||||||
- fdt_size_dt_strings(fdt);
|
- fdt_size_dt_strings(fdt);
|
||||||
|
@ -108,7 +108,7 @@ static void *fdt_grab_space_(void *fdt, size_t len)
|
||||||
|
|
||||||
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
|
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
|
||||||
{
|
{
|
||||||
const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
|
const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
|
||||||
sizeof(struct fdt_reserve_entry));
|
sizeof(struct fdt_reserve_entry));
|
||||||
void *fdt = buf;
|
void *fdt = buf;
|
||||||
|
|
||||||
|
@ -152,6 +152,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
|
||||||
|
|
||||||
FDT_SW_PROBE(fdt);
|
FDT_SW_PROBE(fdt);
|
||||||
|
|
||||||
|
if (bufsize < 0)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||||
tailsize = fdt_size_dt_strings(fdt);
|
tailsize = fdt_size_dt_strings(fdt);
|
||||||
|
|
||||||
|
@ -159,7 +162,7 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
|
||||||
headsize + tailsize > fdt_totalsize(fdt))
|
headsize + tailsize > fdt_totalsize(fdt))
|
||||||
return -FDT_ERR_INTERNAL;
|
return -FDT_ERR_INTERNAL;
|
||||||
|
|
||||||
if ((headsize + tailsize) > bufsize)
|
if ((headsize + tailsize) > (unsigned)bufsize)
|
||||||
return -FDT_ERR_NOSPACE;
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
|
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
|
||||||
|
@ -247,18 +250,18 @@ int fdt_end_node(void *fdt)
|
||||||
static int fdt_add_string_(void *fdt, const char *s)
|
static int fdt_add_string_(void *fdt, const char *s)
|
||||||
{
|
{
|
||||||
char *strtab = (char *)fdt + fdt_totalsize(fdt);
|
char *strtab = (char *)fdt + fdt_totalsize(fdt);
|
||||||
int strtabsize = fdt_size_dt_strings(fdt);
|
unsigned int strtabsize = fdt_size_dt_strings(fdt);
|
||||||
int len = strlen(s) + 1;
|
unsigned int len = strlen(s) + 1;
|
||||||
int struct_top, offset;
|
unsigned int struct_top, offset;
|
||||||
|
|
||||||
offset = -strtabsize - len;
|
offset = strtabsize + len;
|
||||||
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||||
if (fdt_totalsize(fdt) + offset < struct_top)
|
if (fdt_totalsize(fdt) - offset < struct_top)
|
||||||
return 0; /* no more room :( */
|
return 0; /* no more room :( */
|
||||||
|
|
||||||
memcpy(strtab + offset, s, len);
|
memcpy(strtab - offset, s, len);
|
||||||
fdt_set_size_dt_strings(fdt, strtabsize + len);
|
fdt_set_size_dt_strings(fdt, strtabsize + len);
|
||||||
return offset;
|
return -offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must only be used to roll back in case of error */
|
/* Must only be used to roll back in case of error */
|
||||||
|
@ -374,7 +377,7 @@ int fdt_finish(void *fdt)
|
||||||
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
|
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
|
||||||
|
|
||||||
/* And fix up fields that were keeping intermediate state. */
|
/* And fix up fields that were keeping intermediate state. */
|
||||||
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
|
fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION);
|
||||||
fdt_set_magic(fdt, FDT_MAGIC);
|
fdt_set_magic(fdt, FDT_MAGIC);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -23,7 +23,7 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||||||
if (!propval)
|
if (!propval)
|
||||||
return proplen;
|
return proplen;
|
||||||
|
|
||||||
if (proplen < (len + idx))
|
if ((unsigned)proplen < (len + idx))
|
||||||
return -FDT_ERR_NOSPACE;
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
memcpy((char *)propval + idx, val, len);
|
memcpy((char *)propval + idx, val, len);
|
||||||
|
|
143
libfdt/libfdt.h
143
libfdt/libfdt.h
|
@ -14,6 +14,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FDT_FIRST_SUPPORTED_VERSION 0x02
|
#define FDT_FIRST_SUPPORTED_VERSION 0x02
|
||||||
|
#define FDT_LAST_COMPATIBLE_VERSION 0x10
|
||||||
#define FDT_LAST_SUPPORTED_VERSION 0x11
|
#define FDT_LAST_SUPPORTED_VERSION 0x11
|
||||||
|
|
||||||
/* Error codes: informative error codes */
|
/* Error codes: informative error codes */
|
||||||
|
@ -101,7 +102,11 @@ extern "C" {
|
||||||
/* FDT_ERR_BADFLAGS: The function was passed a flags field that
|
/* FDT_ERR_BADFLAGS: The function was passed a flags field that
|
||||||
* contains invalid flags or an invalid combination of flags. */
|
* contains invalid flags or an invalid combination of flags. */
|
||||||
|
|
||||||
#define FDT_ERR_MAX 18
|
#define FDT_ERR_ALIGNMENT 19
|
||||||
|
/* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte
|
||||||
|
* aligned. */
|
||||||
|
|
||||||
|
#define FDT_ERR_MAX 19
|
||||||
|
|
||||||
/* constants */
|
/* constants */
|
||||||
#define FDT_MAX_PHANDLE 0xfffffffe
|
#define FDT_MAX_PHANDLE 0xfffffffe
|
||||||
|
@ -122,11 +127,16 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
|
||||||
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
|
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Alignment helpers:
|
* External helpers to access words from a device tree blob. They're built
|
||||||
* These helpers access words from a device tree blob. They're
|
* to work even with unaligned pointers on platforms (such as ARMv5) that don't
|
||||||
* built to work even with unaligned pointers on platforms (ike
|
* like unaligned loads and stores.
|
||||||
* ARM) that don't like unaligned loads and stores
|
|
||||||
*/
|
*/
|
||||||
|
static inline uint16_t fdt16_ld(const fdt16_t *p)
|
||||||
|
{
|
||||||
|
const uint8_t *bp = (const uint8_t *)p;
|
||||||
|
|
||||||
|
return ((uint16_t)bp[0] << 8) | bp[1];
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint32_t fdt32_ld(const fdt32_t *p)
|
static inline uint32_t fdt32_ld(const fdt32_t *p)
|
||||||
{
|
{
|
||||||
|
@ -184,22 +194,22 @@ int fdt_next_node(const void *fdt, int offset, int *depth);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_first_subnode() - get offset of first direct subnode
|
* fdt_first_subnode() - get offset of first direct subnode
|
||||||
*
|
|
||||||
* @fdt: FDT blob
|
* @fdt: FDT blob
|
||||||
* @offset: Offset of node to check
|
* @offset: Offset of node to check
|
||||||
* @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
|
*
|
||||||
|
* Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
|
||||||
*/
|
*/
|
||||||
int fdt_first_subnode(const void *fdt, int offset);
|
int fdt_first_subnode(const void *fdt, int offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_next_subnode() - get offset of next direct subnode
|
* fdt_next_subnode() - get offset of next direct subnode
|
||||||
|
* @fdt: FDT blob
|
||||||
|
* @offset: Offset of previous subnode
|
||||||
*
|
*
|
||||||
* After first calling fdt_first_subnode(), call this function repeatedly to
|
* After first calling fdt_first_subnode(), call this function repeatedly to
|
||||||
* get direct subnodes of a parent node.
|
* get direct subnodes of a parent node.
|
||||||
*
|
*
|
||||||
* @fdt: FDT blob
|
* Return: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
|
||||||
* @offset: Offset of previous subnode
|
|
||||||
* @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
|
|
||||||
* subnodes
|
* subnodes
|
||||||
*/
|
*/
|
||||||
int fdt_next_subnode(const void *fdt, int offset);
|
int fdt_next_subnode(const void *fdt, int offset);
|
||||||
|
@ -225,7 +235,6 @@ int fdt_next_subnode(const void *fdt, int offset);
|
||||||
* Note that this is implemented as a macro and @node is used as
|
* Note that this is implemented as a macro and @node is used as
|
||||||
* iterator in the loop. The parent variable be constant or even a
|
* iterator in the loop. The parent variable be constant or even a
|
||||||
* literal.
|
* literal.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
#define fdt_for_each_subnode(node, fdt, parent) \
|
#define fdt_for_each_subnode(node, fdt, parent) \
|
||||||
for (node = fdt_first_subnode(fdt, parent); \
|
for (node = fdt_first_subnode(fdt, parent); \
|
||||||
|
@ -269,17 +278,21 @@ fdt_set_hdr_(size_dt_struct);
|
||||||
/**
|
/**
|
||||||
* fdt_header_size - return the size of the tree's header
|
* fdt_header_size - return the size of the tree's header
|
||||||
* @fdt: pointer to a flattened device tree
|
* @fdt: pointer to a flattened device tree
|
||||||
|
*
|
||||||
|
* Return: size of DTB header in bytes
|
||||||
*/
|
*/
|
||||||
size_t fdt_header_size(const void *fdt);
|
size_t fdt_header_size(const void *fdt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_header_size_ - internal function which takes a version number
|
* fdt_header_size_ - internal function to get header size from a version number
|
||||||
|
* @version: devicetree version number
|
||||||
|
*
|
||||||
|
* Return: size of DTB header in bytes
|
||||||
*/
|
*/
|
||||||
size_t fdt_header_size_(uint32_t version);
|
size_t fdt_header_size_(uint32_t version);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_check_header - sanity check a device tree header
|
* fdt_check_header - sanity check a device tree header
|
||||||
|
|
||||||
* @fdt: pointer to data which might be a flattened device tree
|
* @fdt: pointer to data which might be a flattened device tree
|
||||||
*
|
*
|
||||||
* fdt_check_header() checks that the given buffer contains what
|
* fdt_check_header() checks that the given buffer contains what
|
||||||
|
@ -404,8 +417,7 @@ static inline uint32_t fdt_get_max_phandle(const void *fdt)
|
||||||
* highest phandle value in the device tree blob) will be returned in the
|
* highest phandle value in the device tree blob) will be returned in the
|
||||||
* @phandle parameter.
|
* @phandle parameter.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Return: 0 on success or a negative error-code on failure
|
||||||
* 0 on success or a negative error-code on failure
|
|
||||||
*/
|
*/
|
||||||
int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
|
int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
|
||||||
|
|
||||||
|
@ -425,9 +437,11 @@ int fdt_num_mem_rsv(const void *fdt);
|
||||||
/**
|
/**
|
||||||
* fdt_get_mem_rsv - retrieve one memory reserve map entry
|
* fdt_get_mem_rsv - retrieve one memory reserve map entry
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
* @address, @size: pointers to 64-bit variables
|
* @n: index of reserve map entry
|
||||||
|
* @address: pointer to 64-bit variable to hold the start address
|
||||||
|
* @size: pointer to 64-bit variable to hold the size of the entry
|
||||||
*
|
*
|
||||||
* On success, *address and *size will contain the address and size of
|
* On success, @address and @size will contain the address and size of
|
||||||
* the n-th reserve map entry from the device tree blob, in
|
* the n-th reserve map entry from the device tree blob, in
|
||||||
* native-endian format.
|
* native-endian format.
|
||||||
*
|
*
|
||||||
|
@ -450,6 +464,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
|
||||||
* namelen characters of name for matching the subnode name. This is
|
* namelen characters of name for matching the subnode name. This is
|
||||||
* useful for finding subnodes based on a portion of a larger string,
|
* useful for finding subnodes based on a portion of a larger string,
|
||||||
* such as a full path.
|
* such as a full path.
|
||||||
|
*
|
||||||
|
* Return: offset of the subnode or -FDT_ERR_NOTFOUND if name not found.
|
||||||
*/
|
*/
|
||||||
#ifndef SWIG /* Not available in Python */
|
#ifndef SWIG /* Not available in Python */
|
||||||
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
|
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
|
||||||
|
@ -489,6 +505,8 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
|
||||||
*
|
*
|
||||||
* Identical to fdt_path_offset(), but only consider the first namelen
|
* Identical to fdt_path_offset(), but only consider the first namelen
|
||||||
* characters of path as the path name.
|
* characters of path as the path name.
|
||||||
|
*
|
||||||
|
* Return: offset of the node or negative libfdt error value otherwise
|
||||||
*/
|
*/
|
||||||
#ifndef SWIG /* Not available in Python */
|
#ifndef SWIG /* Not available in Python */
|
||||||
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
|
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
|
||||||
|
@ -588,7 +606,7 @@ int fdt_next_property_offset(const void *fdt, int offset);
|
||||||
/**
|
/**
|
||||||
* fdt_for_each_property_offset - iterate over all properties of a node
|
* fdt_for_each_property_offset - iterate over all properties of a node
|
||||||
*
|
*
|
||||||
* @property_offset: property offset (int, lvalue)
|
* @property: property offset (int, lvalue)
|
||||||
* @fdt: FDT blob (const void *)
|
* @fdt: FDT blob (const void *)
|
||||||
* @node: node offset (int)
|
* @node: node offset (int)
|
||||||
*
|
*
|
||||||
|
@ -653,6 +671,9 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||||
*
|
*
|
||||||
* Identical to fdt_get_property(), but only examine the first namelen
|
* Identical to fdt_get_property(), but only examine the first namelen
|
||||||
* characters of name for matching the property name.
|
* characters of name for matching the property name.
|
||||||
|
*
|
||||||
|
* Return: pointer to the structure representing the property, or NULL
|
||||||
|
* if not found
|
||||||
*/
|
*/
|
||||||
#ifndef SWIG /* Not available in Python */
|
#ifndef SWIG /* Not available in Python */
|
||||||
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||||
|
@ -745,6 +766,8 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||||
*
|
*
|
||||||
* Identical to fdt_getprop(), but only examine the first namelen
|
* Identical to fdt_getprop(), but only examine the first namelen
|
||||||
* characters of name for matching the property name.
|
* characters of name for matching the property name.
|
||||||
|
*
|
||||||
|
* Return: pointer to the property's value or NULL on error
|
||||||
*/
|
*/
|
||||||
#ifndef SWIG /* Not available in Python */
|
#ifndef SWIG /* Not available in Python */
|
||||||
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||||
|
@ -766,10 +789,10 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
|
||||||
* @lenp: pointer to an integer variable (will be overwritten) or NULL
|
* @lenp: pointer to an integer variable (will be overwritten) or NULL
|
||||||
*
|
*
|
||||||
* fdt_getprop() retrieves a pointer to the value of the property
|
* fdt_getprop() retrieves a pointer to the value of the property
|
||||||
* named 'name' of the node at offset nodeoffset (this will be a
|
* named @name of the node at offset @nodeoffset (this will be a
|
||||||
* pointer to within the device blob itself, not a copy of the value).
|
* pointer to within the device blob itself, not a copy of the value).
|
||||||
* If lenp is non-NULL, the length of the property value is also
|
* If @lenp is non-NULL, the length of the property value is also
|
||||||
* returned, in the integer pointed to by lenp.
|
* returned, in the integer pointed to by @lenp.
|
||||||
*
|
*
|
||||||
* returns:
|
* returns:
|
||||||
* pointer to the property's value
|
* pointer to the property's value
|
||||||
|
@ -814,8 +837,11 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
|
||||||
* @name: name of the alias th look up
|
* @name: name of the alias th look up
|
||||||
* @namelen: number of characters of name to consider
|
* @namelen: number of characters of name to consider
|
||||||
*
|
*
|
||||||
* Identical to fdt_get_alias(), but only examine the first namelen
|
* Identical to fdt_get_alias(), but only examine the first @namelen
|
||||||
* characters of name for matching the alias name.
|
* characters of @name for matching the alias name.
|
||||||
|
*
|
||||||
|
* Return: a pointer to the expansion of the alias named @name, if it exists,
|
||||||
|
* NULL otherwise
|
||||||
*/
|
*/
|
||||||
#ifndef SWIG /* Not available in Python */
|
#ifndef SWIG /* Not available in Python */
|
||||||
const char *fdt_get_alias_namelen(const void *fdt,
|
const char *fdt_get_alias_namelen(const void *fdt,
|
||||||
|
@ -828,7 +854,7 @@ const char *fdt_get_alias_namelen(const void *fdt,
|
||||||
* @name: name of the alias th look up
|
* @name: name of the alias th look up
|
||||||
*
|
*
|
||||||
* fdt_get_alias() retrieves the value of a given alias. That is, the
|
* fdt_get_alias() retrieves the value of a given alias. That is, the
|
||||||
* value of the property named 'name' in the node /aliases.
|
* value of the property named @name in the node /aliases.
|
||||||
*
|
*
|
||||||
* returns:
|
* returns:
|
||||||
* a pointer to the expansion of the alias named 'name', if it exists
|
* a pointer to the expansion of the alias named 'name', if it exists
|
||||||
|
@ -1004,14 +1030,13 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
|
||||||
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
|
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_node_check_compatible: check a node's compatible property
|
* fdt_node_check_compatible - check a node's compatible property
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
* @nodeoffset: offset of a tree node
|
* @nodeoffset: offset of a tree node
|
||||||
* @compatible: string to match against
|
* @compatible: string to match against
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* fdt_node_check_compatible() returns 0 if the given node contains a
|
* fdt_node_check_compatible() returns 0 if the given node contains a
|
||||||
* 'compatible' property with the given string as one of its elements,
|
* @compatible property with the given string as one of its elements,
|
||||||
* it returns non-zero otherwise, or on error.
|
* it returns non-zero otherwise, or on error.
|
||||||
*
|
*
|
||||||
* returns:
|
* returns:
|
||||||
|
@ -1075,7 +1100,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
|
||||||
* one or more strings, each terminated by \0, as is found in a device tree
|
* one or more strings, each terminated by \0, as is found in a device tree
|
||||||
* "compatible" property.
|
* "compatible" property.
|
||||||
*
|
*
|
||||||
* @return: 1 if the string is found in the list, 0 not found, or invalid list
|
* Return: 1 if the string is found in the list, 0 not found, or invalid list
|
||||||
*/
|
*/
|
||||||
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
|
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
|
||||||
|
|
||||||
|
@ -1084,7 +1109,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
* @nodeoffset: offset of a tree node
|
* @nodeoffset: offset of a tree node
|
||||||
* @property: name of the property containing the string list
|
* @property: name of the property containing the string list
|
||||||
* @return:
|
*
|
||||||
|
* Return:
|
||||||
* the number of strings in the given property
|
* the number of strings in the given property
|
||||||
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
|
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
|
||||||
* -FDT_ERR_NOTFOUND if the property does not exist
|
* -FDT_ERR_NOTFOUND if the property does not exist
|
||||||
|
@ -1104,7 +1130,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property);
|
||||||
* small-valued cell properties, such as #address-cells, when searching for
|
* small-valued cell properties, such as #address-cells, when searching for
|
||||||
* the empty string.
|
* the empty string.
|
||||||
*
|
*
|
||||||
* @return:
|
* return:
|
||||||
* the index of the string in the list of strings
|
* the index of the string in the list of strings
|
||||||
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
|
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
|
||||||
* -FDT_ERR_NOTFOUND if the property does not exist or does not contain
|
* -FDT_ERR_NOTFOUND if the property does not exist or does not contain
|
||||||
|
@ -1128,7 +1154,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
|
||||||
* If non-NULL, the length of the string (on success) or a negative error-code
|
* If non-NULL, the length of the string (on success) or a negative error-code
|
||||||
* (on failure) will be stored in the integer pointer to by lenp.
|
* (on failure) will be stored in the integer pointer to by lenp.
|
||||||
*
|
*
|
||||||
* @return:
|
* Return:
|
||||||
* A pointer to the string at the given index in the string list or NULL on
|
* A pointer to the string at the given index in the string list or NULL on
|
||||||
* failure. On success the length of the string will be stored in the memory
|
* failure. On success the length of the string will be stored in the memory
|
||||||
* location pointed to by the lenp parameter, if non-NULL. On failure one of
|
* location pointed to by the lenp parameter, if non-NULL. On failure one of
|
||||||
|
@ -1217,6 +1243,8 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
|
||||||
* starting from the given index, and using only the first characters
|
* starting from the given index, and using only the first characters
|
||||||
* of the name. It is useful when you want to manipulate only one value of
|
* of the name. It is useful when you want to manipulate only one value of
|
||||||
* an array and you have a string that doesn't end with \0.
|
* an array and you have a string that doesn't end with \0.
|
||||||
|
*
|
||||||
|
* Return: 0 on success, negative libfdt error value otherwise
|
||||||
*/
|
*/
|
||||||
#ifndef SWIG /* Not available in Python */
|
#ifndef SWIG /* Not available in Python */
|
||||||
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||||||
|
@ -1330,8 +1358,13 @@ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_setprop_inplace_cell - change the value of a single-cell property
|
* fdt_setprop_inplace_cell - change the value of a single-cell property
|
||||||
|
* @fdt: pointer to the device tree blob
|
||||||
|
* @nodeoffset: offset of the node containing the property
|
||||||
|
* @name: name of the property to change the value of
|
||||||
|
* @val: new value of the 32-bit cell
|
||||||
*
|
*
|
||||||
* This is an alternative name for fdt_setprop_inplace_u32()
|
* This is an alternative name for fdt_setprop_inplace_u32()
|
||||||
|
* Return: 0 on success, negative libfdt error number otherwise.
|
||||||
*/
|
*/
|
||||||
static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
|
static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
|
||||||
const char *name, uint32_t val)
|
const char *name, uint32_t val)
|
||||||
|
@ -1403,7 +1436,7 @@ int fdt_nop_node(void *fdt, int nodeoffset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_create_with_flags - begin creation of a new fdt
|
* fdt_create_with_flags - begin creation of a new fdt
|
||||||
* @fdt: pointer to memory allocated where fdt will be created
|
* @buf: pointer to memory allocated where fdt will be created
|
||||||
* @bufsize: size of the memory space at fdt
|
* @bufsize: size of the memory space at fdt
|
||||||
* @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
|
* @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
|
||||||
*
|
*
|
||||||
|
@ -1421,7 +1454,7 @@ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_create - begin creation of a new fdt
|
* fdt_create - begin creation of a new fdt
|
||||||
* @fdt: pointer to memory allocated where fdt will be created
|
* @buf: pointer to memory allocated where fdt will be created
|
||||||
* @bufsize: size of the memory space at fdt
|
* @bufsize: size of the memory space at fdt
|
||||||
*
|
*
|
||||||
* fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
|
* fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
|
||||||
|
@ -1486,7 +1519,8 @@ int fdt_pack(void *fdt);
|
||||||
/**
|
/**
|
||||||
* fdt_add_mem_rsv - add one memory reserve map entry
|
* fdt_add_mem_rsv - add one memory reserve map entry
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
* @address, @size: 64-bit values (native endian)
|
* @address: 64-bit start address of the reserve map entry
|
||||||
|
* @size: 64-bit size of the reserved region
|
||||||
*
|
*
|
||||||
* Adds a reserve map entry to the given blob reserving a region at
|
* Adds a reserve map entry to the given blob reserving a region at
|
||||||
* address address of length size.
|
* address address of length size.
|
||||||
|
@ -1691,8 +1725,14 @@ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_setprop_cell - set a property to a single cell value
|
* fdt_setprop_cell - set a property to a single cell value
|
||||||
|
* @fdt: pointer to the device tree blob
|
||||||
|
* @nodeoffset: offset of the node whose property to change
|
||||||
|
* @name: name of the property to change
|
||||||
|
* @val: 32-bit integer value for the property (native endian)
|
||||||
*
|
*
|
||||||
* This is an alternative name for fdt_setprop_u32()
|
* This is an alternative name for fdt_setprop_u32()
|
||||||
|
*
|
||||||
|
* Return: 0 on success, negative libfdt error value otherwise.
|
||||||
*/
|
*/
|
||||||
static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
|
static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
|
||||||
uint32_t val)
|
uint32_t val)
|
||||||
|
@ -1863,8 +1903,14 @@ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_appendprop_cell - append a single cell value to a property
|
* fdt_appendprop_cell - append a single cell value to a property
|
||||||
|
* @fdt: pointer to the device tree blob
|
||||||
|
* @nodeoffset: offset of the node whose property to change
|
||||||
|
* @name: name of the property to change
|
||||||
|
* @val: 32-bit integer value to append to the property (native endian)
|
||||||
*
|
*
|
||||||
* This is an alternative name for fdt_appendprop_u32()
|
* This is an alternative name for fdt_appendprop_u32()
|
||||||
|
*
|
||||||
|
* Return: 0 on success, negative libfdt error value otherwise.
|
||||||
*/
|
*/
|
||||||
static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
|
static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
|
||||||
const char *name, uint32_t val)
|
const char *name, uint32_t val)
|
||||||
|
@ -1967,13 +2013,16 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name);
|
||||||
* fdt_add_subnode_namelen - creates a new node based on substring
|
* fdt_add_subnode_namelen - creates a new node based on substring
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
* @parentoffset: structure block offset of a node
|
* @parentoffset: structure block offset of a node
|
||||||
* @name: name of the subnode to locate
|
* @name: name of the subnode to create
|
||||||
* @namelen: number of characters of name to consider
|
* @namelen: number of characters of name to consider
|
||||||
*
|
*
|
||||||
* Identical to fdt_add_subnode(), but use only the first namelen
|
* Identical to fdt_add_subnode(), but use only the first @namelen
|
||||||
* characters of name as the name of the new node. This is useful for
|
* characters of @name as the name of the new node. This is useful for
|
||||||
* creating subnodes based on a portion of a larger string, such as a
|
* creating subnodes based on a portion of a larger string, such as a
|
||||||
* full path.
|
* full path.
|
||||||
|
*
|
||||||
|
* Return: structure block offset of the created subnode (>=0),
|
||||||
|
* negative libfdt error value otherwise
|
||||||
*/
|
*/
|
||||||
#ifndef SWIG /* Not available in Python */
|
#ifndef SWIG /* Not available in Python */
|
||||||
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||||||
|
@ -1992,7 +2041,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||||||
*
|
*
|
||||||
* This function will insert data into the blob, and will therefore
|
* This function will insert data into the blob, and will therefore
|
||||||
* change the offsets of some existing nodes.
|
* change the offsets of some existing nodes.
|
||||||
|
*
|
||||||
* returns:
|
* returns:
|
||||||
* structure block offset of the created nodeequested subnode (>=0), on
|
* structure block offset of the created nodeequested subnode (>=0), on
|
||||||
* success
|
* success
|
||||||
|
@ -2067,6 +2116,24 @@ int fdt_del_node(void *fdt, int nodeoffset);
|
||||||
*/
|
*/
|
||||||
int fdt_overlay_apply(void *fdt, void *fdto);
|
int fdt_overlay_apply(void *fdt, void *fdto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_overlay_target_offset - retrieves the offset of a fragment's target
|
||||||
|
* @fdt: Base device tree blob
|
||||||
|
* @fdto: Device tree overlay blob
|
||||||
|
* @fragment_offset: node offset of the fragment in the overlay
|
||||||
|
* @pathp: pointer which receives the path of the target (or NULL)
|
||||||
|
*
|
||||||
|
* fdt_overlay_target_offset() retrieves the target offset in the base
|
||||||
|
* device tree of a fragment, no matter how the actual targeting is
|
||||||
|
* done (through a phandle or a path)
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* the targeted node offset in the base device tree
|
||||||
|
* Negative error code on error
|
||||||
|
*/
|
||||||
|
int fdt_overlay_target_offset(const void *fdt, const void *fdto,
|
||||||
|
int fragment_offset, char const **pathp);
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/* Debugging / informational functions */
|
/* Debugging / informational functions */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
|
@ -46,6 +46,25 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
|
||||||
return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
|
return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal helpers to access tructural elements of the device tree
|
||||||
|
* blob (rather than for exaple reading integers from within property
|
||||||
|
* values). We assume that we are either given a naturally aligned
|
||||||
|
* address for the platform or if we are not, we are on a platform
|
||||||
|
* where unaligned memory reads will be handled in a graceful manner.
|
||||||
|
* If not the external helpers fdtXX_ld() from libfdt.h can be used
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
|
static inline uint32_t fdt32_ld_(const fdt32_t *p)
|
||||||
|
{
|
||||||
|
return fdt32_to_cpu(*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t fdt64_ld_(const fdt64_t *p)
|
||||||
|
{
|
||||||
|
return fdt64_to_cpu(*p);
|
||||||
|
}
|
||||||
|
|
||||||
#define FDT_SW_MAGIC (~FDT_MAGIC)
|
#define FDT_SW_MAGIC (~FDT_MAGIC)
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
55
libfdt/meson.build
Normal file
55
libfdt/meson.build
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
version_script = '-Wl,--version-script=@0@'.format(meson.current_source_dir() / 'version.lds')
|
||||||
|
if not cc.has_link_argument(version_script)
|
||||||
|
version_script = []
|
||||||
|
endif
|
||||||
|
|
||||||
|
sources = files(
|
||||||
|
'fdt.c',
|
||||||
|
'fdt_addresses.c',
|
||||||
|
'fdt_check.c',
|
||||||
|
'fdt_empty_tree.c',
|
||||||
|
'fdt_overlay.c',
|
||||||
|
'fdt_ro.c',
|
||||||
|
'fdt_rw.c',
|
||||||
|
'fdt_strerror.c',
|
||||||
|
'fdt_sw.c',
|
||||||
|
'fdt_wip.c',
|
||||||
|
)
|
||||||
|
|
||||||
|
libfdt = library(
|
||||||
|
'fdt', sources,
|
||||||
|
version: '1.6.0',
|
||||||
|
link_args: ['-Wl,--no-undefined', version_script],
|
||||||
|
link_depends: 'version.lds',
|
||||||
|
install: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
libfdt_a = static_library(
|
||||||
|
'fdt', sources,
|
||||||
|
install: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
libfdt_inc = include_directories('.')
|
||||||
|
|
||||||
|
libfdt_dep = declare_dependency(
|
||||||
|
include_directories: libfdt_inc,
|
||||||
|
link_with: libfdt,
|
||||||
|
)
|
||||||
|
|
||||||
|
install_headers(
|
||||||
|
files(
|
||||||
|
'fdt.h',
|
||||||
|
'libfdt.h',
|
||||||
|
'libfdt_env.h',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
pkgconfig = import('pkgconfig')
|
||||||
|
|
||||||
|
pkgconfig.generate(
|
||||||
|
libraries: libfdt,
|
||||||
|
version: meson.project_version(),
|
||||||
|
filebase: 'libfdt',
|
||||||
|
name: 'libfdt',
|
||||||
|
description: 'Flat Device Tree manipulation',
|
||||||
|
)
|
|
@ -77,6 +77,7 @@ LIBFDT_1.2 {
|
||||||
fdt_appendprop_addrrange;
|
fdt_appendprop_addrrange;
|
||||||
fdt_setprop_inplace_namelen_partial;
|
fdt_setprop_inplace_namelen_partial;
|
||||||
fdt_create_with_flags;
|
fdt_create_with_flags;
|
||||||
|
fdt_overlay_target_offset;
|
||||||
local:
|
local:
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
41
livetree.c
41
livetree.c
|
@ -438,7 +438,7 @@ cell_t propval_cell(struct property *prop)
|
||||||
return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
|
return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t propval_cell_n(struct property *prop, int n)
|
cell_t propval_cell_n(struct property *prop, unsigned int n)
|
||||||
{
|
{
|
||||||
assert(prop->val.len / sizeof(cell_t) >= n);
|
assert(prop->val.len / sizeof(cell_t) >= n);
|
||||||
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
|
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
|
||||||
|
@ -526,7 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
|
||||||
p = strchr(path, '/');
|
p = strchr(path, '/');
|
||||||
|
|
||||||
for_each_child(tree, child) {
|
for_each_child(tree, child) {
|
||||||
if (p && strprefixeq(path, p - path, child->name))
|
if (p && strprefixeq(path, (size_t)(p - path), child->name))
|
||||||
return get_node_by_path(child, p+1);
|
return get_node_by_path(child, p+1);
|
||||||
else if (!p && streq(path, child->name))
|
else if (!p && streq(path, child->name))
|
||||||
return child;
|
return child;
|
||||||
|
@ -559,7 +559,7 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
|
||||||
{
|
{
|
||||||
struct node *child, *node;
|
struct node *child, *node;
|
||||||
|
|
||||||
if ((phandle == 0) || (phandle == -1)) {
|
if (!phandle_is_valid(phandle)) {
|
||||||
assert(generate_fixups);
|
assert(generate_fixups);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -581,12 +581,39 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
|
||||||
|
|
||||||
struct node *get_node_by_ref(struct node *tree, const char *ref)
|
struct node *get_node_by_ref(struct node *tree, const char *ref)
|
||||||
{
|
{
|
||||||
|
struct node *target = tree;
|
||||||
|
const char *label = NULL, *path = NULL;
|
||||||
|
|
||||||
if (streq(ref, "/"))
|
if (streq(ref, "/"))
|
||||||
return tree;
|
return tree;
|
||||||
else if (ref[0] == '/')
|
|
||||||
return get_node_by_path(tree, ref);
|
if (ref[0] == '/')
|
||||||
|
path = ref;
|
||||||
else
|
else
|
||||||
return get_node_by_label(tree, ref);
|
label = ref;
|
||||||
|
|
||||||
|
if (label) {
|
||||||
|
const char *slash = strchr(label, '/');
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
if (slash) {
|
||||||
|
buf = xstrndup(label, slash - label);
|
||||||
|
label = buf;
|
||||||
|
path = slash + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = get_node_by_label(tree, label);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if (!target)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path)
|
||||||
|
target = get_node_by_path(target, path);
|
||||||
|
|
||||||
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t get_node_phandle(struct node *root, struct node *node)
|
cell_t get_node_phandle(struct node *root, struct node *node)
|
||||||
|
@ -594,7 +621,7 @@ cell_t get_node_phandle(struct node *root, struct node *node)
|
||||||
static cell_t phandle = 1; /* FIXME: ick, static local */
|
static cell_t phandle = 1; /* FIXME: ick, static local */
|
||||||
struct data d = empty_data;
|
struct data d = empty_data;
|
||||||
|
|
||||||
if ((node->phandle != 0) && (node->phandle != -1))
|
if (phandle_is_valid(node->phandle))
|
||||||
return node->phandle;
|
return node->phandle;
|
||||||
|
|
||||||
while (get_node_by_phandle(root, phandle))
|
while (get_node_by_phandle(root, phandle))
|
||||||
|
|
129
meson.build
Normal file
129
meson.build
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
project('dtc', 'c',
|
||||||
|
version: '1.6.0',
|
||||||
|
license: ['GPL2+', 'BSD-2'],
|
||||||
|
default_options: 'werror=true',
|
||||||
|
)
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
|
add_project_arguments(
|
||||||
|
cc.get_supported_arguments([
|
||||||
|
'-Wpointer-arith',
|
||||||
|
'-Wcast-qual',
|
||||||
|
'-Wnested-externs',
|
||||||
|
'-Wstrict-prototypes',
|
||||||
|
'-Wmissing-prototypes',
|
||||||
|
'-Wredundant-decls',
|
||||||
|
'-Wshadow'
|
||||||
|
]),
|
||||||
|
language: 'c'
|
||||||
|
)
|
||||||
|
|
||||||
|
if host_machine.system() == 'windows'
|
||||||
|
add_project_arguments(
|
||||||
|
'-D__USE_MINGW_ANSI_STDIO=1',
|
||||||
|
language: 'c'
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
add_project_arguments(
|
||||||
|
'-DFDT_ASSUME_MASK=' + get_option('assume-mask').to_string(),
|
||||||
|
language: 'c'
|
||||||
|
)
|
||||||
|
|
||||||
|
yamltree = 'yamltree.c'
|
||||||
|
yaml = dependency('yaml-0.1', required: get_option('yaml'))
|
||||||
|
if not yaml.found()
|
||||||
|
add_project_arguments('-DNO_YAML', language: 'c')
|
||||||
|
yamltree = []
|
||||||
|
endif
|
||||||
|
|
||||||
|
valgrind = dependency('valgrind', required: get_option('valgrind'))
|
||||||
|
if not valgrind.found()
|
||||||
|
add_project_arguments('-DNO_VALGRIND', language: 'c')
|
||||||
|
endif
|
||||||
|
|
||||||
|
py = import('python')
|
||||||
|
py = py.find_installation(required: get_option('python'))
|
||||||
|
swig = find_program('swig', required: get_option('python'))
|
||||||
|
|
||||||
|
version_gen_h = vcs_tag(
|
||||||
|
input: 'version_gen.h.in',
|
||||||
|
output: 'version_gen.h',
|
||||||
|
)
|
||||||
|
|
||||||
|
subdir('libfdt')
|
||||||
|
|
||||||
|
if get_option('tools')
|
||||||
|
flex = find_program('flex', required: true)
|
||||||
|
bison = find_program('bison', required: true)
|
||||||
|
|
||||||
|
util_dep = declare_dependency(
|
||||||
|
sources: ['util.c', version_gen_h],
|
||||||
|
include_directories: '.',
|
||||||
|
dependencies: libfdt_dep
|
||||||
|
)
|
||||||
|
|
||||||
|
lgen = generator(
|
||||||
|
flex,
|
||||||
|
output: '@PLAINNAME@.lex.c',
|
||||||
|
arguments: ['-o', '@OUTPUT@', '@INPUT@'],
|
||||||
|
)
|
||||||
|
|
||||||
|
pgen = generator(
|
||||||
|
bison,
|
||||||
|
output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'],
|
||||||
|
arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@'],
|
||||||
|
)
|
||||||
|
|
||||||
|
if cc.check_header('fnmatch.h')
|
||||||
|
executable(
|
||||||
|
'convert-dtsv0',
|
||||||
|
[
|
||||||
|
lgen.process('convert-dtsv0-lexer.l'),
|
||||||
|
'srcpos.c',
|
||||||
|
],
|
||||||
|
dependencies: util_dep,
|
||||||
|
install: true,
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
executable(
|
||||||
|
'dtc',
|
||||||
|
[
|
||||||
|
lgen.process('dtc-lexer.l'),
|
||||||
|
pgen.process('dtc-parser.y'),
|
||||||
|
'checks.c',
|
||||||
|
'data.c',
|
||||||
|
'dtc.c',
|
||||||
|
'flattree.c',
|
||||||
|
'fstree.c',
|
||||||
|
'livetree.c',
|
||||||
|
'srcpos.c',
|
||||||
|
'treesource.c',
|
||||||
|
yamltree,
|
||||||
|
],
|
||||||
|
dependencies: [util_dep, yaml],
|
||||||
|
install: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach e: ['fdtdump', 'fdtget', 'fdtput', 'fdtoverlay']
|
||||||
|
executable(e, files(e + '.c'), dependencies: util_dep, install: true)
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
install_data(
|
||||||
|
'dtdiff',
|
||||||
|
install_dir: get_option('prefix') / get_option('bindir'),
|
||||||
|
install_mode: 'rwxr-xr-x',
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if not meson.is_cross_build()
|
||||||
|
if py.found() and swig.found()
|
||||||
|
subdir('pylibfdt')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('tools')
|
||||||
|
subdir('tests')
|
||||||
|
endif
|
||||||
|
endif
|
10
meson_options.txt
Normal file
10
meson_options.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
option('tools', type: 'boolean', value: true,
|
||||||
|
description: 'Build tools')
|
||||||
|
option('assume-mask', type: 'integer', value: 0,
|
||||||
|
description: 'Control the assumptions made (e.g. risking security issues) in the code.')
|
||||||
|
option('yaml', type: 'feature', value: 'auto',
|
||||||
|
description: 'YAML support')
|
||||||
|
option('valgrind', type: 'feature', value: 'auto',
|
||||||
|
description: 'Valgrind support')
|
||||||
|
option('python', type: 'feature', value: 'auto',
|
||||||
|
description: 'Build pylibfdt Python library')
|
|
@ -9,16 +9,15 @@ PYLIBFDT_CLEANFILES = $(PYLIBFDT_CLEANFILES_L:%=$(PYLIBFDT_dir)/%)
|
||||||
PYLIBFDT_CLEANDIRS_L = build __pycache__
|
PYLIBFDT_CLEANDIRS_L = build __pycache__
|
||||||
PYLIBFDT_CLEANDIRS = $(PYLIBFDT_CLEANDIRS_L:%=$(PYLIBFDT_dir)/%)
|
PYLIBFDT_CLEANDIRS = $(PYLIBFDT_CLEANDIRS_L:%=$(PYLIBFDT_dir)/%)
|
||||||
|
|
||||||
SETUP = $(PYLIBFDT_dir)/setup.py
|
SETUP = ./setup.py
|
||||||
SETUPFLAGS =
|
|
||||||
|
|
||||||
ifndef V
|
ifndef V
|
||||||
SETUPFLAGS += --quiet
|
SETUPFLAGS += --quiet
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(PYMODULE): $(PYLIBFDT_srcs) $(LIBFDT_archive) $(SETUP) $(VERSION_FILE)
|
$(PYMODULE): $(PYLIBFDT_srcs) $(LIBFDT_archive) $(SETUP)
|
||||||
@$(VECHO) PYMOD $@
|
@$(VECHO) PYMOD $@
|
||||||
$(PYTHON) $(SETUP) $(SETUPFLAGS) build_ext --build-lib=../$(PYLIBFDT_dir)
|
$(PYTHON) $(SETUP) $(SETUPFLAGS) build_ext --build-lib=$(PYLIBFDT_dir)
|
||||||
|
|
||||||
install_pylibfdt: $(PYMODULE)
|
install_pylibfdt: $(PYMODULE)
|
||||||
@$(VECHO) INSTALL-PYLIB
|
@$(VECHO) INSTALL-PYLIB
|
||||||
|
|
|
@ -443,6 +443,29 @@ class FdtRo(object):
|
||||||
"""
|
"""
|
||||||
return fdt_get_alias(self._fdt, name)
|
return fdt_get_alias(self._fdt, name)
|
||||||
|
|
||||||
|
def get_path(self, nodeoffset, quiet=()):
|
||||||
|
"""Get the full path of a node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nodeoffset: Node offset to check
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Full path to the node
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if an error occurs
|
||||||
|
"""
|
||||||
|
size = 1024
|
||||||
|
while True:
|
||||||
|
ret, path = fdt_get_path(self._fdt, nodeoffset, size)
|
||||||
|
if ret == -NOSPACE:
|
||||||
|
size = size * 2
|
||||||
|
continue
|
||||||
|
err = check_err(ret, quiet)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
return path
|
||||||
|
|
||||||
def parent_offset(self, nodeoffset, quiet=()):
|
def parent_offset(self, nodeoffset, quiet=()):
|
||||||
"""Get the offset of a node's parent
|
"""Get the offset of a node's parent
|
||||||
|
|
||||||
|
@ -716,6 +739,21 @@ class Property(bytearray):
|
||||||
def as_int64(self):
|
def as_int64(self):
|
||||||
return self.as_cell('q')
|
return self.as_cell('q')
|
||||||
|
|
||||||
|
def as_list(self, fmt):
|
||||||
|
return list(map(lambda x: x[0], struct.iter_unpack('>' + fmt, self)))
|
||||||
|
|
||||||
|
def as_uint32_list(self):
|
||||||
|
return self.as_list('L')
|
||||||
|
|
||||||
|
def as_int32_list(self):
|
||||||
|
return self.as_list('l')
|
||||||
|
|
||||||
|
def as_uint64_list(self):
|
||||||
|
return self.as_list('Q')
|
||||||
|
|
||||||
|
def as_int64_list(self):
|
||||||
|
return self.as_list('q')
|
||||||
|
|
||||||
def as_str(self):
|
def as_str(self):
|
||||||
"""Unicode is supported by decoding from UTF-8"""
|
"""Unicode is supported by decoding from UTF-8"""
|
||||||
if self[-1] != 0:
|
if self[-1] != 0:
|
||||||
|
@ -724,6 +762,13 @@ class Property(bytearray):
|
||||||
raise ValueError('Property contains embedded nul characters')
|
raise ValueError('Property contains embedded nul characters')
|
||||||
return self[:-1].decode('utf-8')
|
return self[:-1].decode('utf-8')
|
||||||
|
|
||||||
|
def as_stringlist(self):
|
||||||
|
"""Unicode is supported by decoding from UTF-8"""
|
||||||
|
if self[-1] != 0:
|
||||||
|
raise ValueError('Property lacks nul termination')
|
||||||
|
parts = self[:-1].split(b'\x00')
|
||||||
|
return list(map(lambda x: x.decode('utf-8'), parts))
|
||||||
|
|
||||||
|
|
||||||
class FdtSw(FdtRo):
|
class FdtSw(FdtRo):
|
||||||
"""Software interface to create a device tree from scratch
|
"""Software interface to create a device tree from scratch
|
||||||
|
@ -1009,7 +1054,7 @@ typedef uint32_t fdt32_t;
|
||||||
}
|
}
|
||||||
$1 = (void *)PyByteArray_AsString($input);
|
$1 = (void *)PyByteArray_AsString($input);
|
||||||
fdt = $1;
|
fdt = $1;
|
||||||
fdt = fdt; /* avoid unused variable warning */
|
(void)fdt; /* avoid unused variable warning */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Some functions do change the device tree, so use void * */
|
/* Some functions do change the device tree, so use void * */
|
||||||
|
@ -1020,7 +1065,7 @@ typedef uint32_t fdt32_t;
|
||||||
}
|
}
|
||||||
$1 = PyByteArray_AsString($input);
|
$1 = PyByteArray_AsString($input);
|
||||||
fdt = $1;
|
fdt = $1;
|
||||||
fdt = fdt; /* avoid unused variable warning */
|
(void)fdt; /* avoid unused variable warning */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* typemap used for fdt_get_property_by_offset() */
|
/* typemap used for fdt_get_property_by_offset() */
|
||||||
|
@ -1040,14 +1085,16 @@ typedef uint32_t fdt32_t;
|
||||||
|
|
||||||
/* typemap used for fdt_getprop() */
|
/* typemap used for fdt_getprop() */
|
||||||
%typemap(out) (const void *) {
|
%typemap(out) (const void *) {
|
||||||
if (!$1)
|
if (!$1) {
|
||||||
$result = Py_None;
|
$result = Py_None;
|
||||||
else
|
Py_INCREF($result);
|
||||||
|
} else {
|
||||||
%#if PY_VERSION_HEX >= 0x03000000
|
%#if PY_VERSION_HEX >= 0x03000000
|
||||||
$result = Py_BuildValue("y#", $1, *arg4);
|
$result = Py_BuildValue("y#", $1, (Py_ssize_t)*arg4);
|
||||||
%#else
|
%#else
|
||||||
$result = Py_BuildValue("s#", $1, *arg4);
|
$result = Py_BuildValue("s#", $1, (Py_ssize_t)*arg4);
|
||||||
%#endif
|
%#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* typemap used for fdt_setprop() */
|
/* typemap used for fdt_setprop() */
|
||||||
|
@ -1091,6 +1138,11 @@ typedef uint32_t fdt32_t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%include "cstring.i"
|
||||||
|
|
||||||
|
%cstring_output_maxsize(char *buf, int buflen);
|
||||||
|
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
|
||||||
|
|
||||||
/* We have both struct fdt_property and a function fdt_property() */
|
/* We have both struct fdt_property and a function fdt_property() */
|
||||||
%warnfilter(302) fdt_property;
|
%warnfilter(302) fdt_property;
|
||||||
|
|
||||||
|
|
12
pylibfdt/meson.build
Normal file
12
pylibfdt/meson.build
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
setup_py = find_program('../setup.py')
|
||||||
|
setup_py = [setup_py.path(), '--quiet', '--top-builddir', meson.project_build_root()]
|
||||||
|
|
||||||
|
custom_target(
|
||||||
|
'pylibfdt',
|
||||||
|
input: 'libfdt.i',
|
||||||
|
output: '_libfdt.so',
|
||||||
|
command: [setup_py, 'build_ext', '--build-lib=' + meson.current_build_dir()],
|
||||||
|
build_by_default: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
meson.add_install_script(setup_py, 'install', '--prefix=' + get_option('prefix'), '--root=$DESTDIR')
|
|
@ -1,48 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
|
||||||
|
|
||||||
# While Python 3 is the default, it's also possible to invoke
|
|
||||||
# this setup.py script with Python 2.
|
|
||||||
|
|
||||||
"""
|
|
||||||
setup.py file for SWIG libfdt
|
|
||||||
Copyright (C) 2017 Google, Inc.
|
|
||||||
Written by Simon Glass <sjg@chromium.org>
|
|
||||||
"""
|
|
||||||
|
|
||||||
from distutils.core import setup, Extension
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
VERSION_PATTERN = '^#define DTC_VERSION "DTC ([^"]*)"$'
|
|
||||||
|
|
||||||
|
|
||||||
def get_version():
|
|
||||||
version_file = "../version_gen.h"
|
|
||||||
f = open(version_file, 'rt')
|
|
||||||
m = re.match(VERSION_PATTERN, f.readline())
|
|
||||||
return m.group(1)
|
|
||||||
|
|
||||||
|
|
||||||
setupdir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
|
||||||
os.chdir(setupdir)
|
|
||||||
|
|
||||||
libfdt_module = Extension(
|
|
||||||
'_libfdt',
|
|
||||||
sources=['libfdt.i'],
|
|
||||||
include_dirs=['../libfdt'],
|
|
||||||
libraries=['fdt'],
|
|
||||||
library_dirs=['../libfdt'],
|
|
||||||
swig_opts=['-I../libfdt'],
|
|
||||||
)
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name='libfdt',
|
|
||||||
version=get_version(),
|
|
||||||
author='Simon Glass <sjg@chromium.org>',
|
|
||||||
description='Python binding for libfdt',
|
|
||||||
ext_modules=[libfdt_module],
|
|
||||||
py_modules=['libfdt'],
|
|
||||||
)
|
|
77
setup.py
Executable file
77
setup.py
Executable file
|
@ -0,0 +1,77 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||||
|
|
||||||
|
# While Python 3 is the default, it's also possible to invoke
|
||||||
|
# this setup.py script with Python 2.
|
||||||
|
|
||||||
|
"""
|
||||||
|
setup.py file for SWIG libfdt
|
||||||
|
Copyright (C) 2017 Google, Inc.
|
||||||
|
Written by Simon Glass <sjg@chromium.org>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from setuptools import setup, Extension
|
||||||
|
from setuptools.command.build_py import build_py as _build_py
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
srcdir = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
with open(os.path.join(srcdir, "README"), "r") as fh:
|
||||||
|
long_description = fh.read()
|
||||||
|
|
||||||
|
def get_top_builddir():
|
||||||
|
if '--top-builddir' in sys.argv:
|
||||||
|
index = sys.argv.index('--top-builddir')
|
||||||
|
sys.argv.pop(index)
|
||||||
|
return sys.argv.pop(index)
|
||||||
|
else:
|
||||||
|
return srcdir
|
||||||
|
|
||||||
|
top_builddir = get_top_builddir()
|
||||||
|
|
||||||
|
libfdt_module = Extension(
|
||||||
|
'_libfdt',
|
||||||
|
sources=[os.path.join(srcdir, 'pylibfdt/libfdt.i')],
|
||||||
|
define_macros=[('PY_SSIZE_T_CLEAN', None)],
|
||||||
|
include_dirs=[os.path.join(srcdir, 'libfdt')],
|
||||||
|
libraries=['fdt'],
|
||||||
|
library_dirs=[os.path.join(top_builddir, 'libfdt')],
|
||||||
|
swig_opts=['-I' + os.path.join(srcdir, 'libfdt')],
|
||||||
|
)
|
||||||
|
|
||||||
|
class build_py(_build_py):
|
||||||
|
def run(self):
|
||||||
|
self.run_command("build_ext")
|
||||||
|
return super().run()
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='libfdt',
|
||||||
|
use_scm_version={
|
||||||
|
"root": srcdir,
|
||||||
|
},
|
||||||
|
cmdclass = {'build_py' : build_py},
|
||||||
|
setup_requires = ['setuptools_scm'],
|
||||||
|
author='Simon Glass',
|
||||||
|
author_email='sjg@chromium.org',
|
||||||
|
description='Python binding for libfdt',
|
||||||
|
ext_modules=[libfdt_module],
|
||||||
|
package_dir={'': os.path.join(srcdir, 'pylibfdt')},
|
||||||
|
py_modules=['libfdt'],
|
||||||
|
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type="text/plain",
|
||||||
|
url="https://git.kernel.org/pub/scm/utils/dtc/dtc.git",
|
||||||
|
license="BSD",
|
||||||
|
license_files=["GPL", "BSD-2-Clause"],
|
||||||
|
|
||||||
|
classifiers=[
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"License :: OSI Approved :: BSD License",
|
||||||
|
"License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
],
|
||||||
|
|
||||||
|
)
|
2
srcpos.c
2
srcpos.c
|
@ -20,7 +20,7 @@ struct search_path {
|
||||||
static struct search_path *search_path_head, **search_path_tail;
|
static struct search_path *search_path_head, **search_path_tail;
|
||||||
|
|
||||||
/* Detect infinite include recursion. */
|
/* Detect infinite include recursion. */
|
||||||
#define MAX_SRCFILE_DEPTH (100)
|
#define MAX_SRCFILE_DEPTH (200)
|
||||||
static int srcfile_depth; /* = 0 */
|
static int srcfile_depth; /* = 0 */
|
||||||
|
|
||||||
static char *get_dirname(const char *path)
|
static char *get_dirname(const char *path)
|
||||||
|
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
|
@ -54,6 +54,7 @@ tmp.*
|
||||||
/property_iterate
|
/property_iterate
|
||||||
/propname_escapes
|
/propname_escapes
|
||||||
/references
|
/references
|
||||||
|
/relref_merge
|
||||||
/root_node
|
/root_node
|
||||||
/rw_tree1
|
/rw_tree1
|
||||||
/rw_oom
|
/rw_oom
|
||||||
|
|
|
@ -18,7 +18,7 @@ LIB_TESTS_L = get_mem_rsv \
|
||||||
open_pack rw_tree1 rw_oom set_name setprop del_property del_node \
|
open_pack rw_tree1 rw_oom set_name setprop del_property del_node \
|
||||||
appendprop1 appendprop2 propname_escapes \
|
appendprop1 appendprop2 propname_escapes \
|
||||||
string_escapes references path-references phandle_format \
|
string_escapes references path-references phandle_format \
|
||||||
boot-cpuid incbin \
|
boot-cpuid incbin relref_merge \
|
||||||
extra-terminating-null \
|
extra-terminating-null \
|
||||||
dtbs_equal_ordered \
|
dtbs_equal_ordered \
|
||||||
dtb_reverse dtbs_equal_unordered \
|
dtb_reverse dtbs_equal_unordered \
|
||||||
|
@ -32,7 +32,9 @@ LIB_TESTS_L = get_mem_rsv \
|
||||||
fs_tree1
|
fs_tree1
|
||||||
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||||
|
|
||||||
LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv
|
LIBTREE_TESTS_L = truncated_property truncated_string truncated_memrsv \
|
||||||
|
two_roots named_root
|
||||||
|
|
||||||
LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
|
LIBTREE_TESTS = $(LIBTREE_TESTS_L:%=$(TESTS_PREFIX)%)
|
||||||
|
|
||||||
DL_LIB_TESTS_L = asm_tree_dump value-labels
|
DL_LIB_TESTS_L = asm_tree_dump value-labels
|
||||||
|
|
20
tests/bad-interrupt-map-mask.dts
Normal file
20
tests/bad-interrupt-map-mask.dts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
interrupt-parent = <&intc>;
|
||||||
|
intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <3>;
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
|
||||||
|
node {
|
||||||
|
#address-cells = <0>;
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-map = <1 &intc 1 2 3>;
|
||||||
|
interrupt-map-mask = <0 0>;
|
||||||
|
|
||||||
|
child {
|
||||||
|
interrupts = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
17
tests/bad-interrupt-map-parent.dts
Normal file
17
tests/bad-interrupt-map-parent.dts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
interrupt-parent = <&intc>;
|
||||||
|
intc: interrupt-controller {
|
||||||
|
};
|
||||||
|
|
||||||
|
node {
|
||||||
|
#address-cells = <0>;
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-map = <1 &intc 1 2 3>;
|
||||||
|
|
||||||
|
child {
|
||||||
|
interrupts = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
19
tests/bad-interrupt-map.dts
Normal file
19
tests/bad-interrupt-map.dts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
interrupt-parent = <&intc>;
|
||||||
|
intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <3>;
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
|
||||||
|
node {
|
||||||
|
/* Missing #address-cells = <0>; */
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-map = <1 &intc 1 2 3>;
|
||||||
|
|
||||||
|
child {
|
||||||
|
interrupts = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -32,7 +32,7 @@ _dt_reserve_map:
|
||||||
dt_struct_start:
|
dt_struct_start:
|
||||||
_dt_struct_start:
|
_dt_struct_start:
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string ""
|
.asciz ""
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0xa
|
.long 0xa
|
||||||
|
@ -58,7 +58,7 @@ _dt_struct_start:
|
||||||
.long 0x2
|
.long 0x2
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string "memory@0"
|
.asciz "memory@0"
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0x7
|
.long 0x7
|
||||||
|
@ -77,7 +77,7 @@ _dt_struct_start:
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_END_NODE
|
.long OF_DT_END_NODE
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string "cpus"
|
.asciz "cpus"
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0x4
|
.long 0x4
|
||||||
|
@ -151,22 +151,22 @@ _dt_struct_end:
|
||||||
.globl dt_strings_start
|
.globl dt_strings_start
|
||||||
dt_strings_start:
|
dt_strings_start:
|
||||||
_dt_strings_start:
|
_dt_strings_start:
|
||||||
.string "model"
|
.asciz "model"
|
||||||
.string "compatible"
|
.asciz "compatible"
|
||||||
.string "#address-cells"
|
.asciz "#address-cells"
|
||||||
.string "#size-cells"
|
.asciz "#size-cells"
|
||||||
.string "device_type"
|
.asciz "device_type"
|
||||||
.string "reg"
|
.asciz "reg"
|
||||||
.string "d10"
|
.asciz "d10"
|
||||||
.string "d23"
|
.asciz "d23"
|
||||||
.string "b101"
|
.asciz "b101"
|
||||||
.string "o17"
|
.asciz "o17"
|
||||||
.string "hd00d"
|
.asciz "hd00d"
|
||||||
.string "stuff"
|
.asciz "stuff"
|
||||||
.string "bad-d-1"
|
.asciz "bad-d-1"
|
||||||
.string "bad-d-2"
|
.asciz "bad-d-2"
|
||||||
.string "bad-o-1"
|
.asciz "bad-o-1"
|
||||||
.string "bad-o-2"
|
.asciz "bad-o-2"
|
||||||
.globl dt_strings_end
|
.globl dt_strings_end
|
||||||
dt_strings_end:
|
dt_strings_end:
|
||||||
_dt_strings_end:
|
_dt_strings_end:
|
||||||
|
|
|
@ -24,13 +24,15 @@ static struct {
|
||||||
TREE(ovf_size_strings),
|
TREE(ovf_size_strings),
|
||||||
TREE(truncated_property), TREE(truncated_string),
|
TREE(truncated_property), TREE(truncated_string),
|
||||||
TREE(truncated_memrsv),
|
TREE(truncated_memrsv),
|
||||||
|
TREE(two_roots),
|
||||||
|
TREE(named_root)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_TREES (sizeof(trees) / sizeof(trees[0]))
|
#define NUM_TREES (sizeof(trees) / sizeof(trees[0]))
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
fprintf(stderr, "Missing output directory argument\n");
|
fprintf(stderr, "Missing output directory argument\n");
|
||||||
|
|
|
@ -54,7 +54,7 @@ static void mkfile(const char *name, void *data, size_t len)
|
||||||
rc = write(fd, data, len);
|
rc = write(fd, data, len);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
FAIL("write(\"%s\"): %s", name, strerror(errno));
|
FAIL("write(\"%s\"): %s", name, strerror(errno));
|
||||||
if (rc != len)
|
if ((unsigned)rc != len)
|
||||||
FAIL("write(\"%s\"): short write", name);
|
FAIL("write(\"%s\"): short write", name);
|
||||||
|
|
||||||
rc = close(fd);
|
rc = close(fd);
|
||||||
|
|
|
@ -34,12 +34,14 @@ static void check_name(void *fdt, const char *path)
|
||||||
offset, getname, len);
|
offset, getname, len);
|
||||||
if (!getname)
|
if (!getname)
|
||||||
FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
|
FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
|
||||||
|
if (len < 0)
|
||||||
|
FAIL("negative name length (%d) for returned node name\n", len);
|
||||||
|
|
||||||
if (strcmp(getname, checkname) != 0)
|
if (strcmp(getname, checkname) != 0)
|
||||||
FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
|
FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
|
||||||
path, getname, checkname);
|
path, getname, checkname);
|
||||||
|
|
||||||
if (len != strlen(getname))
|
if ((unsigned)len != strlen(getname))
|
||||||
FAIL("fdt_get_name(%s) returned length %d instead of %zd",
|
FAIL("fdt_get_name(%s) returned length %d instead of %zd",
|
||||||
path, len, strlen(getname));
|
path, len, strlen(getname));
|
||||||
|
|
||||||
|
|
12
tests/good-gpio.dts
Normal file
12
tests/good-gpio.dts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
gpio: gpio-controller {
|
||||||
|
#gpio-cells = <3>;
|
||||||
|
};
|
||||||
|
|
||||||
|
node {
|
||||||
|
foo,nr-gpios = <1>;
|
||||||
|
foo-gpios = <&gpio 1 2 3>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -59,7 +59,7 @@ int main(int argc, char *argv[])
|
||||||
void *fdt;
|
void *fdt;
|
||||||
const fdt32_t *res;
|
const fdt32_t *res;
|
||||||
int reslen;
|
int reslen;
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
test_init(argc, argv);
|
test_init(argc, argv);
|
||||||
|
|
||||||
|
|
131
tests/meson.build
Normal file
131
tests/meson.build
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
trees = static_library('trees', files('trees.S'), c_args: '-D__ASSEMBLY__',
|
||||||
|
include_directories: libfdt_inc)
|
||||||
|
|
||||||
|
dumptrees = executable('dumptrees', files('dumptrees.c'),
|
||||||
|
link_with: trees, dependencies: libfdt_dep)
|
||||||
|
|
||||||
|
dumptrees_dtb = custom_target(
|
||||||
|
'dumptrees',
|
||||||
|
command: [dumptrees, meson.current_build_dir()],
|
||||||
|
output: [
|
||||||
|
'test_tree1.dtb',
|
||||||
|
'bad_node_char.dtb',
|
||||||
|
'bad_node_format.dtb',
|
||||||
|
'bad_prop_char.dtb',
|
||||||
|
'ovf_size_strings.dtb',
|
||||||
|
'truncated_property.dtb',
|
||||||
|
'truncated_string.dtb',
|
||||||
|
'truncated_memrsv.dtb',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
testutil_dep = declare_dependency(sources: ['testutils.c'], link_with: trees)
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
'add_subnode_with_nops',
|
||||||
|
'addr_size_cells',
|
||||||
|
'addr_size_cells2',
|
||||||
|
'appendprop1',
|
||||||
|
'appendprop2',
|
||||||
|
'appendprop_addrrange',
|
||||||
|
'boot-cpuid',
|
||||||
|
'char_literal',
|
||||||
|
'check_full',
|
||||||
|
'check_header',
|
||||||
|
'check_path',
|
||||||
|
'del_node',
|
||||||
|
'del_property',
|
||||||
|
'dtb_reverse',
|
||||||
|
'dtbs_equal_ordered',
|
||||||
|
'dtbs_equal_unordered',
|
||||||
|
'extra-terminating-null',
|
||||||
|
'find_property',
|
||||||
|
'fs_tree1',
|
||||||
|
'get_alias',
|
||||||
|
'get_mem_rsv',
|
||||||
|
'get_name',
|
||||||
|
'get_path',
|
||||||
|
'get_phandle',
|
||||||
|
'get_prop_offset',
|
||||||
|
'getprop',
|
||||||
|
'incbin',
|
||||||
|
'integer-expressions',
|
||||||
|
'mangle-layout',
|
||||||
|
'move_and_save',
|
||||||
|
'node_check_compatible',
|
||||||
|
'node_offset_by_compatible',
|
||||||
|
'node_offset_by_phandle',
|
||||||
|
'node_offset_by_prop_value',
|
||||||
|
'nop_node',
|
||||||
|
'nop_property',
|
||||||
|
'nopulate',
|
||||||
|
'notfound',
|
||||||
|
'open_pack',
|
||||||
|
'overlay',
|
||||||
|
'overlay_bad_fixup',
|
||||||
|
'parent_offset',
|
||||||
|
'path-references',
|
||||||
|
'path_offset',
|
||||||
|
'path_offset_aliases',
|
||||||
|
'phandle_format',
|
||||||
|
'property_iterate',
|
||||||
|
'propname_escapes',
|
||||||
|
'references',
|
||||||
|
'root_node',
|
||||||
|
'rw_oom',
|
||||||
|
'rw_tree1',
|
||||||
|
'set_name',
|
||||||
|
'setprop',
|
||||||
|
'setprop_inplace',
|
||||||
|
'sized_cells',
|
||||||
|
'string_escapes',
|
||||||
|
'stringlist',
|
||||||
|
'subnode_iterate',
|
||||||
|
'subnode_offset',
|
||||||
|
'supernode_atdepth_offset',
|
||||||
|
'sw_states',
|
||||||
|
'sw_tree1',
|
||||||
|
'utilfdt_test',
|
||||||
|
]
|
||||||
|
|
||||||
|
tests += [
|
||||||
|
'truncated_memrsv',
|
||||||
|
'truncated_property',
|
||||||
|
'truncated_string',
|
||||||
|
]
|
||||||
|
|
||||||
|
dl = cc.find_library('dl', required: false)
|
||||||
|
if dl.found()
|
||||||
|
tests += [
|
||||||
|
'asm_tree_dump',
|
||||||
|
'value-labels',
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
|
||||||
|
foreach t: tests
|
||||||
|
executable(t, files(t + '.c'), dependencies: [testutil_dep, util_dep, libfdt_dep, dl])
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
run_tests = find_program('run_tests.sh')
|
||||||
|
|
||||||
|
env = []
|
||||||
|
if not py.found()
|
||||||
|
env += 'NO_PYTHON=1'
|
||||||
|
else
|
||||||
|
env += [
|
||||||
|
'PYTHON=' + py.path(),
|
||||||
|
'PYTHONPATH=' + meson.source_root() / 'pylibfdt',
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
if not yaml.found()
|
||||||
|
env += 'NO_YAML=1'
|
||||||
|
endif
|
||||||
|
|
||||||
|
test(
|
||||||
|
'run-test',
|
||||||
|
run_tests,
|
||||||
|
workdir: meson.current_build_dir(),
|
||||||
|
depends: dumptrees_dtb,
|
||||||
|
env: env,
|
||||||
|
timeout: 1800, # mostly for valgrind
|
||||||
|
)
|
|
@ -43,7 +43,8 @@ static int nopulate_struct(char *buf, const char *fdt)
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *fdt, *fdt2, *buf;
|
char *fdt, *fdt2, *buf;
|
||||||
int newsize, struct_start, struct_end_old, struct_end_new, delta;
|
int newsize, struct_end_old, struct_end_new, delta;
|
||||||
|
unsigned int struct_start;
|
||||||
const char *inname;
|
const char *inname;
|
||||||
char outname[PATH_MAX];
|
char outname[PATH_MAX];
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,11 @@ static int fdt_getprop_u32_by_poffset(void *fdt, const char *path,
|
||||||
return node_off;
|
return node_off;
|
||||||
|
|
||||||
val = fdt_getprop(fdt, node_off, name, &len);
|
val = fdt_getprop(fdt, node_off, name, &len);
|
||||||
if (!val || (len < (sizeof(uint32_t) * (poffset + 1))))
|
if (val && len < 0)
|
||||||
|
FAIL("fdt_getprop() returns negative length");
|
||||||
|
if (!val && len < 0)
|
||||||
|
return len;
|
||||||
|
if (!val || ((unsigned)len < (sizeof(uint32_t) * (poffset + 1))))
|
||||||
return -FDT_ERR_NOTFOUND;
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
|
||||||
*out = fdt32_to_cpu(*(val + poffset));
|
*out = fdt32_to_cpu(*(val + poffset));
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fragment@5 {
|
fragment@4 {
|
||||||
target = <&test>;
|
target = <&test>;
|
||||||
|
|
||||||
__overlay__ {
|
__overlay__ {
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fragment@6 {
|
fragment@5 {
|
||||||
target = <&test>;
|
target = <&test>;
|
||||||
|
|
||||||
__overlay__ {
|
__overlay__ {
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fragment@7 {
|
fragment@6 {
|
||||||
target = <&test>;
|
target = <&test>;
|
||||||
|
|
||||||
__overlay__ {
|
__overlay__ {
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fragment@8 {
|
fragment@7 {
|
||||||
target = <&test>;
|
target = <&test>;
|
||||||
|
|
||||||
__overlay__ {
|
__overlay__ {
|
||||||
|
|
|
@ -53,7 +53,7 @@ int main(int argc, char *argv[])
|
||||||
void *fdt;
|
void *fdt;
|
||||||
const char *p;
|
const char *p;
|
||||||
int len, multilen;
|
int len, multilen;
|
||||||
int n1, n2, n3, n4;
|
int n1, n2, n3, n4, n5;
|
||||||
|
|
||||||
test_init(argc, argv);
|
test_init(argc, argv);
|
||||||
fdt = load_blob_arg(argc, argv);
|
fdt = load_blob_arg(argc, argv);
|
||||||
|
@ -89,6 +89,12 @@ int main(int argc, char *argv[])
|
||||||
check_ref(fdt, n3, "/foobar/baz");
|
check_ref(fdt, n3, "/foobar/baz");
|
||||||
check_ref(fdt, n4, "/foo/baz");
|
check_ref(fdt, n4, "/foo/baz");
|
||||||
|
|
||||||
|
n5 = fdt_path_offset(fdt, "/bar/baz");
|
||||||
|
if (n5 < 0)
|
||||||
|
FAIL("fdt_path_offset(/bar/baz): %s", fdt_strerror(n5));
|
||||||
|
|
||||||
|
check_ref(fdt, n5, "/bar/baz");
|
||||||
|
|
||||||
check_rref(fdt);
|
check_rref(fdt);
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
|
|
|
@ -25,4 +25,13 @@
|
||||||
lref = &n3;
|
lref = &n3;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
n5: bar {
|
||||||
|
baz {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
n6: &{n5/baz} {
|
||||||
|
ref = &{n6/};
|
||||||
|
lref = &{n5/baz};
|
||||||
};
|
};
|
||||||
|
|
18
tests/phandle-args-overflow.dts
Normal file
18
tests/phandle-args-overflow.dts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://github.com/dgibson/dtc/issues/64
|
||||||
|
*
|
||||||
|
* Certain dtc versions had a bug where this input caused an infinite
|
||||||
|
* loop in check_property_phandle_args().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
clocks = <&ref &ref>;
|
||||||
|
|
||||||
|
ref: poc {
|
||||||
|
phandle = <1>;
|
||||||
|
#clock-cells = <0xffffffff>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -45,7 +45,7 @@ int main(int argc, char *argv[])
|
||||||
FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4));
|
FAIL("fdt_path_offset(/node4): %s", fdt_strerror(n4));
|
||||||
|
|
||||||
h4 = fdt_get_phandle(fdt, n4);
|
h4 = fdt_get_phandle(fdt, n4);
|
||||||
if ((h4 == 0) || (h4 == -1))
|
if ((h4 == 0) || (h4 == ~0U))
|
||||||
FAIL("/node4 has bad phandle 0x%x\n", h4);
|
FAIL("/node4 has bad phandle 0x%x\n", h4);
|
||||||
|
|
||||||
if (phandle_format & PHANDLE_LEGACY)
|
if (phandle_format & PHANDLE_LEGACY)
|
||||||
|
|
|
@ -23,7 +23,7 @@ static void test_node(void *fdt, int parent_offset)
|
||||||
uint32_t properties;
|
uint32_t properties;
|
||||||
const fdt32_t *prop;
|
const fdt32_t *prop;
|
||||||
int offset, property;
|
int offset, property;
|
||||||
int count;
|
unsigned int count;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -348,6 +348,19 @@ class PyLibfdtBasicTests(unittest.TestCase):
|
||||||
self.assertEqual("/subnode@1/subsubnode", self.fdt3.get_alias('ss1'))
|
self.assertEqual("/subnode@1/subsubnode", self.fdt3.get_alias('ss1'))
|
||||||
self.assertEqual("/subnode@1/subsubnode/subsubsubnode", self.fdt3.get_alias('sss1'))
|
self.assertEqual("/subnode@1/subsubnode/subsubsubnode", self.fdt3.get_alias('sss1'))
|
||||||
|
|
||||||
|
def testGetPath(self):
|
||||||
|
"""Test for the get_path() method"""
|
||||||
|
node = self.fdt.path_offset('/subnode@1')
|
||||||
|
node2 = self.fdt.path_offset('/subnode@1/subsubnode')
|
||||||
|
self.assertEqual("/subnode@1", self.fdt.get_path(node))
|
||||||
|
self.assertEqual("/subnode@1/subsubnode", self.fdt.get_path(node2))
|
||||||
|
|
||||||
|
with self.assertRaises(FdtException) as e:
|
||||||
|
self.fdt.get_path(-1)
|
||||||
|
self.assertEqual(e.exception.err, -libfdt.BADOFFSET)
|
||||||
|
|
||||||
|
self.assertEqual(-libfdt.BADOFFSET, self.fdt.get_path(-1, quiet=(libfdt.BADOFFSET,)))
|
||||||
|
|
||||||
def testParentOffset(self):
|
def testParentOffset(self):
|
||||||
"""Test for the parent_offset() method"""
|
"""Test for the parent_offset() method"""
|
||||||
self.assertEqual(-libfdt.NOTFOUND,
|
self.assertEqual(-libfdt.NOTFOUND,
|
||||||
|
@ -382,6 +395,25 @@ class PyLibfdtBasicTests(unittest.TestCase):
|
||||||
self.get_prop("prop-uint64").as_uint64())
|
self.get_prop("prop-uint64").as_uint64())
|
||||||
self.assertEqual(-2, self.get_prop("prop-int64").as_int64())
|
self.assertEqual(-2, self.get_prop("prop-int64").as_int64())
|
||||||
|
|
||||||
|
def testGetIntListProperties(self):
|
||||||
|
"""Test that we can access properties as integer lists"""
|
||||||
|
self.assertEqual([128, -16, -2],
|
||||||
|
self.get_prop("prop-int32-array").as_int32_list())
|
||||||
|
self.assertEqual([0x1, 0x98765432, 0xdeadbeef],
|
||||||
|
self.get_prop("prop-uint32-array").as_uint32_list())
|
||||||
|
self.assertEqual([0x100000000, -2],
|
||||||
|
self.get_prop("prop-int64-array").as_int64_list())
|
||||||
|
self.assertEqual([0x100000000, 0x1],
|
||||||
|
self.get_prop("prop-uint64-array").as_uint64_list())
|
||||||
|
|
||||||
|
def testGetStringlistProperties(self):
|
||||||
|
"""Test that we can access properties as string list"""
|
||||||
|
node = self.fdt.path_offset('/subnode@1/subsubnode')
|
||||||
|
self.assertEqual(["subsubnode1", "subsubnode"],
|
||||||
|
self.fdt.getprop(node, "compatible").as_stringlist())
|
||||||
|
self.assertEqual(["this is a placeholder string", "string2"],
|
||||||
|
self.fdt.getprop(node, "placeholder").as_stringlist())
|
||||||
|
|
||||||
def testReserveMap(self):
|
def testReserveMap(self):
|
||||||
"""Test that we can access the memory reserve map"""
|
"""Test that we can access the memory reserve map"""
|
||||||
self.assertEqual(2, self.fdt.num_mem_rsv())
|
self.assertEqual(2, self.fdt.num_mem_rsv())
|
||||||
|
|
|
@ -106,7 +106,7 @@ int main(int argc, char *argv[])
|
||||||
if ((h4 == 0x2000) || (h4 == 0x1) || (h4 == 0))
|
if ((h4 == 0x2000) || (h4 == 0x1) || (h4 == 0))
|
||||||
FAIL("/node4 has bad phandle, 0x%x", h4);
|
FAIL("/node4 has bad phandle, 0x%x", h4);
|
||||||
|
|
||||||
if ((h5 == 0) || (h5 == -1))
|
if ((h5 == 0) || (h5 == ~0U))
|
||||||
FAIL("/node5 has bad phandle, 0x%x", h5);
|
FAIL("/node5 has bad phandle, 0x%x", h5);
|
||||||
if ((h5 == h4) || (h5 == h2) || (h5 == h1))
|
if ((h5 == h4) || (h5 == h2) || (h5 == h1))
|
||||||
FAIL("/node5 has duplicate phandle, 0x%x", h5);
|
FAIL("/node5 has duplicate phandle, 0x%x", h5);
|
||||||
|
|
51
tests/relref_merge.c
Normal file
51
tests/relref_merge.c
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
/*
|
||||||
|
* libfdt - Flat Device Tree manipulation
|
||||||
|
* Testcase for label relative child references in dtc
|
||||||
|
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||||
|
* Copyright (C) 2020 Ahmad Fatoum, Pengutronix.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
#include "testdata.h"
|
||||||
|
|
||||||
|
static void check_exist(void *fdt, const char *path)
|
||||||
|
{
|
||||||
|
int sn = fdt_path_offset(fdt, path);
|
||||||
|
if (sn < 0)
|
||||||
|
FAIL("%s expected but not found: %s", path, fdt_strerror(sn));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_doesnt_exist(void *fdt, const char *path)
|
||||||
|
{
|
||||||
|
int sn = fdt_path_offset(fdt, path);
|
||||||
|
if (sn >= 0)
|
||||||
|
FAIL("%s found but not expected %d", path, sn);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
fdt = load_blob_arg(argc, argv);
|
||||||
|
|
||||||
|
check_exist(fdt, "/node/subnode1");
|
||||||
|
check_exist(fdt, "/node/keep-me");
|
||||||
|
check_doesnt_exist(fdt, "/node/remove-me");
|
||||||
|
|
||||||
|
check_doesnt_exist(fdt, "/node2");
|
||||||
|
check_doesnt_exist(fdt, "/node/subnode3");
|
||||||
|
|
||||||
|
check_exist(fdt, "/node/subnode4");
|
||||||
|
|
||||||
|
check_exist(fdt, "/node/subnode1/add-me");
|
||||||
|
|
||||||
|
PASS();
|
||||||
|
}
|
40
tests/relref_merge.dts
Normal file
40
tests/relref_merge.dts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
node_label: node {
|
||||||
|
keep-me {};
|
||||||
|
remove-me {};
|
||||||
|
|
||||||
|
subnode1 {
|
||||||
|
property-inline1;
|
||||||
|
property-inline2;
|
||||||
|
property-inline3;
|
||||||
|
};
|
||||||
|
|
||||||
|
subnode2 {
|
||||||
|
property-inline1;
|
||||||
|
};
|
||||||
|
|
||||||
|
subnode3 {
|
||||||
|
property-inline1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
node2_label: node2 {
|
||||||
|
property-inline1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/omit-if-no-ref/ &{node_label/subnode1};
|
||||||
|
/omit-if-no-ref/ &node2_label;
|
||||||
|
/delete-node/ &{node_label/subnode3};
|
||||||
|
|
||||||
|
&{node_label/} {
|
||||||
|
/delete-node/ remove-me;
|
||||||
|
|
||||||
|
subnode4 { };
|
||||||
|
};
|
||||||
|
|
||||||
|
label: &{node_label/subnode1} {
|
||||||
|
selfref = &{node_label/subnode1};
|
||||||
|
add-me { };
|
||||||
|
};
|
|
@ -288,7 +288,7 @@ dtc_overlay_tests () {
|
||||||
run_test check_path overlay_overlay.test.dtb exists "/__local_fixups__"
|
run_test check_path overlay_overlay.test.dtb exists "/__local_fixups__"
|
||||||
|
|
||||||
# Without syntactic sugar
|
# Without syntactic sugar
|
||||||
run_dtc_test -I dts -O dtb -o overlay_overlay_nosugar.test.dtb "$SRCDIR/overlay_overlay.dts"
|
run_dtc_test -I dts -O dtb -o overlay_overlay_nosugar.test.dtb "$SRCDIR/overlay_overlay_nosugar.dts"
|
||||||
run_test check_path overlay_overlay_nosugar.test.dtb not-exists "/__symbols__"
|
run_test check_path overlay_overlay_nosugar.test.dtb not-exists "/__symbols__"
|
||||||
run_test check_path overlay_overlay_nosugar.test.dtb exists "/__fixups__"
|
run_test check_path overlay_overlay_nosugar.test.dtb exists "/__fixups__"
|
||||||
run_test check_path overlay_overlay_nosugar.test.dtb exists "/__local_fixups__"
|
run_test check_path overlay_overlay_nosugar.test.dtb exists "/__local_fixups__"
|
||||||
|
@ -513,12 +513,15 @@ libfdt_tests () {
|
||||||
run_dtc_test -I fs -O dtb -o fs.test_tree1.test.dtb $FSBASE/test_tree1
|
run_dtc_test -I fs -O dtb -o fs.test_tree1.test.dtb $FSBASE/test_tree1
|
||||||
run_test dtbs_equal_unordered -m fs.test_tree1.test.dtb test_tree1.dtb
|
run_test dtbs_equal_unordered -m fs.test_tree1.test.dtb test_tree1.dtb
|
||||||
|
|
||||||
|
## https://github.com/dgibson/dtc/issues/64
|
||||||
|
check_tests "$SRCDIR/phandle-args-overflow.dts" clocks_property
|
||||||
|
|
||||||
# check full tests
|
# check full tests
|
||||||
for good in test_tree1.dtb; do
|
for good in test_tree1.dtb; do
|
||||||
run_test check_full $good
|
run_test check_full $good
|
||||||
done
|
done
|
||||||
for bad in truncated_property.dtb truncated_string.dtb \
|
for bad in truncated_property.dtb truncated_string.dtb \
|
||||||
truncated_memrsv.dtb; do
|
truncated_memrsv.dtb two_roots.dtb named_root.dtb; do
|
||||||
run_test check_full -n $bad
|
run_test check_full -n $bad
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
@ -666,6 +669,9 @@ dtc_tests () {
|
||||||
tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb
|
tree1_tests dtc_tree1_merge_path.test.dtb test_tree1.dtb
|
||||||
run_wrap_error_test $DTC -I dts -O dtb -o /dev/null "$SRCDIR/test_label_ref.dts"
|
run_wrap_error_test $DTC -I dts -O dtb -o /dev/null "$SRCDIR/test_label_ref.dts"
|
||||||
|
|
||||||
|
run_dtc_test -I dts -O dtb -o dtc_relref_merge.test.dtb "$SRCDIR/relref_merge.dts"
|
||||||
|
run_test relref_merge dtc_relref_merge.test.dtb
|
||||||
|
|
||||||
# Check prop/node delete functionality
|
# Check prop/node delete functionality
|
||||||
run_dtc_test -I dts -O dtb -o dtc_tree1_delete.test.dtb "$SRCDIR/test_tree1_delete.dts"
|
run_dtc_test -I dts -O dtb -o dtc_tree1_delete.test.dtb "$SRCDIR/test_tree1_delete.dts"
|
||||||
tree1_tests dtc_tree1_delete.test.dtb
|
tree1_tests dtc_tree1_delete.test.dtb
|
||||||
|
@ -691,7 +697,7 @@ dtc_tests () {
|
||||||
run_sh_test "$SRCDIR/dtc-fatal.sh" -I dts -O dtb "$SRCDIR/nonexist-node-ref2.dts"
|
run_sh_test "$SRCDIR/dtc-fatal.sh" -I dts -O dtb "$SRCDIR/nonexist-node-ref2.dts"
|
||||||
check_tests "$SRCDIR/bad-name-property.dts" name_properties
|
check_tests "$SRCDIR/bad-name-property.dts" name_properties
|
||||||
|
|
||||||
check_tests "$SRCDIR/bad-ncells.dts" address_cells_is_cell size_cells_is_cell interrupt_cells_is_cell
|
check_tests "$SRCDIR/bad-ncells.dts" address_cells_is_cell size_cells_is_cell interrupts_extended_is_cell
|
||||||
check_tests "$SRCDIR/bad-string-props.dts" device_type_is_string model_is_string status_is_string label_is_string compatible_is_string_list names_is_string_list
|
check_tests "$SRCDIR/bad-string-props.dts" device_type_is_string model_is_string status_is_string label_is_string compatible_is_string_list names_is_string_list
|
||||||
check_tests "$SRCDIR/bad-chosen.dts" chosen_node_is_root
|
check_tests "$SRCDIR/bad-chosen.dts" chosen_node_is_root
|
||||||
check_tests "$SRCDIR/bad-chosen.dts" chosen_node_bootargs
|
check_tests "$SRCDIR/bad-chosen.dts" chosen_node_bootargs
|
||||||
|
@ -709,12 +715,17 @@ dtc_tests () {
|
||||||
check_tests "$SRCDIR/unit-addr-unique.dts" unique_unit_address
|
check_tests "$SRCDIR/unit-addr-unique.dts" unique_unit_address
|
||||||
check_tests "$SRCDIR/bad-phandle-cells.dts" interrupts_extended_property
|
check_tests "$SRCDIR/bad-phandle-cells.dts" interrupts_extended_property
|
||||||
check_tests "$SRCDIR/bad-gpio.dts" gpios_property
|
check_tests "$SRCDIR/bad-gpio.dts" gpios_property
|
||||||
|
check_tests "$SRCDIR/good-gpio.dts" -n gpios_property
|
||||||
check_tests "$SRCDIR/bad-graph.dts" graph_child_address
|
check_tests "$SRCDIR/bad-graph.dts" graph_child_address
|
||||||
check_tests "$SRCDIR/bad-graph.dts" graph_port
|
check_tests "$SRCDIR/bad-graph.dts" graph_port
|
||||||
check_tests "$SRCDIR/bad-graph.dts" graph_endpoint
|
check_tests "$SRCDIR/bad-graph.dts" graph_endpoint
|
||||||
run_sh_test "$SRCDIR/dtc-checkfails.sh" deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/bad-gpio.dts"
|
run_sh_test "$SRCDIR/dtc-checkfails.sh" deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/bad-gpio.dts"
|
||||||
|
run_sh_test "$SRCDIR/dtc-checkfails.sh" -n deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/good-gpio.dts"
|
||||||
check_tests "$SRCDIR/bad-interrupt-cells.dts" interrupts_property
|
check_tests "$SRCDIR/bad-interrupt-cells.dts" interrupts_property
|
||||||
check_tests "$SRCDIR/bad-interrupt-controller.dts" interrupt_provider
|
check_tests "$SRCDIR/bad-interrupt-controller.dts" interrupt_provider
|
||||||
|
check_tests "$SRCDIR/bad-interrupt-map.dts" interrupt_map
|
||||||
|
check_tests "$SRCDIR/bad-interrupt-map-parent.dts" interrupt_map
|
||||||
|
check_tests "$SRCDIR/bad-interrupt-map-mask.dts" interrupt_map
|
||||||
run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_chars -- -I dtb -O dtb bad_node_char.dtb
|
run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_chars -- -I dtb -O dtb bad_node_char.dtb
|
||||||
run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_format -- -I dtb -O dtb bad_node_format.dtb
|
run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_format -- -I dtb -O dtb bad_node_format.dtb
|
||||||
run_sh_test "$SRCDIR/dtc-checkfails.sh" property_name_chars -- -I dtb -O dtb bad_prop_char.dtb
|
run_sh_test "$SRCDIR/dtc-checkfails.sh" property_name_chars -- -I dtb -O dtb bad_prop_char.dtb
|
||||||
|
@ -738,7 +749,7 @@ dtc_tests () {
|
||||||
|
|
||||||
|
|
||||||
# Check warning options
|
# Check warning options
|
||||||
run_sh_test "$SRCDIR/dtc-checkfails.sh" address_cells_is_cell interrupt_cells_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts"
|
run_sh_test "$SRCDIR/dtc-checkfails.sh" address_cells_is_cell interrupts_extended_is_cell -n size_cells_is_cell -- -Wno_size_cells_is_cell -I dts -O dtb "$SRCDIR/bad-ncells.dts"
|
||||||
run_sh_test "$SRCDIR/dtc-fails.sh" -n test-warn-output.test.dtb -I dts -O dtb "$SRCDIR/bad-ncells.dts"
|
run_sh_test "$SRCDIR/dtc-fails.sh" -n test-warn-output.test.dtb -I dts -O dtb "$SRCDIR/bad-ncells.dts"
|
||||||
run_sh_test "$SRCDIR/dtc-fails.sh" test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell
|
run_sh_test "$SRCDIR/dtc-fails.sh" test-error-output.test.dtb -I dts -O dtb bad-ncells.dts -Esize_cells_is_cell
|
||||||
run_sh_test "$SRCDIR/dtc-checkfails.sh" always_fail -- -Walways_fail -I dts -O dtb "$SRCDIR/test_tree1.dts"
|
run_sh_test "$SRCDIR/dtc-checkfails.sh" always_fail -- -Walways_fail -I dts -O dtb "$SRCDIR/test_tree1.dts"
|
||||||
|
@ -850,6 +861,8 @@ fdtget_tests () {
|
||||||
run_fdtget_test 8000 -tx $dtb /cpus/PowerPC,970@1 d-cache-size
|
run_fdtget_test 8000 -tx $dtb /cpus/PowerPC,970@1 d-cache-size
|
||||||
run_fdtget_test "61 62 63 0" -tbx $dtb /randomnode tricky1
|
run_fdtget_test "61 62 63 0" -tbx $dtb /randomnode tricky1
|
||||||
run_fdtget_test "a b c d de ea ad be ef" -tbx $dtb /randomnode blob
|
run_fdtget_test "a b c d de ea ad be ef" -tbx $dtb /randomnode blob
|
||||||
|
run_fdtget_test "MyBoardName\0MyBoardFamilyName\0" -tr $dtb / compatible
|
||||||
|
run_fdtget_test "\x0a\x0b\x0c\x0d\xde\xea\xad\xbe\xef" -tr $dtb /randomnode blob
|
||||||
|
|
||||||
# Here the property size is not a multiple of 4 bytes, so it should fail
|
# Here the property size is not a multiple of 4 bytes, so it should fail
|
||||||
run_wrap_error_test $DTGET -tlx $dtb /randomnode mixed
|
run_wrap_error_test $DTGET -tlx $dtb /randomnode mixed
|
||||||
|
|
|
@ -39,7 +39,11 @@ static void check_set_name(void *fdt, const char *path, const char *newname)
|
||||||
FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
|
FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
|
||||||
path, getname, oldname);
|
path, getname, oldname);
|
||||||
|
|
||||||
if (len != strlen(getname))
|
if (len < 0)
|
||||||
|
FAIL("fdt_get_name(%s) returned negative length: %d",
|
||||||
|
path, len);
|
||||||
|
|
||||||
|
if ((unsigned)len != strlen(getname))
|
||||||
FAIL("fdt_get_name(%s) returned length %d instead of %zd",
|
FAIL("fdt_get_name(%s) returned length %d instead of %zd",
|
||||||
path, len, strlen(getname));
|
path, len, strlen(getname));
|
||||||
|
|
||||||
|
@ -51,12 +55,14 @@ static void check_set_name(void *fdt, const char *path, const char *newname)
|
||||||
getname = fdt_get_name(fdt, offset, &len);
|
getname = fdt_get_name(fdt, offset, &len);
|
||||||
if (!getname)
|
if (!getname)
|
||||||
FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
|
FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
|
||||||
|
if (len < 0)
|
||||||
|
FAIL("negative name length (%d) for returned node name\n", len);
|
||||||
|
|
||||||
if (strcmp(getname, newname) != 0)
|
if (strcmp(getname, newname) != 0)
|
||||||
FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
|
FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
|
||||||
path, getname, newname);
|
path, getname, newname);
|
||||||
|
|
||||||
if (len != strlen(getname))
|
if ((unsigned)len != strlen(getname))
|
||||||
FAIL("fdt_get_name(%s) returned length %d instead of %zd",
|
FAIL("fdt_get_name(%s) returned length %d instead of %zd",
|
||||||
path, len, strlen(getname));
|
path, len, strlen(getname));
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ int main(int argc, char *argv[])
|
||||||
TEST_STRING_1);
|
TEST_STRING_1);
|
||||||
|
|
||||||
verbose_printf("Old string value was \"%s\"\n", strp);
|
verbose_printf("Old string value was \"%s\"\n", strp);
|
||||||
xstr = strdup(strp);
|
xstr = xstrdup(strp);
|
||||||
xlen = strlen(xstr);
|
xlen = strlen(xstr);
|
||||||
for (i = 0; i < xlen; i++)
|
for (i = 0; i < xlen; i++)
|
||||||
xstr[i] = toupper(xstr[i]);
|
xstr[i] = toupper(xstr[i]);
|
||||||
|
|
|
@ -23,7 +23,7 @@ static void test_node(void *fdt, int parent_offset)
|
||||||
uint32_t subnodes;
|
uint32_t subnodes;
|
||||||
const fdt32_t *prop;
|
const fdt32_t *prop;
|
||||||
int offset;
|
int offset;
|
||||||
int count;
|
unsigned int count;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
/* This property indicates the number of subnodes to expect */
|
/* This property indicates the number of subnodes to expect */
|
||||||
|
|
|
@ -44,7 +44,7 @@ _dt_reserve_map:
|
||||||
dt_struct_start:
|
dt_struct_start:
|
||||||
_dt_struct_start:
|
_dt_struct_start:
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string ""
|
.asciz ""
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0xc
|
.long 0xc
|
||||||
|
@ -76,7 +76,7 @@ _dt_struct_start:
|
||||||
.long 0x2
|
.long 0x2
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string "cpus"
|
.asciz "cpus"
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0x4
|
.long 0x4
|
||||||
|
@ -94,7 +94,7 @@ _dt_struct_start:
|
||||||
.long 0x0
|
.long 0x0
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string "PowerPC,970@0"
|
.asciz "PowerPC,970@0"
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0xc
|
.long 0xc
|
||||||
|
@ -139,7 +139,7 @@ _dt_struct_start:
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_END_NODE
|
.long OF_DT_END_NODE
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string "PowerPC,970@1"
|
.asciz "PowerPC,970@1"
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0xc
|
.long 0xc
|
||||||
|
@ -181,7 +181,7 @@ _dt_struct_start:
|
||||||
.long OF_DT_END_NODE
|
.long OF_DT_END_NODE
|
||||||
.long OF_DT_END_NODE
|
.long OF_DT_END_NODE
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string "randomnode"
|
.asciz "randomnode"
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0x13
|
.long 0x13
|
||||||
|
@ -216,7 +216,7 @@ _dt_struct_start:
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_END_NODE
|
.long OF_DT_END_NODE
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string "memory@0"
|
.asciz "memory@0"
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0x7
|
.long 0x7
|
||||||
|
@ -242,7 +242,7 @@ memreg:
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_END_NODE
|
.long OF_DT_END_NODE
|
||||||
.long OF_DT_BEGIN_NODE
|
.long OF_DT_BEGIN_NODE
|
||||||
.string "chosen"
|
.asciz "chosen"
|
||||||
.balign 4
|
.balign 4
|
||||||
.long OF_DT_PROP
|
.long OF_DT_PROP
|
||||||
.long 0xf
|
.long 0xf
|
||||||
|
@ -267,25 +267,25 @@ _dt_struct_end:
|
||||||
.globl dt_strings_start
|
.globl dt_strings_start
|
||||||
dt_strings_start:
|
dt_strings_start:
|
||||||
_dt_strings_start:
|
_dt_strings_start:
|
||||||
.string "model"
|
.asciz "model"
|
||||||
.string "compatible"
|
.asciz "compatible"
|
||||||
.string "#address-cells"
|
.asciz "#address-cells"
|
||||||
.string "#size-cells"
|
.asciz "#size-cells"
|
||||||
.string "linux,phandle"
|
.asciz "linux,phandle"
|
||||||
.string "name"
|
.asciz "name"
|
||||||
.string "device_type"
|
.asciz "device_type"
|
||||||
.string "reg"
|
.asciz "reg"
|
||||||
.string "clock-frequency"
|
.asciz "clock-frequency"
|
||||||
.string "timebase-frequency"
|
.asciz "timebase-frequency"
|
||||||
.string "linux,boot-cpu"
|
.asciz "linux,boot-cpu"
|
||||||
.string "i-cache-size"
|
.asciz "i-cache-size"
|
||||||
.string "d-cache-size"
|
.asciz "d-cache-size"
|
||||||
.string "string"
|
.asciz "string"
|
||||||
.string "blob"
|
.asciz "blob"
|
||||||
.string "ref"
|
.asciz "ref"
|
||||||
.string "mixed"
|
.asciz "mixed"
|
||||||
.string "bootargs"
|
.asciz "bootargs"
|
||||||
.string "linux,platform"
|
.asciz "linux,platform"
|
||||||
.globl dt_strings_end
|
.globl dt_strings_end
|
||||||
dt_strings_end:
|
dt_strings_end:
|
||||||
_dt_strings_end:
|
_dt_strings_end:
|
||||||
|
|
|
@ -8,4 +8,8 @@
|
||||||
prop-hex64 = /bits/ 64 <0xdeadbeef01abcdef>;
|
prop-hex64 = /bits/ 64 <0xdeadbeef01abcdef>;
|
||||||
prop-uint64 = /bits/ 64 <9223372036854775807>;
|
prop-uint64 = /bits/ 64 <9223372036854775807>;
|
||||||
prop-int64 = /bits/ 64 <0xfffffffffffffffe>;
|
prop-int64 = /bits/ 64 <0xfffffffffffffffe>;
|
||||||
|
prop-int32-array = <128>, <(-16)>, <0xfffffffe>;
|
||||||
|
prop-uint32-array = <0x1>, <0x98765432>, <0xdeadbeef>;
|
||||||
|
prop-int64-array = /bits/ 64 <0x100000000 0xfffffffffffffffe>;
|
||||||
|
prop-uint64-array = /bits/ 64 <0x100000000 0x1>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,4 +55,6 @@ extern struct fdt_header bad_prop_char;
|
||||||
extern struct fdt_header ovf_size_strings;
|
extern struct fdt_header ovf_size_strings;
|
||||||
extern struct fdt_header truncated_string;
|
extern struct fdt_header truncated_string;
|
||||||
extern struct fdt_header truncated_memrsv;
|
extern struct fdt_header truncated_memrsv;
|
||||||
|
extern struct fdt_header two_roots;
|
||||||
|
extern struct fdt_header named_root;
|
||||||
#endif /* ! __ASSEMBLY */
|
#endif /* ! __ASSEMBLY */
|
||||||
|
|
|
@ -83,7 +83,7 @@ void cleanup(void);
|
||||||
void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size);
|
void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size);
|
||||||
|
|
||||||
void check_property(void *fdt, int nodeoffset, const char *name,
|
void check_property(void *fdt, int nodeoffset, const char *name,
|
||||||
int len, const void *val);
|
unsigned int len, const void *val);
|
||||||
#define check_property_cell(fdt, nodeoffset, name, val) \
|
#define check_property_cell(fdt, nodeoffset, name, val) \
|
||||||
({ \
|
({ \
|
||||||
fdt32_t x = cpu_to_fdt32(val); \
|
fdt32_t x = cpu_to_fdt32(val); \
|
||||||
|
|
|
@ -88,7 +88,7 @@ void check_mem_rsv(void *fdt, int n, uint64_t addr, uint64_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_property(void *fdt, int nodeoffset, const char *name,
|
void check_property(void *fdt, int nodeoffset, const char *name,
|
||||||
int len, const void *val)
|
unsigned int len, const void *val)
|
||||||
{
|
{
|
||||||
const struct fdt_property *prop;
|
const struct fdt_property *prop;
|
||||||
int retlen, namelen;
|
int retlen, namelen;
|
||||||
|
@ -101,6 +101,9 @@ void check_property(void *fdt, int nodeoffset, const char *name,
|
||||||
if (! prop)
|
if (! prop)
|
||||||
FAIL("Error retrieving \"%s\" pointer: %s", name,
|
FAIL("Error retrieving \"%s\" pointer: %s", name,
|
||||||
fdt_strerror(retlen));
|
fdt_strerror(retlen));
|
||||||
|
if (retlen < 0)
|
||||||
|
FAIL("negative name length (%d) for returned property\n",
|
||||||
|
retlen);
|
||||||
|
|
||||||
tag = fdt32_to_cpu(prop->tag);
|
tag = fdt32_to_cpu(prop->tag);
|
||||||
nameoff = fdt32_to_cpu(prop->nameoff);
|
nameoff = fdt32_to_cpu(prop->nameoff);
|
||||||
|
@ -112,13 +115,16 @@ void check_property(void *fdt, int nodeoffset, const char *name,
|
||||||
propname = fdt_get_string(fdt, nameoff, &namelen);
|
propname = fdt_get_string(fdt, nameoff, &namelen);
|
||||||
if (!propname)
|
if (!propname)
|
||||||
FAIL("Couldn't get property name: %s", fdt_strerror(namelen));
|
FAIL("Couldn't get property name: %s", fdt_strerror(namelen));
|
||||||
if (namelen != strlen(propname))
|
if (namelen < 0)
|
||||||
|
FAIL("negative name length (%d) for returned string\n",
|
||||||
|
namelen);
|
||||||
|
if ((unsigned)namelen != strlen(propname))
|
||||||
FAIL("Incorrect prop name length: %d instead of %zd",
|
FAIL("Incorrect prop name length: %d instead of %zd",
|
||||||
namelen, strlen(propname));
|
namelen, strlen(propname));
|
||||||
if (!streq(propname, name))
|
if (!streq(propname, name))
|
||||||
FAIL("Property name mismatch \"%s\" instead of \"%s\"",
|
FAIL("Property name mismatch \"%s\" instead of \"%s\"",
|
||||||
propname, name);
|
propname, name);
|
||||||
if (proplen != retlen)
|
if (proplen != (unsigned)retlen)
|
||||||
FAIL("Length retrieved for \"%s\" by fdt_get_property()"
|
FAIL("Length retrieved for \"%s\" by fdt_get_property()"
|
||||||
" differs from stored length (%d != %d)",
|
" differs from stored length (%d != %d)",
|
||||||
name, retlen, proplen);
|
name, retlen, proplen);
|
||||||
|
|
375
tests/trees.S
375
tests/trees.S
|
@ -1,174 +1,187 @@
|
||||||
#include <fdt.h>
|
#include <fdt.h>
|
||||||
#include "testdata.h"
|
#include "testdata.h"
|
||||||
|
|
||||||
#define FDTLONG(val) \
|
.macro fdtlong val
|
||||||
.byte ((val) >> 24) & 0xff ; \
|
.byte ((\val) >> 24) & 0xff
|
||||||
.byte ((val) >> 16) & 0xff ; \
|
.byte ((\val) >> 16) & 0xff
|
||||||
.byte ((val) >> 8) & 0xff ; \
|
.byte ((\val) >> 8) & 0xff
|
||||||
.byte (val) & 0xff ;
|
.byte (\val) & 0xff
|
||||||
|
.endm
|
||||||
|
|
||||||
#define TREE_HDR(tree) \
|
.macro treehdr tree
|
||||||
.balign 8 ; \
|
.balign 8
|
||||||
.globl tree ; \
|
.globl \tree
|
||||||
tree: \
|
\tree :
|
||||||
FDTLONG(FDT_MAGIC) ; \
|
fdtlong FDT_MAGIC
|
||||||
FDTLONG(tree##_end - tree) ; \
|
fdtlong (\tree\()_end - \tree)
|
||||||
FDTLONG(tree##_struct - tree) ; \
|
fdtlong (\tree\()_struct - \tree)
|
||||||
FDTLONG(tree##_strings - tree) ; \
|
fdtlong (\tree\()_strings - \tree)
|
||||||
FDTLONG(tree##_rsvmap - tree) ; \
|
fdtlong (\tree\()_rsvmap - \tree)
|
||||||
FDTLONG(0x11) ; \
|
fdtlong 0x11
|
||||||
FDTLONG(0x10) ; \
|
fdtlong 0x10
|
||||||
FDTLONG(0) ; \
|
fdtlong 0
|
||||||
FDTLONG(tree##_strings_end - tree##_strings) ; \
|
fdtlong (\tree\()_strings_end - \tree\()_strings)
|
||||||
FDTLONG(tree##_struct_end - tree##_struct) ;
|
fdtlong (\tree\()_struct_end - \tree\()_struct)
|
||||||
|
.endm
|
||||||
|
|
||||||
#define RSVMAP_ENTRY(addrh, addrl, lenh, lenl) \
|
.macro rsvmape addrh, addrl, lenh, lenl
|
||||||
FDTLONG(addrh) ; \
|
fdtlong \addrh
|
||||||
FDTLONG(addrl) ; \
|
fdtlong \addrl
|
||||||
FDTLONG(lenh) ; \
|
fdtlong \lenh
|
||||||
FDTLONG(lenl)
|
fdtlong \lenl
|
||||||
|
.endm
|
||||||
|
|
||||||
#define EMPTY_RSVMAP(tree) \
|
.macro empty_rsvmap tree
|
||||||
.balign 8 ; \
|
.balign 8
|
||||||
tree##_rsvmap: ; \
|
\tree\()_rsvmap:
|
||||||
RSVMAP_ENTRY(0, 0, 0, 0) \
|
rsvmape 0, 0, 0, 0
|
||||||
tree##_rsvmap_end: ;
|
\tree\()_rsvmap_end:
|
||||||
|
.endm
|
||||||
|
|
||||||
#define PROPHDR(tree, name, len) \
|
.macro prophdr tree, name, len
|
||||||
FDTLONG(FDT_PROP) ; \
|
fdtlong FDT_PROP
|
||||||
FDTLONG(len) ; \
|
fdtlong \len
|
||||||
FDTLONG(tree##_##name - tree##_strings) ;
|
fdtlong (\tree\()_\name - \tree\()_strings)
|
||||||
|
.endm
|
||||||
|
|
||||||
#define PROP_EMPTY(tree, name) \
|
.macro propnil tree, name
|
||||||
PROPHDR(tree, name, 0) ;
|
prophdr \tree, \name, 0
|
||||||
|
.endm
|
||||||
|
|
||||||
#define PROP_INT(tree, name, val) \
|
.macro propu32 tree, name, val
|
||||||
PROPHDR(tree, name, 4) \
|
prophdr \tree, \name, 4
|
||||||
FDTLONG(val) ;
|
fdtlong \val
|
||||||
|
.endm
|
||||||
|
|
||||||
#define PROP_INT64(tree, name, valh, vall) \
|
.macro propu64 tree, name, valh, vall
|
||||||
PROPHDR(tree, name, 8) \
|
prophdr \tree, \name, 8
|
||||||
FDTLONG(valh) ; \
|
fdtlong \valh
|
||||||
FDTLONG(vall) ;
|
fdtlong \vall
|
||||||
|
.endm
|
||||||
|
|
||||||
#define PROP_STR(tree, name, str) \
|
.macro propstr tree, name, str:vararg
|
||||||
PROPHDR(tree, name, 55f - 54f) \
|
prophdr \tree, \name, (55f - 54f)
|
||||||
54: \
|
54:
|
||||||
.string str ; \
|
.asciz \str
|
||||||
55: \
|
55:
|
||||||
.balign 4 ;
|
.balign 4
|
||||||
|
.endm
|
||||||
|
|
||||||
#define BEGIN_NODE(name) \
|
.macro beginn name:vararg
|
||||||
FDTLONG(FDT_BEGIN_NODE) ; \
|
fdtlong FDT_BEGIN_NODE
|
||||||
.string name ; \
|
.asciz \name
|
||||||
.balign 4 ;
|
.balign 4
|
||||||
|
.endm
|
||||||
|
|
||||||
#define END_NODE \
|
.macro endn
|
||||||
FDTLONG(FDT_END_NODE) ;
|
fdtlong FDT_END_NODE
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro string tree, name, str:vararg
|
||||||
|
\tree\()_\name :
|
||||||
|
.asciz \str
|
||||||
|
.endm
|
||||||
|
|
||||||
#define STRING(tree, name, str) \
|
|
||||||
tree##_##name: ; \
|
|
||||||
.string str ;
|
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
|
||||||
TREE_HDR(test_tree1)
|
treehdr test_tree1
|
||||||
|
|
||||||
.balign 8
|
.balign 8
|
||||||
test_tree1_rsvmap:
|
test_tree1_rsvmap:
|
||||||
RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L)
|
rsvmape TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L
|
||||||
RSVMAP_ENTRY(TEST_ADDR_2H, TEST_ADDR_2L, TEST_SIZE_2H, TEST_SIZE_2L)
|
rsvmape TEST_ADDR_2H, TEST_ADDR_2L, TEST_SIZE_2H, TEST_SIZE_2L
|
||||||
RSVMAP_ENTRY(0, 0, 0, 0)
|
rsvmape 0, 0, 0, 0
|
||||||
test_tree1_rsvmap_end:
|
test_tree1_rsvmap_end:
|
||||||
|
|
||||||
test_tree1_struct:
|
test_tree1_struct:
|
||||||
BEGIN_NODE("")
|
beginn ""
|
||||||
PROP_STR(test_tree1, compatible, "test_tree1")
|
propstr test_tree1, compatible, "test_tree1"
|
||||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
|
propu32 test_tree1, prop_int, TEST_VALUE_1
|
||||||
PROP_INT64(test_tree1, prop_int64, TEST_VALUE64_1H, TEST_VALUE64_1L)
|
propu64 test_tree1, prop_int64, TEST_VALUE64_1H, TEST_VALUE64_1L
|
||||||
PROP_STR(test_tree1, prop_str, TEST_STRING_1)
|
propstr test_tree1, prop_str, TEST_STRING_1
|
||||||
PROP_INT(test_tree1, address_cells, 1)
|
propu32 test_tree1, address_cells, 1
|
||||||
PROP_INT(test_tree1, size_cells, 0)
|
propu32 test_tree1, size_cells, 0
|
||||||
|
|
||||||
BEGIN_NODE("subnode@1")
|
beginn "subnode@1"
|
||||||
PROP_STR(test_tree1, compatible, "subnode1")
|
propstr test_tree1, compatible, "subnode1"
|
||||||
PROP_INT(test_tree1, reg, 1)
|
propu32 test_tree1, reg, 1
|
||||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
|
propu32 test_tree1, prop_int, TEST_VALUE_1
|
||||||
|
|
||||||
BEGIN_NODE("subsubnode")
|
beginn "subsubnode"
|
||||||
PROP_STR(test_tree1, compatible, "subsubnode1\0subsubnode")
|
propstr test_tree1, compatible, "subsubnode1\0subsubnode"
|
||||||
PROP_STR(test_tree1, placeholder, "this is a placeholder string\0string2")
|
propstr test_tree1, placeholder, "this is a placeholder string\0string2"
|
||||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_1)
|
propu32 test_tree1, prop_int, TEST_VALUE_1
|
||||||
END_NODE
|
endn
|
||||||
|
|
||||||
BEGIN_NODE("ss1")
|
beginn "ss1"
|
||||||
END_NODE
|
endn
|
||||||
|
|
||||||
END_NODE
|
endn
|
||||||
|
|
||||||
BEGIN_NODE("subnode@2")
|
beginn "subnode@2"
|
||||||
PROP_INT(test_tree1, reg, 2)
|
propu32 test_tree1, reg, 2
|
||||||
PROP_INT(test_tree1, linux_phandle, PHANDLE_1)
|
propu32 test_tree1, linux_phandle, PHANDLE_1
|
||||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
|
propu32 test_tree1, prop_int, TEST_VALUE_2
|
||||||
PROP_INT(test_tree1, address_cells, 1)
|
propu32 test_tree1, address_cells, 1
|
||||||
PROP_INT(test_tree1, size_cells, 0)
|
propu32 test_tree1, size_cells, 0
|
||||||
|
|
||||||
BEGIN_NODE("subsubnode@0")
|
beginn "subsubnode@0"
|
||||||
PROP_INT(test_tree1, reg, 0)
|
propu32 test_tree1, reg, 0
|
||||||
PROP_INT(test_tree1, phandle, PHANDLE_2)
|
propu32 test_tree1, phandle, PHANDLE_2
|
||||||
PROP_STR(test_tree1, compatible, "subsubnode2\0subsubnode")
|
propstr test_tree1, compatible, "subsubnode2\0subsubnode"
|
||||||
PROP_INT(test_tree1, prop_int, TEST_VALUE_2)
|
propu32 test_tree1, prop_int, TEST_VALUE_2
|
||||||
END_NODE
|
endn
|
||||||
|
|
||||||
BEGIN_NODE("ss2")
|
beginn "ss2"
|
||||||
END_NODE
|
endn
|
||||||
|
|
||||||
END_NODE
|
endn
|
||||||
|
|
||||||
END_NODE
|
endn
|
||||||
FDTLONG(FDT_END)
|
fdtlong FDT_END
|
||||||
test_tree1_struct_end:
|
test_tree1_struct_end:
|
||||||
|
|
||||||
test_tree1_strings:
|
test_tree1_strings:
|
||||||
STRING(test_tree1, compatible, "compatible")
|
string test_tree1, compatible, "compatible"
|
||||||
STRING(test_tree1, prop_int, "prop-int")
|
string test_tree1, prop_int, "prop-int"
|
||||||
STRING(test_tree1, prop_int64, "prop-int64")
|
string test_tree1, prop_int64, "prop-int64"
|
||||||
STRING(test_tree1, prop_str, "prop-str")
|
string test_tree1, prop_str, "prop-str"
|
||||||
STRING(test_tree1, linux_phandle, "linux,phandle")
|
string test_tree1, linux_phandle, "linux,phandle"
|
||||||
STRING(test_tree1, phandle, "phandle")
|
string test_tree1, phandle, "phandle"
|
||||||
STRING(test_tree1, reg, "reg")
|
string test_tree1, reg, "reg"
|
||||||
STRING(test_tree1, placeholder, "placeholder")
|
string test_tree1, placeholder, "placeholder"
|
||||||
STRING(test_tree1, address_cells, "#address-cells")
|
string test_tree1, address_cells, "#address-cells"
|
||||||
STRING(test_tree1, size_cells, "#size-cells")
|
string test_tree1, size_cells, "#size-cells"
|
||||||
test_tree1_strings_end:
|
test_tree1_strings_end:
|
||||||
test_tree1_end:
|
test_tree1_end:
|
||||||
|
|
||||||
|
|
||||||
TREE_HDR(truncated_property)
|
treehdr truncated_property
|
||||||
EMPTY_RSVMAP(truncated_property)
|
empty_rsvmap truncated_property
|
||||||
|
|
||||||
truncated_property_struct:
|
truncated_property_struct:
|
||||||
BEGIN_NODE("")
|
beginn ""
|
||||||
PROPHDR(truncated_property, prop_truncated, 4)
|
prophdr truncated_property, prop_truncated, 4
|
||||||
/* Oops, no actual property data here */
|
/* Oops, no actual property data here */
|
||||||
truncated_property_struct_end:
|
truncated_property_struct_end:
|
||||||
|
|
||||||
truncated_property_strings:
|
truncated_property_strings:
|
||||||
STRING(truncated_property, prop_truncated, "truncated")
|
string truncated_property, prop_truncated, "truncated"
|
||||||
truncated_property_strings_end:
|
truncated_property_strings_end:
|
||||||
|
|
||||||
truncated_property_end:
|
truncated_property_end:
|
||||||
|
|
||||||
|
|
||||||
TREE_HDR(bad_node_char)
|
treehdr bad_node_char
|
||||||
EMPTY_RSVMAP(bad_node_char)
|
empty_rsvmap bad_node_char
|
||||||
|
|
||||||
bad_node_char_struct:
|
bad_node_char_struct:
|
||||||
BEGIN_NODE("")
|
beginn ""
|
||||||
BEGIN_NODE("sub$node")
|
beginn "sub$node"
|
||||||
END_NODE
|
endn
|
||||||
END_NODE
|
endn
|
||||||
FDTLONG(FDT_END)
|
fdtlong FDT_END
|
||||||
bad_node_char_struct_end:
|
bad_node_char_struct_end:
|
||||||
|
|
||||||
bad_node_char_strings:
|
bad_node_char_strings:
|
||||||
|
@ -176,15 +189,15 @@ bad_node_char_strings_end:
|
||||||
bad_node_char_end:
|
bad_node_char_end:
|
||||||
|
|
||||||
|
|
||||||
TREE_HDR(bad_node_format)
|
treehdr bad_node_format
|
||||||
EMPTY_RSVMAP(bad_node_format)
|
empty_rsvmap bad_node_format
|
||||||
|
|
||||||
bad_node_format_struct:
|
bad_node_format_struct:
|
||||||
BEGIN_NODE("")
|
beginn ""
|
||||||
BEGIN_NODE("subnode@1@2")
|
beginn "subnode@1@2"
|
||||||
END_NODE
|
endn
|
||||||
END_NODE
|
endn
|
||||||
FDTLONG(FDT_END)
|
fdtlong FDT_END
|
||||||
bad_node_format_struct_end:
|
bad_node_format_struct_end:
|
||||||
|
|
||||||
bad_node_format_strings:
|
bad_node_format_strings:
|
||||||
|
@ -192,18 +205,18 @@ bad_node_format_strings_end:
|
||||||
bad_node_format_end:
|
bad_node_format_end:
|
||||||
|
|
||||||
|
|
||||||
TREE_HDR(bad_prop_char)
|
treehdr bad_prop_char
|
||||||
EMPTY_RSVMAP(bad_prop_char)
|
empty_rsvmap bad_prop_char
|
||||||
|
|
||||||
bad_prop_char_struct:
|
bad_prop_char_struct:
|
||||||
BEGIN_NODE("")
|
beginn ""
|
||||||
PROP_INT(bad_prop_char, prop, TEST_VALUE_1)
|
propu32 bad_prop_char, prop, TEST_VALUE_1
|
||||||
END_NODE
|
endn
|
||||||
FDTLONG(FDT_END)
|
fdtlong FDT_END
|
||||||
bad_prop_char_struct_end:
|
bad_prop_char_struct_end:
|
||||||
|
|
||||||
bad_prop_char_strings:
|
bad_prop_char_strings:
|
||||||
STRING(bad_prop_char, prop, "prop$erty")
|
string bad_prop_char, prop, "prop$erty"
|
||||||
bad_prop_char_strings_end:
|
bad_prop_char_strings_end:
|
||||||
bad_prop_char_end:
|
bad_prop_char_end:
|
||||||
|
|
||||||
|
@ -212,62 +225,60 @@ bad_prop_char_end:
|
||||||
.balign 8
|
.balign 8
|
||||||
.globl ovf_size_strings
|
.globl ovf_size_strings
|
||||||
ovf_size_strings:
|
ovf_size_strings:
|
||||||
FDTLONG(FDT_MAGIC)
|
fdtlong FDT_MAGIC
|
||||||
FDTLONG(ovf_size_strings_end - ovf_size_strings)
|
fdtlong (ovf_size_strings_end - ovf_size_strings)
|
||||||
FDTLONG(ovf_size_strings_struct - ovf_size_strings)
|
fdtlong (ovf_size_strings_struct - ovf_size_strings)
|
||||||
FDTLONG(ovf_size_strings_strings - ovf_size_strings)
|
fdtlong (ovf_size_strings_strings - ovf_size_strings)
|
||||||
FDTLONG(ovf_size_strings_rsvmap - ovf_size_strings)
|
fdtlong (ovf_size_strings_rsvmap - ovf_size_strings)
|
||||||
FDTLONG(0x11)
|
fdtlong 0x11
|
||||||
FDTLONG(0x10)
|
fdtlong 0x10
|
||||||
FDTLONG(0)
|
fdtlong 0
|
||||||
FDTLONG(0xffffffff)
|
fdtlong 0xffffffff
|
||||||
FDTLONG(ovf_size_strings_struct_end - ovf_size_strings_struct)
|
fdtlong (ovf_size_strings_struct_end - ovf_size_strings_struct)
|
||||||
EMPTY_RSVMAP(ovf_size_strings)
|
empty_rsvmap ovf_size_strings
|
||||||
|
|
||||||
ovf_size_strings_struct:
|
ovf_size_strings_struct:
|
||||||
BEGIN_NODE("")
|
beginn ""
|
||||||
PROP_INT(ovf_size_strings, bad_string, 0)
|
propu32 ovf_size_strings, bad_string, 0
|
||||||
END_NODE
|
endn
|
||||||
FDTLONG(FDT_END)
|
fdtlong FDT_END
|
||||||
ovf_size_strings_struct_end:
|
ovf_size_strings_struct_end:
|
||||||
|
|
||||||
ovf_size_strings_strings:
|
ovf_size_strings_strings:
|
||||||
STRING(ovf_size_strings, x, "x")
|
string ovf_size_strings, x, "x"
|
||||||
ovf_size_strings_bad_string = ovf_size_strings_strings + 0x10000000
|
ovf_size_strings_bad_string = ovf_size_strings_strings + 0x10000000
|
||||||
ovf_size_strings_strings_end:
|
ovf_size_strings_strings_end:
|
||||||
ovf_size_strings_end:
|
ovf_size_strings_end:
|
||||||
|
|
||||||
|
|
||||||
/* truncated_string */
|
/* truncated_string */
|
||||||
TREE_HDR(truncated_string)
|
treehdr truncated_string
|
||||||
EMPTY_RSVMAP(truncated_string)
|
empty_rsvmap truncated_string
|
||||||
|
|
||||||
truncated_string_struct:
|
truncated_string_struct:
|
||||||
BEGIN_NODE("")
|
beginn ""
|
||||||
PROP_EMPTY(truncated_string, good_string)
|
propnil truncated_string, good_string
|
||||||
PROP_EMPTY(truncated_string, bad_string)
|
propnil truncated_string, bad_string
|
||||||
END_NODE
|
endn
|
||||||
FDTLONG(FDT_END)
|
fdtlong FDT_END
|
||||||
truncated_string_struct_end:
|
truncated_string_struct_end:
|
||||||
|
|
||||||
truncated_string_strings:
|
truncated_string_strings:
|
||||||
STRING(truncated_string, good_string, "good")
|
string truncated_string, good_string, "good"
|
||||||
truncated_string_bad_string:
|
truncated_string_bad_string:
|
||||||
.byte 'b'
|
.ascii "bad"
|
||||||
.byte 'a'
|
|
||||||
.byte 'd'
|
|
||||||
/* NOTE: terminating \0 deliberately missing */
|
/* NOTE: terminating \0 deliberately missing */
|
||||||
truncated_string_strings_end:
|
truncated_string_strings_end:
|
||||||
truncated_string_end:
|
truncated_string_end:
|
||||||
|
|
||||||
|
|
||||||
/* truncated_memrsv */
|
/* truncated_memrsv */
|
||||||
TREE_HDR(truncated_memrsv)
|
treehdr truncated_memrsv
|
||||||
|
|
||||||
truncated_memrsv_struct:
|
truncated_memrsv_struct:
|
||||||
BEGIN_NODE("")
|
beginn ""
|
||||||
END_NODE
|
endn
|
||||||
FDTLONG(FDT_END)
|
fdtlong FDT_END
|
||||||
truncated_memrsv_struct_end:
|
truncated_memrsv_struct_end:
|
||||||
|
|
||||||
truncated_memrsv_strings:
|
truncated_memrsv_strings:
|
||||||
|
@ -275,7 +286,41 @@ truncated_memrsv_strings_end:
|
||||||
|
|
||||||
.balign 8
|
.balign 8
|
||||||
truncated_memrsv_rsvmap:
|
truncated_memrsv_rsvmap:
|
||||||
RSVMAP_ENTRY(TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L)
|
rsvmape TEST_ADDR_1H, TEST_ADDR_1L, TEST_SIZE_1H, TEST_SIZE_1L
|
||||||
truncated_memrsv_rsvmap_end:
|
truncated_memrsv_rsvmap_end:
|
||||||
|
|
||||||
truncated_memrsv_end:
|
truncated_memrsv_end:
|
||||||
|
|
||||||
|
|
||||||
|
/* two root nodes */
|
||||||
|
treehdr two_roots
|
||||||
|
empty_rsvmap two_roots
|
||||||
|
|
||||||
|
two_roots_struct:
|
||||||
|
beginn ""
|
||||||
|
endn
|
||||||
|
beginn ""
|
||||||
|
endn
|
||||||
|
fdtlong FDT_END
|
||||||
|
two_roots_struct_end:
|
||||||
|
|
||||||
|
two_roots_strings:
|
||||||
|
two_roots_strings_end:
|
||||||
|
|
||||||
|
two_roots_end:
|
||||||
|
|
||||||
|
|
||||||
|
/* root node with a non-empty name */
|
||||||
|
treehdr named_root
|
||||||
|
empty_rsvmap named_root
|
||||||
|
|
||||||
|
named_root_struct:
|
||||||
|
beginn "fake"
|
||||||
|
endn
|
||||||
|
fdtlong FDT_END
|
||||||
|
named_root_struct_end:
|
||||||
|
|
||||||
|
named_root_strings:
|
||||||
|
named_root_strings_end:
|
||||||
|
|
||||||
|
named_root_end:
|
||||||
|
|
|
@ -13,8 +13,11 @@
|
||||||
int64: [!u64 [0x200000000]]
|
int64: [!u64 [0x200000000]]
|
||||||
int64-array: [!u64 [0x100000000, 0x0]]
|
int64-array: [!u64 [0x100000000, 0x0]]
|
||||||
a-string-with-nulls: ["foo\0bar", "baz"]
|
a-string-with-nulls: ["foo\0bar", "baz"]
|
||||||
|
a-phandle: [[!phandle 0x1]]
|
||||||
|
a-phandle-with-args: [[!phandle 0x1, 0x0, 0x1], [!phandle 0x1, 0x2, 0x3]]
|
||||||
subsubnode:
|
subsubnode:
|
||||||
compatible: ["subsubnode1", "subsubnode"]
|
compatible: ["subsubnode1", "subsubnode"]
|
||||||
|
phandle: [[0x1]]
|
||||||
subsubsubnode:
|
subsubsubnode:
|
||||||
compatible: ["subsubsubnode1", [0x1234], "subsubsubnode"]
|
compatible: ["subsubsubnode1", [0x1234], "subsubsubnode"]
|
||||||
...
|
...
|
||||||
|
|
|
@ -16,9 +16,12 @@
|
||||||
int64 = /bits/ 64 <0x200000000>;
|
int64 = /bits/ 64 <0x200000000>;
|
||||||
int64-array = /bits/ 64 <0x100000000 0x00> int64_array_label_end:;
|
int64-array = /bits/ 64 <0x100000000 0x00> int64_array_label_end:;
|
||||||
a-string-with-nulls = "foo\0bar", "baz";
|
a-string-with-nulls = "foo\0bar", "baz";
|
||||||
|
a-phandle = <&subsub1>;
|
||||||
|
a-phandle-with-args = <&subsub1 0x00 0x01>, <&subsub1 0x02 0x03>;
|
||||||
|
|
||||||
subsub1: subsubnode {
|
subsub1: subsubnode {
|
||||||
compatible = "subsubnode1", "subsubnode";
|
compatible = "subsubnode1", "subsubnode";
|
||||||
|
phandle = <0x01>;
|
||||||
|
|
||||||
subsubsub1: subsubsubnode {
|
subsubsub1: subsubsubnode {
|
||||||
compatible = "subsubsubnode1", <0x1234>, valuea: valueb: "subsubsubnode";
|
compatible = "subsubsubnode1", <0x1234>, valuea: valueb: "subsubsubnode";
|
||||||
|
|
|
@ -73,6 +73,9 @@ static void check_sizes(char *modifier, int expected_size)
|
||||||
|
|
||||||
*ptr = 's';
|
*ptr = 's';
|
||||||
check(fmt, 's', -1);
|
check(fmt, 's', -1);
|
||||||
|
|
||||||
|
*ptr = 'r';
|
||||||
|
check(fmt, 'r', -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_utilfdt_decode_type(void)
|
static void test_utilfdt_decode_type(void)
|
||||||
|
@ -90,7 +93,7 @@ static void test_utilfdt_decode_type(void)
|
||||||
/* try every other character */
|
/* try every other character */
|
||||||
checkfail("");
|
checkfail("");
|
||||||
for (ch = ' '; ch < 127; ch++) {
|
for (ch = ' '; ch < 127; ch++) {
|
||||||
if (!strchr("iuxs", ch)) {
|
if (!strchr("iuxsr", ch)) {
|
||||||
*fmt = ch;
|
*fmt = ch;
|
||||||
fmt[1] = '\0';
|
fmt[1] = '\0';
|
||||||
checkfail(fmt);
|
checkfail(fmt);
|
||||||
|
|
46
treesource.c
46
treesource.c
|
@ -124,27 +124,6 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has_data_type_information(struct marker *m)
|
|
||||||
{
|
|
||||||
return m->type >= TYPE_UINT8;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct marker *next_type_marker(struct marker *m)
|
|
||||||
{
|
|
||||||
while (m && !has_data_type_information(m))
|
|
||||||
m = m->next;
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t type_marker_length(struct marker *m)
|
|
||||||
{
|
|
||||||
struct marker *next = next_type_marker(m->next);
|
|
||||||
|
|
||||||
if (next)
|
|
||||||
return next->offset - m->offset;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *delim_start[] = {
|
static const char *delim_start[] = {
|
||||||
[TYPE_UINT8] = "[",
|
[TYPE_UINT8] = "[",
|
||||||
[TYPE_UINT16] = "/bits/ 16 <",
|
[TYPE_UINT16] = "/bits/ 16 <",
|
||||||
|
@ -229,26 +208,39 @@ static void write_propval(FILE *f, struct property *prop)
|
||||||
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
|
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
|
||||||
size_t data_len = type_marker_length(m) ? : len - m->offset;
|
size_t data_len = type_marker_length(m) ? : len - m->offset;
|
||||||
const char *p = &prop->val.val[m->offset];
|
const char *p = &prop->val.val[m->offset];
|
||||||
|
struct marker *m_phandle;
|
||||||
|
|
||||||
if (has_data_type_information(m)) {
|
if (is_type_marker(m->type)) {
|
||||||
emit_type = m->type;
|
emit_type = m->type;
|
||||||
fprintf(f, " %s", delim_start[emit_type]);
|
fprintf(f, " %s", delim_start[emit_type]);
|
||||||
} else if (m->type == LABEL)
|
} else if (m->type == LABEL)
|
||||||
fprintf(f, " %s:", m->ref);
|
fprintf(f, " %s:", m->ref);
|
||||||
else if (m->offset)
|
|
||||||
fputc(' ', f);
|
|
||||||
|
|
||||||
if (emit_type == TYPE_NONE) {
|
if (emit_type == TYPE_NONE || chunk_len == 0)
|
||||||
assert(chunk_len == 0);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
switch(emit_type) {
|
switch(emit_type) {
|
||||||
case TYPE_UINT16:
|
case TYPE_UINT16:
|
||||||
write_propval_int(f, p, chunk_len, 2);
|
write_propval_int(f, p, chunk_len, 2);
|
||||||
break;
|
break;
|
||||||
case TYPE_UINT32:
|
case TYPE_UINT32:
|
||||||
|
m_phandle = prop->val.markers;
|
||||||
|
for_each_marker_of_type(m_phandle, REF_PHANDLE)
|
||||||
|
if (m->offset == m_phandle->offset)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (m_phandle) {
|
||||||
|
if (m_phandle->ref[0] == '/')
|
||||||
|
fprintf(f, "&{%s}", m_phandle->ref);
|
||||||
|
else
|
||||||
|
fprintf(f, "&%s", m_phandle->ref);
|
||||||
|
if (chunk_len > 4) {
|
||||||
|
fputc(' ', f);
|
||||||
|
write_propval_int(f, p + 4, chunk_len - 4, 4);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
write_propval_int(f, p, chunk_len, 4);
|
write_propval_int(f, p, chunk_len, 4);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TYPE_UINT64:
|
case TYPE_UINT64:
|
||||||
write_propval_int(f, p, chunk_len, 8);
|
write_propval_int(f, p, chunk_len, 8);
|
||||||
|
|
15
util.c
15
util.c
|
@ -33,6 +33,17 @@ char *xstrdup(const char *s)
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *xstrndup(const char *s, size_t n)
|
||||||
|
{
|
||||||
|
size_t len = strnlen(s, n) + 1;
|
||||||
|
char *d = xmalloc(len);
|
||||||
|
|
||||||
|
memcpy(d, s, len - 1);
|
||||||
|
d[len - 1] = '\0';
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
int xavsprintf_append(char **strp, const char *fmt, va_list ap)
|
int xavsprintf_append(char **strp, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
int n, size = 0; /* start with 128 bytes */
|
int n, size = 0; /* start with 128 bytes */
|
||||||
|
@ -353,11 +364,11 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we should now have a type */
|
/* we should now have a type */
|
||||||
if ((*fmt == '\0') || !strchr("iuxs", *fmt))
|
if ((*fmt == '\0') || !strchr("iuxsr", *fmt))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* convert qualifier (bhL) to byte size */
|
/* convert qualifier (bhL) to byte size */
|
||||||
if (*fmt != 's')
|
if (*fmt != 's' && *fmt != 'r')
|
||||||
*size = qualifier == 'b' ? 1 :
|
*size = qualifier == 'b' ? 1 :
|
||||||
qualifier == 'h' ? 2 :
|
qualifier == 'h' ? 2 :
|
||||||
qualifier == 'l' ? 4 : -1;
|
qualifier == 'l' ? 4 : -1;
|
||||||
|
|
11
util.h
11
util.h
|
@ -2,6 +2,7 @@
|
||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
@ -12,10 +13,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#ifdef __clang__
|
#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
|
||||||
#define PRINTF(i, j) __attribute__((format (printf, i, j)))
|
|
||||||
#else
|
|
||||||
#define PRINTF(i, j) __attribute__((format (gnu_printf, i, j)))
|
#define PRINTF(i, j) __attribute__((format (gnu_printf, i, j)))
|
||||||
|
#else
|
||||||
|
#define PRINTF(i, j) __attribute__((format (printf, i, j)))
|
||||||
#endif
|
#endif
|
||||||
#define NORETURN __attribute__((noreturn))
|
#define NORETURN __attribute__((noreturn))
|
||||||
#else
|
#else
|
||||||
|
@ -60,6 +61,7 @@ static inline void *xrealloc(void *p, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char *xstrdup(const char *s);
|
extern char *xstrdup(const char *s);
|
||||||
|
extern char *xstrndup(const char *s, size_t len);
|
||||||
|
|
||||||
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
|
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
|
||||||
extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...);
|
extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...);
|
||||||
|
@ -142,6 +144,7 @@ int utilfdt_write_err(const char *filename, const void *blob);
|
||||||
* i signed integer
|
* i signed integer
|
||||||
* u unsigned integer
|
* u unsigned integer
|
||||||
* x hex
|
* x hex
|
||||||
|
* r raw
|
||||||
*
|
*
|
||||||
* TODO: Implement ll modifier (8 bytes)
|
* TODO: Implement ll modifier (8 bytes)
|
||||||
* TODO: Implement o type (octal)
|
* TODO: Implement o type (octal)
|
||||||
|
@ -159,7 +162,7 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define USAGE_TYPE_MSG \
|
#define USAGE_TYPE_MSG \
|
||||||
"<type>\ts=string, i=int, u=unsigned, x=hex\n" \
|
"<type>\ts=string, i=int, u=unsigned, x=hex, r=raw\n" \
|
||||||
"\tOptional modifier prefix:\n" \
|
"\tOptional modifier prefix:\n" \
|
||||||
"\t\thh or b=byte, h=2 byte, l=4 byte (default)";
|
"\t\thh or b=byte, h=2 byte, l=4 byte (default)";
|
||||||
|
|
||||||
|
|
1
version_gen.h.in
Normal file
1
version_gen.h.in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#define DTC_VERSION "DTC @VCS_TAG@"
|
18
yamltree.c
18
yamltree.c
|
@ -29,11 +29,12 @@ char *yaml_error_name[] = {
|
||||||
(emitter)->problem, __func__, __LINE__); \
|
(emitter)->problem, __func__, __LINE__); \
|
||||||
})
|
})
|
||||||
|
|
||||||
static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width)
|
static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers,
|
||||||
|
char *data, unsigned int seq_offset, unsigned int len, int width)
|
||||||
{
|
{
|
||||||
yaml_event_t event;
|
yaml_event_t event;
|
||||||
void *tag;
|
void *tag;
|
||||||
int off, start_offset = markers->offset;
|
unsigned int off;
|
||||||
|
|
||||||
switch(width) {
|
switch(width) {
|
||||||
case 1: tag = "!u8"; break;
|
case 1: tag = "!u8"; break;
|
||||||
|
@ -66,7 +67,7 @@ static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, ch
|
||||||
m = markers;
|
m = markers;
|
||||||
is_phandle = false;
|
is_phandle = false;
|
||||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
if (m->offset == (start_offset + off)) {
|
if (m->offset == (seq_offset + off)) {
|
||||||
is_phandle = true;
|
is_phandle = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -112,8 +113,9 @@ static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
|
||||||
static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
|
static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
|
||||||
{
|
{
|
||||||
yaml_event_t event;
|
yaml_event_t event;
|
||||||
int len = prop->val.len;
|
unsigned int len = prop->val.len;
|
||||||
struct marker *m = prop->val.markers;
|
struct marker *m = prop->val.markers;
|
||||||
|
struct marker *markers = prop->val.markers;
|
||||||
|
|
||||||
/* Emit the property name */
|
/* Emit the property name */
|
||||||
yaml_scalar_event_initialize(&event, NULL,
|
yaml_scalar_event_initialize(&event, NULL,
|
||||||
|
@ -151,19 +153,19 @@ static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
|
||||||
|
|
||||||
switch(m->type) {
|
switch(m->type) {
|
||||||
case TYPE_UINT16:
|
case TYPE_UINT16:
|
||||||
yaml_propval_int(emitter, m, data, chunk_len, 2);
|
yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2);
|
||||||
break;
|
break;
|
||||||
case TYPE_UINT32:
|
case TYPE_UINT32:
|
||||||
yaml_propval_int(emitter, m, data, chunk_len, 4);
|
yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4);
|
||||||
break;
|
break;
|
||||||
case TYPE_UINT64:
|
case TYPE_UINT64:
|
||||||
yaml_propval_int(emitter, m, data, chunk_len, 8);
|
yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8);
|
||||||
break;
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
yaml_propval_string(emitter, data, chunk_len);
|
yaml_propval_string(emitter, data, chunk_len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
yaml_propval_int(emitter, m, data, chunk_len, 1);
|
yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue