Compare commits

...

19 commits

Author SHA1 Message Date
Uwe Kleine-König
a26ef6400b Restore phandle references from __fixups__ node
Some checks failed
Build test / build-make (ubuntu) (push) Has been cancelled
Build test / build-make (alpine) (push) Has been cancelled
Build test / build-make (archlinux) (push) Has been cancelled
Build test / build-make (fedora) (push) Has been cancelled
Build test / build-meson (alpine) (push) Has been cancelled
Build test / build-meson (archlinux) (push) Has been cancelled
Build test / build-meson (fedora) (push) Has been cancelled
Build test / build-meson (ubuntu) (push) Has been cancelled
Build test / clang64 (push) Has been cancelled
Build test / mingw32 (push) Has been cancelled
Build test / mingw64 (push) Has been cancelled
Build test / ucrt64 (push) Has been cancelled
The __fixups__ node contains information about labels. Parse its
properties to create phandle markers which improve the resulting dts
when decompiling a device tree blob.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Message-ID: <20250919092912.663304-14-u.kleine-koenig@baylibre.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-16 13:45:59 +11:00
Uwe Kleine-König
05c524db44 Restore phandle references from __local_fixups__ node
The __local_fixups__ node contains information about phandles. Parse it
to improve the result when decompiling a device tree blob.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Message-ID: <20250919092912.663304-13-u.kleine-koenig@baylibre.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-16 13:45:12 +11:00
Uwe Kleine-König
db65a3a3f4 Restore labels from __symbols__ node
If the input has a __symbols__ node, restore the named labels for the
respective nodes.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Message-ID: <20250919092912.663304-12-u.kleine-koenig@baylibre.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-16 13:37:35 +11:00
Uwe Kleine-König
64330c682c Improve type guessing when compiling to dts format
In the presence of (non-type) markers guess the type of each chunk
between markers individually instead of only once for the whole
property.

Note that this only gets relevant with the next few commits that restore
labels and phandles. Note further that this rework is necessary with
these further changes, because phandle markers are currently not
considered for type guessing and so a phandle at an offset that isn't a
multiple of 4 triggers an assertion if the property was guessed to have
type TYPE_UINT32.

Now that guess_value_type() is only called for data chunks without
markers, the function can be simplified a bit.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Message-ID: <20250919092912.663304-11-u.kleine-koenig@baylibre.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-16 13:33:45 +11:00
Uwe Kleine-König
cbb48690c6 Set DTSF_PLUGIN if needed when compiling from dtb
The need for the plugin flag is determined by the existence of __fixups__
or __local_fixups__.

This is a bit simplifying because if __fixups__ or __local_fixups__
exist but don't have properties, the plugin flag isn't needed. But in
practise the test should be good enough such that this corner case
doesn't matter.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Message-ID: <20250919092912.663304-10-u.kleine-koenig@baylibre.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-16 12:02:30 +11:00
Uwe Kleine-König
ef3b1baf63 Emit /plugin/ when compiling to .dts with DTSF_PLUGIN set
This fixes `dtc -I dts -O dts` to make the file a plugin if the source
file is one.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Message-ID: <20250919092912.663304-9-u.kleine-koenig@baylibre.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-16 12:02:30 +11:00
Maldus512
7c78c8542d Added empty node name check
The Devicetree specification states that a node name shall be of form
`node-name@unit-address` and that the `node-name` component cannot be
empty.

However, the `dtc` parser considers a node name as a non-empty
sequences of the allowed characters plus the @ character, and
unit-address extraction is processed after parsing.

This has the side effect of considering an empty name plus an address
as a valid node name (e.g. `@0`).  I've added the node_name_not_empty
check, verifying that the `node->basenamelen` is not zero (unless it's
the root node).

Signed-off-by: Mattia Maldini <mattia512maldini@gmail.com>
[dwg: Re-wrap commit message]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-16 11:51:53 +11:00
Herve Codina
14dd76b967 fdtdump: Change FDT_PROP prob handling to ease future addition
In order to ease future tags addition, perform operation related to
FDT_PROP when the tag is explicitly FDT_PROP instead of relying to a
kind of default value case.

Handle the FDT_PROP tag exactly in the same way as it is done for
other tags.

No functional modification.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Message-ID: <20260112142009.1006236-6-herve.codina@bootlin.com>
Reviewed-by: Ayush Singh <ayush@beagleboard.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-15 11:26:20 +11:00
Stephen Gallagher
9a1c801a1a Fix discarded const qualifiers
It's unsafe to implicitly discard the const qualifier on a pointer. In
overlay_fixup_phandle(), this was probably just an oversight, and making
the "sep" variable a const char * is sufficient to fix it.

In create_node(), however, the "p" variable is directly modifying the
buffer pointed to by "const char* node_name". To fix this, we need to
actually make a duplicate of the buffer and operate on that instead.

