diff --git a/checks.c b/checks.c index 22f1b2a..59b23b8 100644 --- a/checks.c +++ b/checks.c @@ -302,11 +302,36 @@ static void fixup_phandle_references(struct check *c, struct node *dt, CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR, &duplicate_node_names, &explicit_phandles); +static void fixup_path_references(struct check *c, struct node *dt, + struct node *node, struct property *prop) +{ + struct marker *m = prop->val.markers; + struct node *refnode; + char *path; + + for_each_marker_of_type(m, REF_PATH) { + assert(m->offset <= prop->val.len); + + refnode = get_node_by_ref(dt, m->ref); + if (!refnode) { + FAIL(c, "Reference to non-existent node or label \"%s\"\n", + m->ref); + continue; + } + + path = refnode->fullpath; + prop->val = data_insert_at_marker(prop->val, m, path, + strlen(path) + 1); + } +} +CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR, + &duplicate_node_names); + static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, &name_is_string, &name_properties, &explicit_phandles, - &phandle_references, + &phandle_references, &path_references, }; int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys); diff --git a/data.c b/data.c index 3c4ab87..a94718c 100644 --- a/data.c +++ b/data.c @@ -202,6 +202,21 @@ struct data data_append_data(struct data d, const void *p, int len) return d; } +struct data data_insert_at_marker(struct data d, struct marker *m, + const void *p, int len) +{ + d = data_grow_for(d, len); + memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset); + memcpy(d.val + m->offset, p, len); + d.len += len; + + /* Adjust all markers after the one we're inserting at */ + m = m->next; + for_each_marker(m) + m->offset += len; + return d; +} + struct data data_append_markers(struct data d, struct marker *m) { struct marker **mp = &d.markers; diff --git a/dtc-parser.y b/dtc-parser.y index 43182fd..002ea7f 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -192,6 +192,10 @@ propdata: { $$ = data_merge($1, $3); } + | propdataprefix DT_REF + { + $$ = data_add_marker($1, REF_PATH, $2); + } | propdata DT_LABEL { $$ = data_add_marker($1, LABEL, $2); diff --git a/dtc.h b/dtc.h index 330e274..6528177 100644 --- a/dtc.h +++ b/dtc.h @@ -104,6 +104,7 @@ typedef u32 cell_t; /* Data blobs */ enum markertype { REF_PHANDLE, + REF_PATH, LABEL, }; @@ -139,6 +140,8 @@ struct data data_copy_escape_string(const char *s, int len); struct data data_copy_file(FILE *f, size_t len); struct data data_append_data(struct data d, const void *p, int len); +struct data data_insert_at_marker(struct data d, struct marker *m, + const void *p, int len); struct data data_merge(struct data d1, struct data d2); struct data data_append_cell(struct data d, cell_t word); struct data data_append_re(struct data d, const struct fdt_reserve_entry *re); diff --git a/tests/Makefile.tests b/tests/Makefile.tests index 569bd9e..ff87eaa 100644 --- a/tests/Makefile.tests +++ b/tests/Makefile.tests @@ -9,7 +9,7 @@ LIB_TESTS_L = get_mem_rsv \ sw_tree1 \ move_and_save mangle-layout \ open_pack rw_tree1 setprop del_property del_node \ - string_escapes references \ + string_escapes references path-references \ dtbs_equal_ordered LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%) diff --git a/tests/path-references.c b/tests/path-references.c new file mode 100644 index 0000000..b96c5b2 --- /dev/null +++ b/tests/path-references.c @@ -0,0 +1,83 @@ +/* + * libfdt - Flat Device Tree manipulation + * Testcase for string references in dtc + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include + +#include +#include + +#include "tests.h" +#include "testdata.h" + +void check_ref(const void *fdt, int node, const char *checkpath) +{ + const char *p; + int len; + + p = fdt_getprop(fdt, node, "ref", &len); + if (!p) + FAIL("fdt_getprop(%d, \"ref\"): %s", node, fdt_strerror(len)); + if (!streq(p, checkpath)) + FAIL("'ref' in node at %d has value \"%s\" instead of \"%s\"", + node, p, checkpath); + + p = fdt_getprop(fdt, node, "lref", &len); + if (!p) + FAIL("fdt_getprop(%d, \"lref\"): %s", node, fdt_strerror(len)); + if (!streq(p, checkpath)) + FAIL("'lref' in node at %d has value \"%s\" instead of \"%s\"", + node, p, checkpath); +} + +int main(int argc, char *argv[]) +{ + void *fdt; + const char *p; + int len, multilen; + int n1, n2; + + test_init(argc, argv); + fdt = load_blob_arg(argc, argv); + + n1 = fdt_path_offset(fdt, "/node1"); + if (n1 < 0) + FAIL("fdt_path_offset(/node1): %s", fdt_strerror(n1)); + n2 = fdt_path_offset(fdt, "/node2"); + if (n2 < 0) + FAIL("fdt_path_offset(/node2): %s", fdt_strerror(n2)); + + check_ref(fdt, n1, "/node2"); + check_ref(fdt, n2, "/node1"); + + /* Check multiple reference */ + multilen = strlen("/node1") + strlen("/node2") + 2; + p = fdt_getprop(fdt, 0, "multiref", &len); + if (!p) + FAIL("fdt_getprop(0, \"multiref\"): %s", fdt_strerror(len)); + if (len != multilen) + FAIL("multiref has wrong length, %d instead of %d", + len, multilen); + if ((!streq(p, "/node1") || !streq(p + strlen("/node1") + 1, "/node2"))) + FAIL("multiref has wrong value"); + + PASS(); +} diff --git a/tests/path-references.dts b/tests/path-references.dts new file mode 100644 index 0000000..91e7ef7 --- /dev/null +++ b/tests/path-references.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +/ { + /* Check multiple references case */ + multiref = &n1 , &n2; + n1: node1 { + ref = &{/node2}; /* reference precedes target */ + lref = &n2; + }; + n2: node2 { + ref = &{/node1}; /* reference after target */ + lref = &n1; + }; +}; diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 9d32337..4a70b4a 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -147,6 +147,9 @@ dtc_tests () { run_test dtc.sh -I dts -O dtb -o dtc_references_dts0.test.dtb references_dts0.dts run_test references dtc_references_dts0.test.dtb + run_test dtc.sh -I dts -O dtb -o dtc_path-references.test.dtb path-references.dts + run_test path-references dtc_path-references.test.dtb + # Check -Odts mode preserve all dtb information for tree in test_tree1.dtb dtc_tree1.test.dtb dtc_escapes.test.dtb ; do run_test dtc.sh -I dtb -O dts -o odts_$tree.test.dts $tree