This introduces a malloc()/free()  and an unbounded strdup() into the
operation, but fdtput isn't a long-running service and the node_name
argument comes directly from argv, so this shouldn't introduce a
significant performance impact.

Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2026-01-10 18:55:38 +11:00
Tom Rini
194ac9422a libfdt: fdt_get_name: Add can_assume(VALID_DTB) check
Some checks failed
Build test / build-make (alpine) (push) Has been cancelled
Build test / build-make (archlinux) (push) Has been cancelled
Build test / build-make (fedora) (push) Has been cancelled
Build test / build-make (ubuntu) (push) Has been cancelled
Build test / build-meson (alpine) (push) Has been cancelled
Build test / build-meson (archlinux) (push) Has been cancelled
Build test / build-meson (fedora) (push) Has been cancelled
Build test / build-meson (ubuntu) (push) Has been cancelled
Build test / clang64 (push) Has been cancelled
Build test / mingw32 (push) Has been cancelled
Build test / mingw64 (push) Has been cancelled
Build test / ucrt64 (push) Has been cancelled
In this function from fdt_ro.c we have (reasonably) some checks of the
DTB before we begin work. However, we do this in a way that we cannot
make use of the normal FDT_RO_PROBE macro and instead have a direct call
to fdt_ro_probe_(). Add a test for !can_assume(VALID_DTB) here first so
that in cases where we are assuming a valid DTB we can omit the checks.

Signed-off-by: Tom Rini <trini@konsulko.com>
Message-ID: <20251210022002.3004223-4-trini@konsulko.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-12-10 17:47:45 +11:00
Tom Rini
39cae0bd00 libfdt: Improve size savings in FDT_RO_PROBE slightly
In the case where we have set FDT_ASSUME_MASK to disable
ASSUME_VALID_DTB checks, we can improve the FDT_RO_PROBE macro slightly.
The first thing that fdt_ro_probe_() does when we can_assume(VALID_DTB)
is true is to return whatever the contents of the totalsize field of the
DTB is. Since the FDT_RO_PROBE macro only cares about a negative value
there, we can optimize this check such that we are to assume it's a
valid DTB, we don't need to do anything here.

Signed-off-by: Tom Rini <trini@konsulko.com>
Message-ID: <20251210022002.3004223-3-trini@konsulko.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-12-10 17:46:08 +11:00
Tom Rini
b126924732 libfdt: libfdt_internal.h correct final comment in ASSUME block
The value "ASSUME_SANE" was never used in the project here, only
ASSUME_PERFECT was used. Update the comment to reflect the correct name.

Fixes: 464962489d ("Add a way to control the level of checks in the code")
Signed-off-by: Tom Rini <trini@konsulko.com>
Message-ID: <20251210022002.3004223-2-trini@konsulko.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-12-10 17:40:17 +11:00
Adam Lackorzynski
7f3184a6c5 libfdt: Remove old MacOS strnlen workaround
Some checks failed
Build test / build-make (alpine) (push) Has been cancelled
Build test / build-make (archlinux) (push) Has been cancelled
Build test / build-make (fedora) (push) Has been cancelled
Build test / build-make (ubuntu) (push) Has been cancelled
Build test / build-meson (alpine) (push) Has been cancelled
Build test / build-meson (archlinux) (push) Has been cancelled
Build test / build-meson (fedora) (push) Has been cancelled
Build test / build-meson (ubuntu) (push) Has been cancelled
Build test / clang64 (push) Has been cancelled
Build test / mingw32 (push) Has been cancelled
Build test / mingw64 (push) Has been cancelled
Build test / ucrt64 (push) Has been cancelled
The check for the MacOS X version (10.7) is problematic, because it
fails unless _DARWIN_C_SOURCE is defined if also _POSIX_C_SOURCE or
_XOPEN_SOURCE is defined, as then the Darwin version defines are not
defined.  We cannot force _DARWIN_C_SOURCE reliably in the header
either, because we cannot be sure that the libfdt_env.h has not already
been included by another source before.

The check is also only for very old versions of Mac OS X. In the
interest of not replacing strnlen arbitrarily for sources using
libfdt and considering that the last version of OS X 10.6 was
released in 2011 I propose to remove the workaround for that system.

We noticed as compiling fdt_strnlen in C++ environments fails
(missing cast for memchr).

Signed-off-by: Adam Lackorzynski <adam@l4re.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-09-30 12:03:03 +10:00
Andrew Davis
9197f1ccd9 checks: Do not check overlays for alias paths
The path given as an alias inside an overlay can be a path to a node
in the base DT. The path check searches only the overlay as that is
the only tree available leading to false check failures.

Skip this check when checking an overlay.

Signed-off-by: Andrew Davis <afd@ti.com>
Message-ID: <20250822171038.190122-1-afd@ti.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-08-25 11:39:08 +10:00
Uwe Kleine-König
e1284ee5dc livetree: Add only new data to fixup nodes instead of complete regeneration
Removing the complete __fixups__ and __local_fixups__ tree might delete
data that should better be retained. See the added test for a situation
that was broken before.

Note that without removing /__fixups__ and /__local_fixups__ in
generate_fixups_tree() and generate_local_fixups_tree() respectively
calling build_and_name_child_node() isn't safe as the nodes might
already exist and then a duplicate would be added. So build_root_node()
has to be used which copes correctly here.

Fixes: 915daadbb6 ("Start with empty __local_fixups__ and __fixups__ nodes")
Closes: https://github.com/dgibson/dtc/issues/170
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Message-ID: <b061ee57157fafbb9d5b9b0b86af760d13a04eda.1755512759.git.u.kleine-koenig@baylibre.com>
[dwg: Use -1 instead of 1 as an error return]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-08-20 21:34:05 +10:00
Niklas Söderlund
cba90ce820 checks: Remove check for graph child addresses
The dtc graph_child_address check can't distinguish between bindings
where there can only be a single endpoint, and cases where there can be
multiple endpoints.

In cases where the bindings allow for multiple endpoints but only one is
described false warnings about unnecessary #address-cells/#size-cells
can be generated, but only if the endpoint described have an address of
0 (A), for single endpoints with a non-zero address (B) no warnings are
generated.

A)
    ports {
	#address-cells = <1>;
	#size-cells = <0>;

	port@0 {
	    #address-cells = <1>;
	    #size-cells = <0>;

	    sourceA: endpoint@0 {
		reg = <0>
	    };
	};
    };

B)
    ports {
	#address-cells = <1>;
	#size-cells = <0>;

	port@0 {
	    #address-cells = <1>;
	    #size-cells = <0>;

	    sourceB: endpoint@1 {
		reg = <1>
	    };
	};
    };

Remove the check as it is somewhat redundant now that we can use schemas
to validate the full node.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Message-ID: <20250817133733.3483922-1-niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-08-19 09:33:15 +10:00
Uwe Kleine-König
763c6ab418 livetree: Simplify append_to_property()
The two if branches are quite similar. Build the property first (in case
it doesn't exist) and then the common parts can be done outside the if
block.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Message-ID: <eef88e559f5b9818c4c2311fa8a75ab6fd4508d5.1755512759.git.u.kleine-koenig@baylibre.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-08-19 09:24:37 +10:00
Rob Herring (Arm)
739403f222 libfdt: Drop including string.h from libfdt_internal.h
Commit 0f69cedc08 ("libfdt_internal: fdt_find_string_len_()") added a
string.h include to libfdt_internal.h which introduces a libc dependency
which cannot be overridden. Environments without libc (e.g. Linux
kernel) use a custom libfdt_env.h. string.h is already indirectly
included in libfdt_env.h, so it can be dropped from libfdt_internal.h.

Fixes: 0f69cedc08 ("libfdt_internal: fdt_find_string_len_()")
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Message-ID: <20250811130416.2653959-1-robh@kernel.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-08-13 11:09:10 +10:00
Colin Finck
1c6c51e51b Consider drive letters when checking for absolute paths on Windows.
This still requires you to specify paths with forward slashes instead of
backslashes on Windows, due to many hardcoded checks for '/'.
Fortunately, the Windows user APIs all support forward slashes too.

Signed-off-by: Colin Finck <mail@colinfinck.de>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2025-08-07 21:42:42 +10:00
16 changed files with 474 additions and 158 deletions

View file

@ -340,6 +340,14 @@ 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_not_empty(struct check *c, struct dt_info *dti,
struct node *node)
{
if (node->basenamelen == 0 && node->parent != NULL)
FAIL(c, dti, node, "Empty node name");
}
ERROR(node_name_not_empty, check_node_name_not_empty, NULL, &node_name_chars);
static void check_node_name_vs_property_name(struct check *c, static void check_node_name_vs_property_name(struct check *c,
struct dt_info *dti, struct dt_info *dti,
struct node *node) struct node *node)
@ -718,11 +726,14 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
continue; continue;
} }
if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) { /* This check does not work for overlays with external paths */
if (!(dti->dtsflags & DTSF_PLUGIN) &&
(!prop->val.val || !get_node_by_path(dti->dt, prop->val.val))) {
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)", FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
prop->val.val); prop->val.val);
continue; continue;
} }
if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name)) if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name))
FAIL(c, dti, node, "aliases property name must include only lowercase and '-'"); FAIL(c, dti, node, "aliases property name must include only lowercase and '-'");
} }
@ -1894,34 +1905,9 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
} }
WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes); WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
static void check_graph_child_address(struct check *c, struct dt_info *dti,
struct node *node)
{
int cnt = 0;
struct node *child;
if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
return;
for_each_child(node, child) {
struct property *prop = get_property(child, "reg");
/* No error if we have any non-zero unit address */
if (prop && propval_cell(prop) != 0 )
return;
cnt++;
}
if (cnt == 1 && node->addr_cells != -1)
FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
node->children->name);
}
WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes, &graph_port, &graph_endpoint);
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, &node_name_not_empty, &property_name_chars,
&name_is_string, &name_properties, &node_name_vs_property_name, &name_is_string, &name_properties, &node_name_vs_property_name,
&duplicate_label, &duplicate_label,
@ -2005,7 +1991,7 @@ static struct check *check_table[] = {
&alias_paths, &alias_paths,
&graph_nodes, &graph_child_address, &graph_port, &graph_endpoint, &graph_nodes, &graph_port, &graph_endpoint,
&always_fail, &always_fail,
}; };

5
dtc.c
View file

@ -338,9 +338,14 @@ int main(int argc, char *argv[])
if (auto_label_aliases) if (auto_label_aliases)
generate_label_tree(dti, "aliases", false); generate_label_tree(dti, "aliases", false);
generate_labels_from_tree(dti, "__symbols__");
if (generate_symbols) if (generate_symbols)
generate_label_tree(dti, "__symbols__", true); generate_label_tree(dti, "__symbols__", true);
fixup_phandles(dti, "__fixups__");
local_fixup_phandles(dti, "__local_fixups__");
if (generate_fixups) { if (generate_fixups) {
generate_fixups_tree(dti, "__fixups__"); generate_fixups_tree(dti, "__fixups__");
generate_local_fixups_tree(dti, "__local_fixups__"); generate_local_fixups_tree(dti, "__local_fixups__");

6
dtc.h
View file

@ -339,9 +339,12 @@ struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist, struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys); struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct dt_info *dti); void sort_tree(struct dt_info *dti);
void generate_labels_from_tree(struct dt_info *dti, const char *name);
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph); void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, const char *name); void generate_fixups_tree(struct dt_info *dti, const char *name);
void fixup_phandles(struct dt_info *dti, const char *name);
void generate_local_fixups_tree(struct dt_info *dti, const char *name); void generate_local_fixups_tree(struct dt_info *dti, const char *name);
void local_fixup_phandles(struct dt_info *dti, const char *name);
/* Checks */ /* Checks */
@ -357,6 +360,9 @@ struct dt_info *dt_from_blob(const char *fname);
/* Tree source */ /* Tree source */
void property_add_marker(struct property *prop,
enum markertype type, unsigned int offset, char *ref);
void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset);
void dt_to_source(FILE *f, struct dt_info *dti); void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f); struct dt_info *dt_from_source(const char *f);

View file

@ -129,23 +129,25 @@ static void dump_blob(void *blob, bool debug)
continue; continue;
} }
if (tag != FDT_PROP) { if (tag == FDT_PROP) {
fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag); sz = fdt32_to_cpu(GET_CELL(p));
break; s = p_strings + fdt32_to_cpu(GET_CELL(p));
if (version < 16 && sz >= 8)
p = PALIGN(p, 8);
t = p;
p = PALIGN(p + sz, 4);
dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
printf("%*s%s", depth * shift, "", s);
utilfdt_print_data(t, sz);
printf(";\n");
continue;
} }
sz = fdt32_to_cpu(GET_CELL(p));
s = p_strings + fdt32_to_cpu(GET_CELL(p));
if (version < 16 && sz >= 8)
p = PALIGN(p, 8);
t = p;
p = PALIGN(p + sz, 4); fprintf(stderr, "%*s ** Unknown tag 0x%08"PRIx32"\n", depth * shift, "", tag);
break;
dumpf("%04"PRIxPTR": string: %s\n", (uintptr_t)s - blob_off, s);
dumpf("%04"PRIxPTR": value\n", (uintptr_t)t - blob_off);
printf("%*s%s", depth * shift, "", s);
utilfdt_print_data(t, sz);
printf(";\n");
} }
} }

View file

@ -254,19 +254,21 @@ static int create_paths(char **blob, const char *in_path)
static int create_node(char **blob, const char *node_name) static int create_node(char **blob, const char *node_name)
{ {
int node = 0; int node = 0;
char *p; const char *p;
char *path = NULL;
p = strrchr(node_name, '/'); p = strrchr(node_name, '/');
if (!p) { if (!p) {
report_error(node_name, -1, -FDT_ERR_BADPATH); report_error(node_name, -1, -FDT_ERR_BADPATH);
return -1; return -1;
} }
*p = '\0';
*blob = realloc_node(*blob, p + 1); *blob = realloc_node(*blob, p + 1);
if (p > node_name) { if (p > node_name) {
node = fdt_path_offset(*blob, node_name); path = xstrndup(node_name, (size_t)(p - node_name));
node = fdt_path_offset(*blob, path);
free(path);
if (node < 0) { if (node < 0) {
report_error(node_name, -1, node); report_error(node_name, -1, node);
return -1; return -1;

View file

@ -807,6 +807,7 @@ struct dt_info *dt_from_blob(const char *fname)
struct node *tree; struct node *tree;
uint32_t val; uint32_t val;
int flags = 0; int flags = 0;
unsigned int dtsflags = DTSF_V1;
f = srcfile_relative_open(fname, NULL); f = srcfile_relative_open(fname, NULL);
@ -919,5 +920,8 @@ struct dt_info *dt_from_blob(const char *fname)
fclose(f); fclose(f);
return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys); if (get_subnode(tree, "__fixups__") || get_subnode(tree, "__local_fixups__"))
dtsflags |= DTSF_PLUGIN;
return build_dt_info(dtsflags, reservelist, tree, boot_cpuid_phys);
} }

View file

@ -407,7 +407,8 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
const char *fixup_str = value; const char *fixup_str = value;
uint32_t path_len, name_len; uint32_t path_len, name_len;
uint32_t fixup_len; uint32_t fixup_len;
char *sep, *endptr; const char *sep;
char *endptr;
int poffset, ret; int poffset, ret;
fixup_end = memchr(value, '\0', len); fixup_end = memchr(value, '\0', len);

View file

@ -306,8 +306,8 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
const char *nameptr; const char *nameptr;
int err; int err;
if (((err = fdt_ro_probe_(fdt)) < 0) if (!can_assume(VALID_DTB) && (((err = fdt_ro_probe_(fdt)) < 0)
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)))
goto fail; goto fail;
nameptr = nh->name; nameptr = nh->name;

View file

@ -66,31 +66,4 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
#undef CPU_TO_FDT16 #undef CPU_TO_FDT16
#undef EXTRACT_BYTE #undef EXTRACT_BYTE
#ifdef __APPLE__
#include <AvailabilityMacros.h>
/* strnlen() is not available on Mac OS < 10.7 */
# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
MAC_OS_X_VERSION_10_7)
#define strnlen fdt_strnlen
/*
* fdt_strnlen: returns the length of a string or max_count - which ever is
* smallest.
* Input 1 string: the string whose size is to be determined
* Input 2 max_count: the maximum value returned by this function
* Output: length of the string or max_count (the smallest of the two)
*/
static inline size_t fdt_strnlen(const char *string, size_t max_count)
{
const char *p = memchr(string, 0, max_count);
return p ? p - string : max_count;
}
#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
MAC_OS_X_VERSION_10_7) */
#endif /* __APPLE__ */
#endif /* LIBFDT_ENV_H */ #endif /* LIBFDT_ENV_H */

View file

@ -6,17 +6,18 @@
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
*/ */
#include <fdt.h> #include <fdt.h>
#include <string.h>
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
int32_t fdt_ro_probe_(const void *fdt); int32_t fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \ #define FDT_RO_PROBE(fdt) \
{ \ { \
int32_t totalsize_; \ if (!can_assume(VALID_DTB)) { \
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \ int32_t totalsize_; \
return totalsize_; \ if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
return totalsize_; \
} \
} }
int fdt_check_node_offset_(const void *fdt, int offset); int fdt_check_node_offset_(const void *fdt, int offset);
@ -93,7 +94,7 @@ static inline uint64_t fdt64_ld_(const fdt64_t *p)
* signature or hash check before using libfdt. * signature or hash check before using libfdt.
* *
* For situations where security is not a concern it may be safe to enable * For situations where security is not a concern it may be safe to enable
* ASSUME_SANE. * ASSUME_PERFECT.
*/ */
enum { enum {
/* /*

View file

@ -340,20 +340,73 @@ void append_to_property(struct node *node,
char *name, const void *data, int len, char *name, const void *data, int len,
enum markertype type) enum markertype type)
{ {
struct data d; struct property *p;
p = get_property(node, name);
if (!p) {
p = build_property(name, empty_data, NULL);
add_property(node, p);
}
p->val = data_add_marker(p->val, type, name);
p->val = data_append_data(p->val, data, len);
}
static int append_unique_str_to_property(struct node *node,
char *name, const char *data, int len)
{
struct property *p; struct property *p;
p = get_property(node, name); p = get_property(node, name);
if (p) { if (p) {
d = data_add_marker(p->val, type, name); const char *s;
d = data_append_data(d, data, len);
p->val = d; if (p->val.len && p->val.val[p->val.len - 1] != '\0')
/* The current content doesn't look like a string */
return -1;
for (s = p->val.val; s < p->val.val + p->val.len; s = strchr(s, '\0') + 1) {
if (strcmp(data, s) == 0)
/* data already contained in node.name */
return 0;
}
} else { } else {
d = data_add_marker(empty_data, type, name); p = build_property(name, empty_data, NULL);
d = data_append_data(d, data, len);
p = build_property(name, d, NULL);
add_property(node, p); add_property(node, p);
} }
p->val = data_add_marker(p->val, TYPE_STRING, name);
p->val = data_append_data(p->val, data, len);
return 0;
}
static int append_unique_u32_to_property(struct node *node, char *name, fdt32_t value)
{
struct property *p;
p = get_property(node, name);
if (p) {
const fdt32_t *v, *val_end = (const fdt32_t *)p->val.val + p->val.len / 4;
if (p->val.len % 4 != 0)
/* The current content doesn't look like a u32 array */
return -1;
for (v = (const void *)p->val.val; v < val_end; v++) {
if (*v == value)
/* value already contained */
return 0;
}
} else {
p = build_property(name, empty_data, NULL);
add_property(node, p);
}
p->val = data_add_marker(p->val, TYPE_UINT32, name);
p->val = data_append_data(p->val, &value, 4);
return 0;
} }
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
@ -918,11 +971,12 @@ static bool any_fixup_tree(struct dt_info *dti, struct node *node)
return false; return false;
} }
static void add_fixup_entry(struct dt_info *dti, struct node *fn, static int add_fixup_entry(struct dt_info *dti, struct node *fn,
struct node *node, struct property *prop, struct node *node, struct property *prop,
struct marker *m) struct marker *m)
{ {
char *entry; char *entry;
int ret;
/* m->ref can only be a REF_PHANDLE, but check anyway */ /* m->ref can only be a REF_PHANDLE, but check anyway */
assert(m->type == REF_PHANDLE); assert(m->type == REF_PHANDLE);
@ -939,32 +993,39 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
xasprintf(&entry, "%s:%s:%u", xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset); node->fullpath, prop->name, m->offset);
append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING); ret = append_unique_str_to_property(fn, m->ref, entry, strlen(entry) + 1);
free(entry); free(entry);
return ret;
} }
static void generate_fixups_tree_internal(struct dt_info *dti, static int generate_fixups_tree_internal(struct dt_info *dti,
struct node *fn, struct node *fn,
struct node *node) struct node *node)
{ {
struct node *dt = dti->dt; struct node *dt = dti->dt;
struct node *c; struct node *c;
struct property *prop; struct property *prop;
struct marker *m; struct marker *m;
struct node *refnode; struct node *refnode;
int ret = 0;
for_each_property(node, prop) { for_each_property(node, prop) {
m = prop->val.markers; m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) { for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref); refnode = get_node_by_ref(dt, m->ref);
if (!refnode) if (!refnode)
add_fixup_entry(dti, fn, node, prop, m); if (add_fixup_entry(dti, fn, node, prop, m))
ret = -1;
} }
} }
for_each_child(node, c) for_each_child(node, c)
generate_fixups_tree_internal(dti, fn, c); if (generate_fixups_tree_internal(dti, fn, c))
ret = -1;
return ret;
} }
static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
@ -989,7 +1050,7 @@ static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
return false; return false;
} }
static void add_local_fixup_entry(struct dt_info *dti, static int add_local_fixup_entry(struct dt_info *dti,
struct node *lfn, struct node *node, struct node *lfn, struct node *node,
struct property *prop, struct marker *m, struct property *prop, struct marker *m,
struct node *refnode) struct node *refnode)
@ -1020,30 +1081,56 @@ static void add_local_fixup_entry(struct dt_info *dti,
free(compp); free(compp);
value_32 = cpu_to_fdt32(m->offset); value_32 = cpu_to_fdt32(m->offset);
append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32); return append_unique_u32_to_property(wn, prop->name, value_32);
} }
static void generate_local_fixups_tree_internal(struct dt_info *dti, static int generate_local_fixups_tree_internal(struct dt_info *dti,
struct node *lfn, struct node *lfn,
struct node *node) struct node *node)
{ {
struct node *dt = dti->dt; struct node *dt = dti->dt;
struct node *c; struct node *c;
struct property *prop; struct property *prop;
struct marker *m; struct marker *m;
struct node *refnode; struct node *refnode;
int ret = 0;
for_each_property(node, prop) { for_each_property(node, prop) {
m = prop->val.markers; m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) { for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref); refnode = get_node_by_ref(dt, m->ref);
if (refnode) if (refnode)
add_local_fixup_entry(dti, lfn, node, prop, m, refnode); if (add_local_fixup_entry(dti, lfn, node, prop, m, refnode))
ret = -1;
} }
} }
for_each_child(node, c) for_each_child(node, c)
generate_local_fixups_tree_internal(dti, lfn, c); if (generate_local_fixups_tree_internal(dti, lfn, c))
ret = -1;
return ret;
}
void generate_labels_from_tree(struct dt_info *dti, const char *name)
{
struct node *an;
struct property *p;
an = get_subnode(dti->dt, name);
if (!an)
return;
for_each_property(an, p) {
struct node *labeled_node;
labeled_node = get_node_by_path(dti->dt, p->val.val);
if (labeled_node)
add_label(&labeled_node->labels, p->name);
else if (quiet < 1)
fprintf(stderr, "Warning: Path %s referenced in property %s/%s missing",
p->val.val, name, p->name);
}
} }
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph) void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
@ -1056,29 +1143,173 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
void generate_fixups_tree(struct dt_info *dti, const char *name) void generate_fixups_tree(struct dt_info *dti, const char *name)
{ {
struct node *n = get_subnode(dti->dt, name);
/* Start with an empty __fixups__ node to not get duplicates */
if (n)
n->deleted = true;
if (!any_fixup_tree(dti, dti->dt)) if (!any_fixup_tree(dti, dti->dt))
return; return;
generate_fixups_tree_internal(dti, if (generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
build_and_name_child_node(dti->dt, name), fprintf(stderr,
dti->dt); "Warning: Preexisting data in %s malformed, some content could not be added.\n",
name);
}
void fixup_phandles(struct dt_info *dti, const char *name)
{
struct node *an;
struct property *fp;
an = get_subnode(dti->dt, name);
if (!an)
return;
for_each_property(an, fp) {
char *fnext = fp->val.val;
char *fv;
unsigned int fl;
while ((fl = fp->val.len - (fnext - fp->val.val))) {
char *propname, *soffset;
struct node *n;
struct property *p;
long offset;
fv = fnext;
fnext = memchr(fv, 0, fl);
if (!fnext) {
if (quiet < 1)
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
fp->name);
break;
}
fnext += 1;
propname = memchr(fv, ':', fnext - 1 - fv);
if (!propname) {
if (quiet < 1)
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
fp->name);
continue;
}
propname++;
soffset = memchr(propname, ':', fnext - 1 - propname);
if (!soffset) {
if (quiet < 1)
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
fp->name);
continue;
}
soffset++;
/*
* temporarily modify the property to not have to create
* a copy for the node path.
*/
*(propname - 1) = '\0';
n = get_node_by_path(dti->dt, fv);
if (!n && quiet < 1)
fprintf(stderr, "Warning: Label %s references non-existing node %s\n",
fp->name, fv);
*(propname - 1) = ':';
if (!n)
continue;
/*
* temporarily modify the property to not have to create
* a copy for the property name.
*/
*(soffset - 1) = '\0';
p = get_property(n, propname);
if (!p && quiet < 1)
fprintf(stderr, "Warning: Label %s references non-existing property %s in node %s\n",
fp->name, n->fullpath, propname);
*(soffset - 1) = ':';
if (!p)
continue;
offset = strtol(soffset, NULL, 0);
if (offset < 0 || offset + 4 > p->val.len) {
if (quiet < 1)
fprintf(stderr,
"Warning: Label %s contains invalid offset for property %s in node %s\n",
fp->name, p->name, n->fullpath);
continue;
}
property_add_marker(p, REF_PHANDLE, offset, fp->name);
}
}
} }
void generate_local_fixups_tree(struct dt_info *dti, const char *name) void generate_local_fixups_tree(struct dt_info *dti, const char *name)
{ {
struct node *n = get_subnode(dti->dt, name);
/* Start with an empty __local_fixups__ node to not get duplicates */
if (n)
n->deleted = true;
if (!any_local_fixup_tree(dti, dti->dt)) if (!any_local_fixup_tree(dti, dti->dt))
return; return;
generate_local_fixups_tree_internal(dti, if (generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
build_and_name_child_node(dti->dt, name), fprintf(stderr,
dti->dt); "Warning: Preexisting data in %s malformed, some content could not be added.\n",
name);
}
static void local_fixup_phandles_node(struct dt_info *dti, struct node *lf, struct node *n)
{
struct property *lfp;
struct node *lfsubnode;
for_each_property(lf, lfp) {
struct property *p = get_property(n, lfp->name);
fdt32_t *offsets = (fdt32_t *)lfp->val.val;
size_t i;
if (!p) {
if (quiet < 1)
fprintf(stderr, "Warning: Property %s in %s referenced in __local_fixups__ missing\n",
lfp->name, n->fullpath);
continue;
}
/*
* Each property in the __local_fixups__ tree is a concatenation
* of offsets, so it must be a multiple of sizeof(fdt32_t).
*/
if (lfp->val.len % sizeof(fdt32_t)) {
if (quiet < 1)
fprintf(stderr, "Warning: property %s in /__local_fixups__%s malformed\n",
lfp->name, n->fullpath);
continue;
}
for (i = 0; i < lfp->val.len / sizeof(fdt32_t); i++)
add_phandle_marker(dti, p, dtb_ld32(offsets + i));
}
for_each_child(lf, lfsubnode) {
struct node *subnode = get_subnode(n, lfsubnode->name);
if (!subnode) {
if (quiet < 1)
fprintf(stderr, "Warning: node %s/%s referenced in __local_fixups__ missing\n",
lfsubnode->name, n->fullpath);
continue;
}
local_fixup_phandles_node(dti, lfsubnode, subnode);
}
}
void local_fixup_phandles(struct dt_info *dti, const char *name)
{
struct node *an;
an = get_subnode(dti->dt, name);
if (!an)
return;
local_fixup_phandles_node(dti, an, dti->dt);
} }

View file

@ -18,6 +18,7 @@ add_project_arguments(
'-Wshadow', '-Wshadow',
'-Wsuggest-attribute=format', '-Wsuggest-attribute=format',
'-Wwrite-strings', '-Wwrite-strings',
'-Wdiscarded-qualifiers',
]), ]),
language: 'c' language: 'c'
) )

View file

@ -88,6 +88,26 @@ static char *shorten_to_initial_path(char *fname)
return NULL; return NULL;
} }
/**
* Returns true if the given path is an absolute one.
*
* On Windows, it either needs to begin with a forward slash or with a drive
* letter (e.g. "C:").
* On all other operating systems, it must begin with a forward slash to be
* considered an absolute path.
*/
static bool is_absolute_path(const char *path)
{
#ifdef WIN32
return (
path[0] == '/' ||
(((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z')) && path[1] == ':')
);
#else
return (path[0] == '/');
#endif
}
/** /**
* Try to open a file in a given directory. * Try to open a file in a given directory.
* *
@ -103,7 +123,7 @@ static char *try_open(const char *dirname, const char *fname, FILE **fp)
{ {
char *fullname; char *fullname;
if (!dirname || fname[0] == '/') if (!dirname || is_absolute_path(fname))
fullname = xstrdup(fname); fullname = xstrdup(fname);
else else
fullname = join_path(dirname, fname); fullname = join_path(dirname, fname);

29
tests/retain-fixups.dts Normal file
View file

@ -0,0 +1,29 @@
/dts-v1/;
/plugin/;
/ {
fixup-node {
property = <0xffffffff>;
property-with-fixup = <0xffffffff>;
property-with-label = <&somenode>;
property-with-label-and-fixup = <&somenode>;
};
label: local-fixup-node {
property = <0xffffffff>;
property-with-local-fixup = <0xffffffff>;
property-with-local-label = <&label>;
property-with-local-label-and-fixup = <&label>;
};
__fixups__ {
somenode = "/fixup-node:property-with-fixup:0", "/fixup-node:property-with-label-and-fixup:0";
};
__local_fixups__ {
local-fixup-node {
property-with-local-fixup = <0x00>;
property-with-local-label-and-fixup = <0x00>;
};
};
};

View file

@ -667,6 +667,11 @@ dtc_tests () {
run_test dtbs_equal_ordered $tree.test.dtb $tree.test.dts.test.dtb run_test dtbs_equal_ordered $tree.test.dtb $tree.test.dts.test.dtb
done done
# Check preservation of __fixups__ and __local_fixups__
run_dtc_test -I dts -O dtb -o retain-fixups.test.dtb "$SRCDIR/retain-fixups.dts"
run_fdtget_test "/fixup-node:property-with-fixup:0 /fixup-node:property-with-label-and-fixup:0 /fixup-node:property-with-label:0" retain-fixups.test.dtb /__fixups__ somenode
run_fdtget_test "property-with-local-fixup\nproperty-with-local-label-and-fixup\nproperty-with-local-label" -p retain-fixups.test.dtb /__local_fixups__/local-fixup-node
# Check -Oyaml output # Check -Oyaml output
if ! $no_yaml; then if ! $no_yaml; then
for tree in type-preservation; do for tree in type-preservation; do
@ -749,7 +754,6 @@ dtc_tests () {
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/good-gpio.dts" -n gpios_property
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
check_tests "$SRCDIR/bad-graph-root1.dts" graph_nodes check_tests "$SRCDIR/bad-graph-root1.dts" graph_nodes
@ -758,7 +762,6 @@ dtc_tests () {
check_tests "$SRCDIR/bad-graph-root4.dts" graph_nodes check_tests "$SRCDIR/bad-graph-root4.dts" graph_nodes
check_tests "$SRCDIR/bad-graph-reg-cells.dts" graph_endpoint check_tests "$SRCDIR/bad-graph-reg-cells.dts" graph_endpoint
check_tests "$SRCDIR/bad-graph-reg-cells.dts" graph_port check_tests "$SRCDIR/bad-graph-reg-cells.dts" graph_port
check_tests "$SRCDIR/bad-graph-child-address.dts" graph_child_address
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" 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

View file

@ -173,23 +173,59 @@ static struct marker **add_marker(struct marker **mi,
return &nm->next; return &nm->next;
} }
static void add_string_markers(struct property *prop) void property_add_marker(struct property *prop,
enum markertype type, unsigned int offset, char *ref)
{ {
int l, len = prop->val.len; add_marker(&prop->val.markers, type, offset, ref);
const char *p = prop->val.val; }
static void add_string_markers(struct property *prop, unsigned int offset, int len)
{
int l;
const char *p = prop->val.val + offset;
struct marker **mi = &prop->val.markers; struct marker **mi = &prop->val.markers;
for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1) for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1)
mi = add_marker(mi, TYPE_STRING, l, NULL); mi = add_marker(mi, TYPE_STRING, offset + l, NULL);
} }
static enum markertype guess_value_type(struct property *prop) void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset)
{ {
int len = prop->val.len; cell_t phandle;
const char *p = prop->val.val; struct node *refn;
struct marker *m = prop->val.markers; char *ref;
if (prop->val.len < offset + 4) {
if (quiet < 1)
fprintf(stderr,
"Warning: property %s too short to contain a phandle at offset %u\n",
prop->name, offset);
return;
}
phandle = dtb_ld32(prop->val.val + offset);
refn = get_node_by_phandle(dti->dt, phandle);
if (!refn) {
if (quiet < 1)
fprintf(stderr,
"Warning: node referenced by phandle 0x%x in property %s not found\n",
phandle, prop->name);
return;
}
if (refn->labels)
ref = refn->labels->label;
else
ref = refn->fullpath;
add_marker(&prop->val.markers, REF_PHANDLE, offset, ref);
}
static enum markertype guess_value_type(struct property *prop, unsigned int offset, int len)
{
const char *p = prop->val.val + offset;
int nnotstring = 0, nnul = 0; int nnotstring = 0, nnul = 0;
int nnotstringlbl = 0, nnotcelllbl = 0;
int i; int i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
@ -199,30 +235,49 @@ static enum markertype guess_value_type(struct property *prop)
nnul++; nnul++;
} }
for_each_marker_of_type(m, LABEL) { if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= len - nnul)) {
if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0'))
nnotstringlbl++;
if ((m->offset % sizeof(cell_t)) != 0)
nnotcelllbl++;
}
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
&& (nnotstringlbl == 0)) {
if (nnul > 1) if (nnul > 1)
add_string_markers(prop); add_string_markers(prop, offset, len);
return TYPE_STRING; return TYPE_STRING;
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { } else if ((len % sizeof(cell_t)) == 0) {
return TYPE_UINT32; return TYPE_UINT32;
} }
return TYPE_UINT8; return TYPE_UINT8;
} }
static void guess_type_markers(struct property *prop)
{
struct marker **m = &prop->val.markers;
unsigned int offset = 0;
for (m = &prop->val.markers; *m; m = &((*m)->next)) {
if (is_type_marker((*m)->type))
/* assume the whole property is already marked */
return;
if ((*m)->offset > offset) {
m = add_marker(m, guess_value_type(prop, offset, (*m)->offset - offset),
offset, NULL);
offset = (*m)->offset;
}
if ((*m)->type == REF_PHANDLE) {
m = add_marker(m, TYPE_UINT32, offset, NULL);
offset += 4;
}
}
if (offset < prop->val.len)
add_marker(m, guess_value_type(prop, offset, prop->val.len - offset),
offset, NULL);
}
static void write_propval(FILE *f, struct property *prop) static void write_propval(FILE *f, struct property *prop)
{ {
size_t len = prop->val.len; size_t len = prop->val.len;
struct marker *m = prop->val.markers; struct marker *m;
struct marker dummy_marker;
enum markertype emit_type = TYPE_NONE; enum markertype emit_type = TYPE_NONE;
char *srcstr; char *srcstr;
@ -241,14 +296,8 @@ static void write_propval(FILE *f, struct property *prop)
fprintf(f, " ="); fprintf(f, " =");
if (!next_type_marker(m)) { guess_type_markers(prop);
/* data type information missing, need to guess */ m = prop->val.markers;
dummy_marker.type = guess_value_type(prop);
dummy_marker.next = prop->val.markers;
dummy_marker.offset = 0;
dummy_marker.ref = NULL;
m = &dummy_marker;
}
for_each_marker(m) { for_each_marker(m) {
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
@ -369,7 +418,10 @@ void dt_to_source(FILE *f, struct dt_info *dti)
{ {
struct reserve_info *re; struct reserve_info *re;
fprintf(f, "/dts-v1/;\n\n"); fprintf(f, "/dts-v1/;\n");
if (dti->dtsflags & DTSF_PLUGIN)
fprintf(f, "/plugin/;\n");
fprintf(f, "\n");
for (re = dti->reservelist; re; re = re->next) { for (re = dti->reservelist; re; re = re->next) {
struct label *l; struct label *l;