From 0638bac388b68c88d10d265aca60f913a56b0eac Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 27 May 2018 09:36:28 +0000 Subject: [PATCH] Add barebox overlay support --- .../init/{fix-devicetree => dt-sdcard} | 0 ...drivers-of-implement-overlay-support.patch | 429 + ...dtc-Update-to-upstream-version-1.4.6.patch | 9483 +++++++++++++++++ 3 files changed, 9912 insertions(+) rename buildroot-external/board/rpi2/barebox-env/init/{fix-devicetree => dt-sdcard} (100%) create mode 100644 buildroot-external/patches/barebox/0001-drivers-of-implement-overlay-support.patch create mode 100644 buildroot-external/patches/barebox/0002-scripts-dtc-Update-to-upstream-version-1.4.6.patch diff --git a/buildroot-external/board/rpi2/barebox-env/init/fix-devicetree b/buildroot-external/board/rpi2/barebox-env/init/dt-sdcard similarity index 100% rename from buildroot-external/board/rpi2/barebox-env/init/fix-devicetree rename to buildroot-external/board/rpi2/barebox-env/init/dt-sdcard diff --git a/buildroot-external/patches/barebox/0001-drivers-of-implement-overlay-support.patch b/buildroot-external/patches/barebox/0001-drivers-of-implement-overlay-support.patch new file mode 100644 index 000000000..3dd6fb4b4 --- /dev/null +++ b/buildroot-external/patches/barebox/0001-drivers-of-implement-overlay-support.patch @@ -0,0 +1,429 @@ +From 059762285f200a6e2527a4447d35f34d66b07bc2 Mon Sep 17 00:00:00 2001 +From: Pascal Vizeli +Date: Sun, 27 May 2018 09:33:20 +0000 +Subject: [PATCH 1/2] drivers: of: implement overlay support + +Signed-off-by: Pascal Vizeli +--- + Documentation/user/devicetree.rst | 101 +++++++++++++++++++++++++++++- + arch/sandbox/dts/Makefile | 5 +- + arch/sandbox/dts/sandbox.dts | 6 ++ + commands/oftree.c | 65 +++++++++++++++++-- + drivers/of/Kconfig | 6 ++ + drivers/of/Makefile | 1 + + include/of.h | 71 +++++++++++++++++++++ + scripts/Makefile.lib | 5 +- + 8 files changed, 251 insertions(+), 9 deletions(-) + +diff --git a/Documentation/user/devicetree.rst b/Documentation/user/devicetree.rst +index 17934d86e..b2220997d 100644 +--- a/Documentation/user/devicetree.rst ++++ b/Documentation/user/devicetree.rst +@@ -21,7 +21,7 @@ The internal devicetree + ----------------------- + + The devicetree consulted by barebox plays a special role. It is referred to +-as the "internal devicetree." The barebox devicetree commands work on this ++as the "internal devicetree". The barebox devicetree commands work on this + devicetree. The devicetree source (DTS) files are kept in sync with the kernel DTS + files. As the FDT files are meant to be backward compatible, it should always be possible + to start a kernel with the barebox internal devicetree. However, since the barebox +@@ -83,3 +83,102 @@ you can exchange the internal devicetree during runtime using the + + oftree -f + oftree -l /new/dtb ++ ++Devicetree overlays ++------------------- ++ ++Since version 3.19, the Linux kernel supports applying "devicetree overlays" to ++its loaded device tree. This can be used to inform the kernel about additional ++non-discoverable devices after the system has booted, which is useful for modular ++boards and FPGAs. The details of the overlay format are specified in the Linux ++`kernel documentation `_ ++and an updated DTC is required to compile the overlays. ++ ++The use cases for overlays in barebox are a bit different: ++ ++* some of the modular devices are needed to boot Linux to userspace, but barebox ++ can detect which module variant is connected ++* one of several parallel or LVDS displays (which use timing data from devicetree) ++ can be connected to the SoC and should be used for boot messages ++* a generic Linux (distribution) kernel should be booted on a modular ++ system and support additional hardware on modules ++ ++barebox supports applying overlays in the internal devicetree was well using the ++:ref:`command_oftree` command with option ``-o``: ++ ++.. code-block:: sh ++ ++ $ ./barebox -d arch/sandbox/dts/sandbox.dtb -i arch/sandbox/dts/sandbox-overlay.dtbo ++ add fd0 backed by file arch/sandbox/dts/sandbox-overlay.dtbo ++ ++ barebox 2015.02.0 #26 Wed Mar 4 09:41:19 CET 2015 ++ ... ++ barebox@barebox sandbox:/ of_dump ++ ... ++ dummy@0 { ++ status = "disabled"; ++ linux,phandle = <0x1>; ++ phandle = <0x1>; ++ }; ++ dummy@1 { ++ status = "disabled"; ++ linux,phandle = <0x2>; ++ phandle = <0x2>; ++ }; ++ __symbols__ { ++ dummy0 = "/dummy@0"; ++ dummy1 = "/dummy@1"; ++ }; ++ ... ++ barebox@barebox sandbox:/ of_dump -f /dev/fd0 ++ { ++ fragment@0 { ++ target = <0xdeadbeef>; ++ __overlay__ { ++ status = "okay"; ++ child { ++ compatible = "barebox,dummy"; ++ }; ++ }; ++ }; ++ fragment@1 { ++ target = <0xdeadbeef>; ++ __overlay__ { ++ status = "okay"; ++ child { ++ compatible = "barebox,dummy"; ++ }; ++ }; ++ }; ++ __fixups__ { ++ dummy0 = "/fragment@0:target:0"; ++ dummy1 = "/fragment@1:target:0"; ++ }; ++ }; ++ barebox@barebox sandbox:/ oftree -o /dev/fd0 ++ barebox@barebox sandbox:/ of_dump ++ ... ++ dummy@0 { ++ linux,phandle = <0x1>; ++ phandle = <0x1>; ++ status = "okay"; ++ child { ++ compatible = "barebox,dummy"; ++ }; ++ }; ++ dummy@1 { ++ linux,phandle = <0x2>; ++ phandle = <0x2>; ++ status = "okay"; ++ child { ++ compatible = "barebox,dummy"; ++ }; ++ }; ++ __symbols__ { ++ dummy0 = "/dummy@0"; ++ dummy1 = "/dummy@1"; ++ }; ++ ... ++ ++If you need to use a different base devicetree instead of the one compiled into ++barebox, it needs to be replaced as described in the previous section. +diff --git a/arch/sandbox/dts/Makefile b/arch/sandbox/dts/Makefile +index 6f6838857..ede219e6f 100644 +--- a/arch/sandbox/dts/Makefile ++++ b/arch/sandbox/dts/Makefile +@@ -1,6 +1,7 @@ + ifeq ($(CONFIG_OFTREE),y) + dtb-y += \ +- sandbox.dtb ++ sandbox.dtb \ ++ sandbox-overlay.dtbo + endif + + # just to build a built-in.o. Otherwise compilation fails when no devicetree is +@@ -8,4 +9,4 @@ endif + obj- += dummy.o + + always := $(dtb-y) +-clean-files := *.dtb *.dtb.S .*.dtc .*.pre .*.dts ++clean-files := *.dtb *.dtb.S .*.dtc .*.pre .*.dts *.dtbo +diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts +index 2595aa13f..1b99a4960 100644 +--- a/arch/sandbox/dts/sandbox.dts ++++ b/arch/sandbox/dts/sandbox.dts +@@ -3,5 +3,11 @@ + #include "skeleton.dtsi" + + / { ++ dummy0: dummy@0 { ++ status = "disabled"; ++ }; + ++ dummy1: dummy@1 { ++ status = "disabled"; ++ }; + }; +diff --git a/commands/oftree.c b/commands/oftree.c +index 8a47c0be5..e0624ad34 100644 +--- a/commands/oftree.c ++++ b/commands/oftree.c +@@ -2,6 +2,7 @@ + * oftree.c - device tree command support + * + * Copyright (c) 2011 Sascha Hauer , Pengutronix ++ * Copyright (C) 2015 Pengutronix, Jan Luebbe + * + * based on U-Boot code by: + * +@@ -48,11 +49,14 @@ static int do_oftree(int argc, char *argv[]) + int probe = 0; + char *load = NULL; + char *save = NULL; ++ char *overlay = NULL; + int free_of = 0; + int ret; + struct device_node *root; ++ int ovinfo_cnt; ++ struct of_overlay_info *ovinfo; + +- while ((opt = getopt(argc, argv, "pfl:s:")) > 0) { ++ while ((opt = getopt(argc, argv, "pfl:o:s:")) > 0) { + switch (opt) { + case 'l': + load = optarg; +@@ -68,6 +72,9 @@ static int do_oftree(int argc, char *argv[]) + case 'f': + free_of = 1; + break; ++ case 'o': ++ overlay = optarg; ++ break; + case 's': + save = optarg; + break; +@@ -84,7 +91,7 @@ static int do_oftree(int argc, char *argv[]) + return 0; + } + +- if (!probe && !load && !save) ++ if (!probe && !load && !save && !overlay) + return COMMAND_ERROR_USAGE; + + if (save) { +@@ -123,6 +130,53 @@ static int do_oftree(int argc, char *argv[]) + } + } + ++ if (IS_ENABLED(CONFIG_OFTREE_OVERLAY) && overlay) { ++ struct device_node *ov; ++ ++ root = of_get_root_node(); ++ if (!root) { ++ printf("no oftree loaded\n"); ++ goto out; ++ } ++ ++ fdt = read_file(overlay, &size); ++ if (!fdt) { ++ printf("unable to read %s\n", overlay); ++ return 1; ++ } ++ ++ ov = of_unflatten_dtb(fdt); ++ free(fdt); ++ ++ if (IS_ERR(ov)) { ++ printf("parse oftree: %s\n", strerror(-ret)); ++ return PTR_ERR(ov); ++ } ++ ++ ret = of_resolve(ov); ++ if (ret) { ++ printf("resolve oftree overlay: %s\n", strerror(-ret)); ++ of_delete_node(ov); ++ goto out; ++ } ++ ++ ret = of_build_overlay_info(ov, &ovinfo_cnt, &ovinfo); ++ if (ret) { ++ printf("prepare oftree overlay: %s\n", strerror(-ret)); ++ of_delete_node(ov); ++ goto out; ++ } ++ ++ ret = of_overlay(ovinfo_cnt, ovinfo); ++ if (ret) { ++ printf("apply oftree overlay: %s\n", strerror(-ret)); ++ of_delete_node(ov); ++ goto out; ++ } ++ ++ of_delete_node(ov); ++ } ++ + if (probe) { + ret = of_probe(); + if (ret) +@@ -137,8 +191,9 @@ out: + + BAREBOX_CMD_HELP_START(oftree) + BAREBOX_CMD_HELP_TEXT("Options:") +-BAREBOX_CMD_HELP_OPT ("-l ", "Load to internal devicetree\n") +-BAREBOX_CMD_HELP_OPT ("-s ", "save internal devicetree to \n") ++BAREBOX_CMD_HELP_OPT ("-l ", "load to internal devicetree") ++BAREBOX_CMD_HELP_OPT ("-s ", "save internal devicetree to ") ++BAREBOX_CMD_HELP_OPT ("-o ", "apply overlay to internal devicetree") + BAREBOX_CMD_HELP_OPT ("-p", "probe devices from stored device tree") + BAREBOX_CMD_HELP_OPT ("-f", "free stored device tree") + BAREBOX_CMD_HELP_END +@@ -146,7 +201,7 @@ BAREBOX_CMD_HELP_END + BAREBOX_CMD_START(oftree) + .cmd = do_oftree, + BAREBOX_CMD_DESC("handle device trees") +- BAREBOX_CMD_OPTS("[-lspf]") ++ BAREBOX_CMD_OPTS("[-lsopf]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_HELP(cmd_oftree_help) + BAREBOX_CMD_END +diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig +index a1fac0e61..d90bd9c6b 100644 +--- a/drivers/of/Kconfig ++++ b/drivers/of/Kconfig +@@ -15,6 +15,12 @@ config OFDEVICE + select DTC + bool "Enable probing of devices from the devicetree" + ++config OFTREE_OVERLAY ++ bool "Enable support for devicetree overlays" ++ depends on OFTREE ++ help ++ Allows you to modify the live tree using overlays. ++ + config OF_ADDRESS_PCI + bool + +diff --git a/drivers/of/Makefile b/drivers/of/Makefile +index ec4387006..323543461 100644 +--- a/drivers/of/Makefile ++++ b/drivers/of/Makefile +@@ -6,3 +6,4 @@ obj-y += partition.o + obj-y += of_net.o + obj-$(CONFIG_MTD) += of_mtd.o + obj-$(CONFIG_OF_BAREBOX_DRIVERS) += barebox.o ++obj-$(CONFIG_OFTREE_OVERLAY) += resolver.o overlay.o +diff --git a/include/of.h b/include/of.h +index fec51bb94..91476ae47 100644 +--- a/include/of.h ++++ b/include/of.h +@@ -730,6 +730,8 @@ static inline struct device_node *of_find_matching_node( + #define for_each_available_child_of_node(parent, child) \ + for (child = of_get_next_available_child(parent, NULL); child != NULL; \ + child = of_get_next_available_child(parent, child)) ++#define for_each_property_of_node(dn, pp) \ ++ list_for_each_entry(pp, &dn->properties, list) + + /** + * of_property_read_bool - Findfrom a property +@@ -850,4 +852,73 @@ static inline struct device_node *of_find_root_node(struct device_node *node) + + return node; + } ++ ++/* illegal phandle value (set when unresolved) */ ++#define OF_PHANDLE_ILLEGAL 0xdeadbeef ++ ++#ifdef CONFIG_OFTREE_OVERLAY ++ ++extern int of_resolve(struct device_node *resolve); ++ ++#else ++ ++static inline int of_resolve(struct device_node *resolve) ++{ ++ return -ENOSYS; ++} ++ ++#endif ++ ++/** ++ * Overlay support ++ */ ++ ++/** ++ * struct of_overlay_info - Holds a single overlay info ++ * @target: target of the overlay operation ++ * @overlay: pointer to the overlay contents node ++ * ++ * Holds a single overlay state. ++ */ ++struct of_overlay_info { ++ struct device_node *target; ++ struct device_node *overlay; ++}; ++ ++#ifdef CONFIG_OFTREE_OVERLAY ++ ++extern int of_overlay(int count, struct of_overlay_info *ovinfo_tab); ++ ++extern int of_fill_overlay_info(struct device_node *info_node, ++ struct of_overlay_info *ovinfo); ++extern int of_build_overlay_info(struct device_node *tree, ++ int *cntp, struct of_overlay_info **ovinfop); ++extern int of_free_overlay_info(int cnt, struct of_overlay_info *ovinfo); ++ ++#else ++ ++static inline int of_overlay(int count, struct of_overlay_info *ovinfo_tab) ++{ ++ return -ENOSYS; ++} ++ ++static inline int of_fill_overlay_info(struct device_node *info_node, ++ struct of_overlay_info *ovinfo) ++{ ++ return -ENOSYS; ++} ++ ++static inline int of_build_overlay_info(struct device_node *tree, ++ int *cntp, struct of_overlay_info **ovinfop) ++{ ++ return -ENOSYS; ++} ++ ++static inline int of_free_overlay_info(int cnt, struct of_overlay_info *ovinfo) ++{ ++ return -ENOSYS; ++} ++ ++#endif ++ + #endif /* __OF_H */ +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index 272b5981e..e7cea55c4 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -261,7 +261,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb $(srctree)/scripts/gen-dtb-s FORCE + + quiet_cmd_dtc = DTC $@ + cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ +- $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \ ++ $(objtree)/scripts/dtc/dtc -@ -O dtb -o $@ -b 0 \ + -i $(srctree)/arch/$(SRCARCH)/dts $(DTC_FLAGS) \ + -i $(srctree)/dts/src/$(SRCARCH) \ + -d $(depfile).dtc $(dtc-tmp) ; \ +@@ -270,6 +270,9 @@ cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ + $(obj)/%.dtb: $(src)/%.dts FORCE + $(call if_changed_dep,dtc) + ++$(obj)/%.dtbo: $(src)/%.dtso FORCE ++ $(call if_changed_dep,dtc) ++ + dtc-tmp = $(subst $(comma),_,$(dot-target).dts) + + obj-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).o,$(bbenv-y)) +-- +2.17.0 + diff --git a/buildroot-external/patches/barebox/0002-scripts-dtc-Update-to-upstream-version-1.4.6.patch b/buildroot-external/patches/barebox/0002-scripts-dtc-Update-to-upstream-version-1.4.6.patch new file mode 100644 index 000000000..2635cc8ee --- /dev/null +++ b/buildroot-external/patches/barebox/0002-scripts-dtc-Update-to-upstream-version-1.4.6.patch @@ -0,0 +1,9483 @@ +From b283776d26027ce237276f57e4522f5d0b6aab3f Mon Sep 17 00:00:00 2001 +From: Pascal Vizeli +Date: Sun, 27 May 2018 09:34:21 +0000 +Subject: [PATCH 2/2] scripts/dtc: Update to upstream version 1.4.6 + +Signed-off-by: Pascal Vizeli +--- + scripts/dtc/.gitignore | 1 - + scripts/dtc/Makefile | 8 +- + scripts/dtc/checks.c | 1194 +++++++++++++++++++++----- + scripts/dtc/data.c | 16 +- + scripts/dtc/dtc-lexer.l | 63 +- + scripts/dtc/dtc-lexer.lex.c_shipped | 894 +++++++++---------- + scripts/dtc/dtc-parser.tab.c_shipped | 813 ++++++++++-------- + scripts/dtc/dtc-parser.tab.h_shipped | 54 +- + scripts/dtc/dtc-parser.y | 91 +- + scripts/dtc/dtc.c | 139 ++- + scripts/dtc/dtc.h | 62 +- + scripts/dtc/fdt.c | 24 +- + scripts/dtc/fdt.h | 6 +- + scripts/dtc/fdt_empty_tree.c | 1 - + scripts/dtc/fdt_ro.c | 288 ++++++- + scripts/dtc/fdt_rw.c | 121 +-- + scripts/dtc/fdt_strerror.c | 6 + + scripts/dtc/fdt_sw.c | 40 +- + scripts/dtc/fdt_wip.c | 43 +- + scripts/dtc/fdtdump.c | 136 +-- + scripts/dtc/fdtget.c | 60 +- + scripts/dtc/fdtput.c | 142 ++- + scripts/dtc/flattree.c | 105 +-- + scripts/dtc/fstree.c | 5 +- + scripts/dtc/libfdt.h | 429 +++++++-- + scripts/dtc/libfdt_env.h | 60 +- + scripts/dtc/libfdt_internal.h | 32 +- + scripts/dtc/livetree.c | 356 +++++++- + scripts/dtc/srcpos.c | 42 +- + scripts/dtc/srcpos.h | 18 +- + scripts/dtc/treesource.c | 20 +- + scripts/dtc/update-dtc-source.sh | 46 +- + scripts/dtc/util.c | 44 +- + scripts/dtc/util.h | 33 +- + scripts/dtc/version_gen.h | 2 +- + 35 files changed, 3666 insertions(+), 1728 deletions(-) + +diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore +index 80f6b50fd..cdabdc95a 100644 +--- a/scripts/dtc/.gitignore ++++ b/scripts/dtc/.gitignore +@@ -2,4 +2,3 @@ dtc + dtc-lexer.lex.c + dtc-parser.tab.c + dtc-parser.tab.h +-fdtget +diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile +index 05973b12a..06aaa8c55 100644 +--- a/scripts/dtc/Makefile ++++ b/scripts/dtc/Makefile +@@ -1,17 +1,15 @@ + # scripts/dtc makefile + +-hostprogs-y := dtc fdtget ++hostprogs-y := dtc + always := $(hostprogs-y) + + dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ + srcpos.o checks.o util.o + dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o + +-libfdt-objs = fdt.o fdt_ro.o fdt_strerror.o fdt_wip.o ++libfdt-objs = fdt.o fdt_ro.o fdt_strerror.o fdt_wip.o fdt_overlay.o + libfdt-objs += fdt_empty_tree.o fdt_rw.o fdt_sw.o + +-fdtget-objs += fdtget.o $(libfdt-objs) util.o +- + # Source files need to get at the userspace version of libfdt_env.h to compile + + HOSTCFLAGS_DTC := -I$(src) +@@ -33,7 +31,7 @@ HOSTCFLAGS_fdt_wip.o := $(HOSTCFLAGS_DTC) + HOSTCFLAGS_fdt_empty_tree.o := $(HOSTCFLAGS_DTC) + HOSTCFLAGS_fdt_rw.o := $(HOSTCFLAGS_DTC) + HOSTCFLAGS_fdt_sw.o := $(HOSTCFLAGS_DTC) +-HOSTCFLAGS_fdtget.o := $(HOSTCFLAGS_DTC) ++HOSTCFLAGS_fdt_overlay.o := $(HOSTCFLAGS_DTC) + + HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC) + HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC) +diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c +index 3bf0fa4a4..815eaf140 100644 +--- a/scripts/dtc/checks.c ++++ b/scripts/dtc/checks.c +@@ -40,16 +40,11 @@ enum checkstatus { + + struct check; + +-typedef void (*tree_check_fn)(struct check *c, struct node *dt); +-typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); +-typedef void (*prop_check_fn)(struct check *c, struct node *dt, +- struct node *node, struct property *prop); ++typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node); + + struct check { + const char *name; +- tree_check_fn tree_fn; +- node_check_fn node_fn; +- prop_check_fn prop_fn; ++ check_fn fn; + void *data; + bool warn, error; + enum checkstatus status; +@@ -58,91 +53,80 @@ struct check { + struct check **prereq; + }; + +-#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ +- static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ +- static struct check nm = { \ +- .name = #nm, \ +- .tree_fn = (tfn), \ +- .node_fn = (nfn), \ +- .prop_fn = (pfn), \ +- .data = (d), \ +- .warn = (w), \ +- .error = (e), \ ++#define CHECK_ENTRY(nm_, fn_, d_, w_, e_, ...) \ ++ static struct check *nm_##_prereqs[] = { __VA_ARGS__ }; \ ++ static struct check nm_ = { \ ++ .name = #nm_, \ ++ .fn = (fn_), \ ++ .data = (d_), \ ++ .warn = (w_), \ ++ .error = (e_), \ + .status = UNCHECKED, \ +- .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ +- .prereq = nm##_prereqs, \ ++ .num_prereqs = ARRAY_SIZE(nm_##_prereqs), \ ++ .prereq = nm_##_prereqs, \ + }; +-#define WARNING(nm, tfn, nfn, pfn, d, ...) \ +- CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__) +-#define ERROR(nm, tfn, nfn, pfn, d, ...) \ +- CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__) +-#define CHECK(nm, tfn, nfn, pfn, d, ...) \ +- CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__) +- +-#define TREE_WARNING(nm, d, ...) \ +- WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) +-#define TREE_ERROR(nm, d, ...) \ +- ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) +-#define TREE_CHECK(nm, d, ...) \ +- CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) +-#define NODE_WARNING(nm, d, ...) \ +- WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) +-#define NODE_ERROR(nm, d, ...) \ +- ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) +-#define NODE_CHECK(nm, d, ...) \ +- CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) +-#define PROP_WARNING(nm, d, ...) \ +- WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) +-#define PROP_ERROR(nm, d, ...) \ +- ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) +-#define PROP_CHECK(nm, d, ...) \ +- CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) +- +-#ifdef __GNUC__ +-static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); +-#endif +-static inline void check_msg(struct check *c, const char *fmt, ...) ++#define WARNING(nm_, fn_, d_, ...) \ ++ CHECK_ENTRY(nm_, fn_, d_, true, false, __VA_ARGS__) ++#define ERROR(nm_, fn_, d_, ...) \ ++ CHECK_ENTRY(nm_, fn_, d_, false, true, __VA_ARGS__) ++#define CHECK(nm_, fn_, d_, ...) \ ++ CHECK_ENTRY(nm_, fn_, d_, false, false, __VA_ARGS__) ++ ++static inline void PRINTF(5, 6) check_msg(struct check *c, struct dt_info *dti, ++ struct node *node, ++ struct property *prop, ++ const char *fmt, ...) + { + va_list ap; + va_start(ap, fmt); + + if ((c->warn && (quiet < 1)) + || (c->error && (quiet < 2))) { +- fprintf(stderr, "%s (%s): ", ++ fprintf(stderr, "%s: %s (%s): ", ++ strcmp(dti->outname, "-") ? dti->outname : "", + (c->error) ? "ERROR" : "Warning", c->name); ++ if (node) { ++ fprintf(stderr, "%s", node->fullpath); ++ if (prop) ++ fprintf(stderr, ":%s", prop->name); ++ fputs(": ", stderr); ++ } + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } ++ va_end(ap); + } + +-#define FAIL(c, ...) \ +- do { \ +- TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ +- (c)->status = FAILED; \ +- check_msg((c), __VA_ARGS__); \ ++#define FAIL(c, dti, node, ...) \ ++ do { \ ++ TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ ++ (c)->status = FAILED; \ ++ check_msg((c), dti, node, NULL, __VA_ARGS__); \ + } while (0) + +-static void check_nodes_props(struct check *c, struct node *dt, struct node *node) ++#define FAIL_PROP(c, dti, node, prop, ...) \ ++ do { \ ++ TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ ++ (c)->status = FAILED; \ ++ check_msg((c), dti, node, prop, __VA_ARGS__); \ ++ } while (0) ++ ++ ++static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node) + { + struct node *child; +- struct property *prop; + + TRACE(c, "%s", node->fullpath); +- if (c->node_fn) +- c->node_fn(c, dt, node); +- +- if (c->prop_fn) +- for_each_property(node, prop) { +- TRACE(c, "%s\t'%s'", node->fullpath, prop->name); +- c->prop_fn(c, dt, node, prop); +- } ++ if (c->fn) ++ c->fn(c, dti, node); + + for_each_child(node, child) +- check_nodes_props(c, dt, child); ++ check_nodes_props(c, dti, child); + } + +-static bool run_check(struct check *c, struct node *dt) ++static bool run_check(struct check *c, struct dt_info *dti) + { ++ struct node *dt = dti->dt; + bool error = false; + int i; + +@@ -155,10 +139,10 @@ static bool run_check(struct check *c, struct node *dt) + + for (i = 0; i < c->num_prereqs; i++) { + struct check *prq = c->prereq[i]; +- error = error || run_check(prq, dt); ++ error = error || run_check(prq, dti); + if (prq->status != PASSED) { + c->status = PREREQ; +- check_msg(c, "Failed prerequisite '%s'", ++ check_msg(c, dti, NULL, NULL, "Failed prerequisite '%s'", + c->prereq[i]->name); + } + } +@@ -166,11 +150,8 @@ static bool run_check(struct check *c, struct node *dt) + if (c->status != UNCHECKED) + goto out; + +- if (c->node_fn || c->prop_fn) +- check_nodes_props(c, dt, dt); ++ check_nodes_props(c, dti, dt); + +- if (c->tree_fn) +- c->tree_fn(c, dt); + if (c->status == UNCHECKED) + c->status = PASSED; + +@@ -188,13 +169,14 @@ out: + */ + + /* A check which always fails, for testing purposes only */ +-static inline void check_always_fail(struct check *c, struct node *dt) ++static inline void check_always_fail(struct check *c, struct dt_info *dti, ++ struct node *node) + { +- FAIL(c, "always_fail check"); ++ FAIL(c, dti, node, "always_fail check"); + } +-TREE_CHECK(always_fail, NULL); ++CHECK(always_fail, check_always_fail, NULL); + +-static void check_is_string(struct check *c, struct node *root, ++static void check_is_string(struct check *c, struct dt_info *dti, + struct node *node) + { + struct property *prop; +@@ -205,15 +187,43 @@ static void check_is_string(struct check *c, struct node *root, + return; /* Not present, assumed ok */ + + if (!data_is_one_string(prop->val)) +- FAIL(c, "\"%s\" property in %s is not a string", +- propname, node->fullpath); ++ FAIL_PROP(c, dti, node, prop, "property is not a string"); + } + #define WARNING_IF_NOT_STRING(nm, propname) \ +- WARNING(nm, NULL, check_is_string, NULL, (propname)) ++ WARNING(nm, check_is_string, (propname)) + #define ERROR_IF_NOT_STRING(nm, propname) \ +- ERROR(nm, NULL, check_is_string, NULL, (propname)) ++ ERROR(nm, check_is_string, (propname)) ++ ++static void check_is_string_list(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ int rem, l; ++ struct property *prop; ++ char *propname = c->data; ++ char *str; ++ ++ prop = get_property(node, propname); ++ if (!prop) ++ return; /* Not present, assumed ok */ ++ ++ str = prop->val.val; ++ rem = prop->val.len; ++ while (rem > 0) { ++ l = strnlen(str, rem); ++ if (l == rem) { ++ FAIL_PROP(c, dti, node, prop, "property is not a string list"); ++ break; ++ } ++ rem -= l + 1; ++ str += l + 1; ++ } ++} ++#define WARNING_IF_NOT_STRING_LIST(nm, propname) \ ++ WARNING(nm, check_is_string_list, (propname)) ++#define ERROR_IF_NOT_STRING_LIST(nm, propname) \ ++ ERROR(nm, check_is_string_list, (propname)) + +-static void check_is_cell(struct check *c, struct node *root, ++static void check_is_cell(struct check *c, struct dt_info *dti, + struct node *node) + { + struct property *prop; +@@ -224,19 +234,18 @@ static void check_is_cell(struct check *c, struct node *root, + return; /* Not present, assumed ok */ + + if (prop->val.len != sizeof(cell_t)) +- FAIL(c, "\"%s\" property in %s is not a single cell", +- propname, node->fullpath); ++ FAIL_PROP(c, dti, node, prop, "property is not a single cell"); + } + #define WARNING_IF_NOT_CELL(nm, propname) \ +- WARNING(nm, NULL, check_is_cell, NULL, (propname)) ++ WARNING(nm, check_is_cell, (propname)) + #define ERROR_IF_NOT_CELL(nm, propname) \ +- ERROR(nm, NULL, check_is_cell, NULL, (propname)) ++ ERROR(nm, check_is_cell, (propname)) + + /* + * Structural check functions + */ + +-static void check_duplicate_node_names(struct check *c, struct node *dt, ++static void check_duplicate_node_names(struct check *c, struct dt_info *dti, + struct node *node) + { + struct node *child, *child2; +@@ -246,12 +255,11 @@ static void check_duplicate_node_names(struct check *c, struct node *dt, + child2; + child2 = child2->next_sibling) + if (streq(child->name, child2->name)) +- FAIL(c, "Duplicate node name %s", +- child->fullpath); ++ FAIL(c, dti, node, "Duplicate node name"); + } +-NODE_ERROR(duplicate_node_names, NULL); ++ERROR(duplicate_node_names, check_duplicate_node_names, NULL); + +-static void check_duplicate_property_names(struct check *c, struct node *dt, ++static void check_duplicate_property_names(struct check *c, struct dt_info *dti, + struct node *node) + { + struct property *prop, *prop2; +@@ -261,48 +269,116 @@ static void check_duplicate_property_names(struct check *c, struct node *dt, + if (prop2->deleted) + continue; + if (streq(prop->name, prop2->name)) +- FAIL(c, "Duplicate property name %s in %s", +- prop->name, node->fullpath); ++ FAIL_PROP(c, dti, node, prop, "Duplicate property name"); + } + } + } +-NODE_ERROR(duplicate_property_names, NULL); ++ERROR(duplicate_property_names, check_duplicate_property_names, NULL); + + #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" + #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + #define DIGITS "0123456789" + #define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" ++#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-" + +-static void check_node_name_chars(struct check *c, struct node *dt, ++static void check_node_name_chars(struct check *c, struct dt_info *dti, + struct node *node) + { + int n = strspn(node->name, c->data); + + if (n < strlen(node->name)) +- FAIL(c, "Bad character '%c' in node %s", +- node->name[n], node->fullpath); ++ FAIL(c, dti, node, "Bad character '%c' in node name", ++ node->name[n]); + } +-NODE_ERROR(node_name_chars, PROPNODECHARS "@"); ++ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); + +-static void check_node_name_format(struct check *c, struct node *dt, ++static void check_node_name_chars_strict(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ int n = strspn(node->name, c->data); ++ ++ if (n < node->basenamelen) ++ FAIL(c, dti, node, "Character '%c' not recommended in node name", ++ node->name[n]); ++} ++CHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT); ++ ++static void check_node_name_format(struct check *c, struct dt_info *dti, + struct node *node) + { + if (strchr(get_unitname(node), '@')) +- FAIL(c, "Node %s has multiple '@' characters in name", +- node->fullpath); ++ FAIL(c, dti, node, "multiple '@' characters in node name"); ++} ++ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); ++ ++static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ const char *unitname = get_unitname(node); ++ struct property *prop = get_property(node, "reg"); ++ ++ if (!prop) { ++ prop = get_property(node, "ranges"); ++ if (prop && !prop->val.len) ++ prop = NULL; ++ } ++ ++ if (prop) { ++ if (!unitname[0]) ++ FAIL(c, dti, node, "node has a reg or ranges property, but no unit name"); ++ } else { ++ if (unitname[0]) ++ FAIL(c, dti, node, "node has a unit name, but no reg property"); ++ } ++} ++WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); ++ ++static void check_property_name_chars(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ struct property *prop; ++ ++ for_each_property(node, prop) { ++ int n = strspn(prop->name, c->data); ++ ++ if (n < strlen(prop->name)) ++ FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name", ++ prop->name[n]); ++ } + } +-NODE_ERROR(node_name_format, NULL, &node_name_chars); ++ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); + +-static void check_property_name_chars(struct check *c, struct node *dt, +- struct node *node, struct property *prop) ++static void check_property_name_chars_strict(struct check *c, ++ struct dt_info *dti, ++ struct node *node) + { +- int n = strspn(prop->name, c->data); ++ struct property *prop; ++ ++ for_each_property(node, prop) { ++ const char *name = prop->name; ++ int n = strspn(name, c->data); + +- if (n < strlen(prop->name)) +- FAIL(c, "Bad character '%c' in property name \"%s\", node %s", +- prop->name[n], prop->name, node->fullpath); ++ if (n == strlen(prop->name)) ++ continue; ++ ++ /* Certain names are whitelisted */ ++ if (streq(name, "device_type")) ++ continue; ++ ++ /* ++ * # is only allowed at the beginning of property names not counting ++ * the vendor prefix. ++ */ ++ if (name[n] == '#' && ((n == 0) || (name[n-1] == ','))) { ++ name += n + 1; ++ n = strspn(name, c->data); ++ } ++ if (n < strlen(name)) ++ FAIL_PROP(c, dti, node, prop, "Character '%c' not recommended in property name", ++ name[n]); ++ } + } +-PROP_ERROR(property_name_chars, PROPNODECHARS); ++CHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT); + + #define DESCLABEL_FMT "%s%s%s%s%s" + #define DESCLABEL_ARGS(node,prop,mark) \ +@@ -311,10 +387,11 @@ PROP_ERROR(property_name_chars, PROPNODECHARS); + ((prop) ? (prop)->name : ""), \ + ((prop) ? "' in " : ""), (node)->fullpath + +-static void check_duplicate_label(struct check *c, struct node *dt, ++static void check_duplicate_label(struct check *c, struct dt_info *dti, + const char *label, struct node *node, + struct property *prop, struct marker *mark) + { ++ struct node *dt = dti->dt; + struct node *othernode = NULL; + struct property *otherprop = NULL; + struct marker *othermark = NULL; +@@ -331,50 +408,49 @@ static void check_duplicate_label(struct check *c, struct node *dt, + return; + + if ((othernode != node) || (otherprop != prop) || (othermark != mark)) +- FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT ++ FAIL(c, dti, node, "Duplicate label '%s' on " DESCLABEL_FMT + " and " DESCLABEL_FMT, + label, DESCLABEL_ARGS(node, prop, mark), + DESCLABEL_ARGS(othernode, otherprop, othermark)); + } + +-static void check_duplicate_label_node(struct check *c, struct node *dt, ++static void check_duplicate_label_node(struct check *c, struct dt_info *dti, + struct node *node) + { + struct label *l; ++ struct property *prop; + + for_each_label(node->labels, l) +- check_duplicate_label(c, dt, l->label, node, NULL, NULL); +-} +-static void check_duplicate_label_prop(struct check *c, struct node *dt, +- struct node *node, struct property *prop) +-{ +- struct marker *m = prop->val.markers; +- struct label *l; ++ check_duplicate_label(c, dti, l->label, node, NULL, NULL); ++ ++ for_each_property(node, prop) { ++ struct marker *m = prop->val.markers; + +- for_each_label(prop->labels, l) +- check_duplicate_label(c, dt, l->label, node, prop, NULL); ++ for_each_label(prop->labels, l) ++ check_duplicate_label(c, dti, l->label, node, prop, NULL); + +- for_each_marker_of_type(m, LABEL) +- check_duplicate_label(c, dt, m->ref, node, prop, m); ++ for_each_marker_of_type(m, LABEL) ++ check_duplicate_label(c, dti, m->ref, node, prop, m); ++ } + } +-ERROR(duplicate_label, NULL, check_duplicate_label_node, +- check_duplicate_label_prop, NULL); ++ERROR(duplicate_label, check_duplicate_label_node, NULL); + +-static void check_explicit_phandles(struct check *c, struct node *root, +- struct node *node, struct property *prop) ++static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, ++ struct node *node, const char *propname) + { ++ struct node *root = dti->dt; ++ struct property *prop; + struct marker *m; +- struct node *other; + cell_t phandle; + +- if (!streq(prop->name, "phandle") +- && !streq(prop->name, "linux,phandle")) +- return; ++ prop = get_property(node, propname); ++ if (!prop) ++ return 0; + + if (prop->val.len != sizeof(cell_t)) { +- FAIL(c, "%s has bad length (%d) %s property", +- node->fullpath, prop->val.len, prop->name); +- return; ++ FAIL_PROP(c, dti, node, prop, "bad length (%d) %s property", ++ prop->val.len, prop->name); ++ return 0; + } + + m = prop->val.markers; +@@ -384,42 +460,65 @@ static void check_explicit_phandles(struct check *c, struct node *root, + /* "Set this node's phandle equal to some + * other node's phandle". That's nonsensical + * by construction. */ { +- FAIL(c, "%s in %s is a reference to another node", +- prop->name, node->fullpath); +- return; ++ FAIL(c, dti, node, "%s is a reference to another node", ++ prop->name); + } + /* But setting this node's phandle equal to its own + * phandle is allowed - that means allocate a unique + * phandle for this node, even if it's not otherwise + * referenced. The value will be filled in later, so +- * no further checking for now. */ +- return; ++ * we treat it as having no phandle data for now. */ ++ return 0; + } + + phandle = propval_cell(prop); + + if ((phandle == 0) || (phandle == -1)) { +- FAIL(c, "%s has bad value (0x%x) in %s property", +- node->fullpath, phandle, prop->name); +- return; ++ FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property", ++ phandle, prop->name); ++ return 0; + } + +- if (node->phandle && (node->phandle != phandle)) +- FAIL(c, "%s has %s property which replaces existing phandle information", +- node->fullpath, prop->name); ++ return phandle; ++} ++ ++static void check_explicit_phandles(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ struct node *root = dti->dt; ++ struct node *other; ++ cell_t phandle, linux_phandle; ++ ++ /* Nothing should have assigned phandles yet */ ++ assert(!node->phandle); ++ ++ phandle = check_phandle_prop(c, dti, node, "phandle"); ++ ++ linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle"); ++ ++ if (!phandle && !linux_phandle) ++ /* No valid phandles; nothing further to check */ ++ return; ++ ++ if (linux_phandle && phandle && (phandle != linux_phandle)) ++ FAIL(c, dti, node, "mismatching 'phandle' and 'linux,phandle'" ++ " properties"); ++ ++ if (linux_phandle && !phandle) ++ phandle = linux_phandle; + + other = get_node_by_phandle(root, phandle); + if (other && (other != node)) { +- FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)", +- node->fullpath, phandle, other->fullpath); ++ FAIL(c, dti, node, "duplicated phandle 0x%x (seen before at %s)", ++ phandle, other->fullpath); + return; + } + + node->phandle = phandle; + } +-PROP_ERROR(explicit_phandles, NULL); ++ERROR(explicit_phandles, check_explicit_phandles, NULL); + +-static void check_name_properties(struct check *c, struct node *root, ++static void check_name_properties(struct check *c, struct dt_info *dti, + struct node *node) + { + struct property **pp, *prop = NULL; +@@ -435,8 +534,8 @@ static void check_name_properties(struct check *c, struct node *root, + + if ((prop->val.len != node->basenamelen+1) + || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { +- FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead" +- " of base node name)", node->fullpath, prop->val.val); ++ FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead" ++ " of base node name)", prop->val.val); + } else { + /* The name property is correct, and therefore redundant. + * Delete it */ +@@ -447,60 +546,73 @@ static void check_name_properties(struct check *c, struct node *root, + } + } + ERROR_IF_NOT_STRING(name_is_string, "name"); +-NODE_ERROR(name_properties, NULL, &name_is_string); ++ERROR(name_properties, check_name_properties, NULL, &name_is_string); + + /* + * Reference fixup functions + */ + +-static void fixup_phandle_references(struct check *c, struct node *dt, +- struct node *node, struct property *prop) ++static void fixup_phandle_references(struct check *c, struct dt_info *dti, ++ struct node *node) + { +- struct marker *m = prop->val.markers; +- struct node *refnode; +- cell_t phandle; ++ struct node *dt = dti->dt; ++ struct property *prop; + +- for_each_marker_of_type(m, REF_PHANDLE) { +- assert(m->offset + sizeof(cell_t) <= prop->val.len); ++ for_each_property(node, prop) { ++ struct marker *m = prop->val.markers; ++ struct node *refnode; ++ cell_t phandle; ++ ++ for_each_marker_of_type(m, REF_PHANDLE) { ++ assert(m->offset + sizeof(cell_t) <= prop->val.len); ++ ++ refnode = get_node_by_ref(dt, m->ref); ++ if (! refnode) { ++ if (!(dti->dtsflags & DTSF_PLUGIN)) ++ FAIL(c, dti, node, "Reference to non-existent node or " ++ "label \"%s\"\n", m->ref); ++ else /* mark the entry as unresolved */ ++ *((fdt32_t *)(prop->val.val + m->offset)) = ++ cpu_to_fdt32(0xffffffff); ++ continue; ++ } + +- refnode = get_node_by_ref(dt, m->ref); +- if (! refnode) { +- FAIL(c, "Reference to non-existent node or label \"%s\"\n", +- m->ref); +- continue; ++ phandle = get_node_phandle(dt, refnode); ++ *((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); + } +- +- phandle = get_node_phandle(dt, refnode); +- *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); + } + } +-ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ++ERROR(phandle_references, fixup_phandle_references, NULL, + &duplicate_node_names, &explicit_phandles); + +-static void fixup_path_references(struct check *c, struct node *dt, +- struct node *node, struct property *prop) ++static void fixup_path_references(struct check *c, struct dt_info *dti, ++ struct node *node) + { +- struct marker *m = prop->val.markers; +- struct node *refnode; +- char *path; ++ struct node *dt = dti->dt; ++ struct property *prop; + +- for_each_marker_of_type(m, REF_PATH) { +- assert(m->offset <= prop->val.len); ++ for_each_property(node, prop) { ++ struct marker *m = prop->val.markers; ++ struct node *refnode; ++ char *path; + +- refnode = get_node_by_ref(dt, m->ref); +- if (!refnode) { +- FAIL(c, "Reference to non-existent node or label \"%s\"\n", +- m->ref); +- continue; +- } ++ for_each_marker_of_type(m, REF_PATH) { ++ assert(m->offset <= prop->val.len); + +- path = refnode->fullpath; +- prop->val = data_insert_at_marker(prop->val, m, path, +- strlen(path) + 1); ++ refnode = get_node_by_ref(dt, m->ref); ++ if (!refnode) { ++ FAIL(c, dti, node, "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); ++ } + } + } +-ERROR(path_references, NULL, NULL, fixup_path_references, NULL, +- &duplicate_node_names); ++ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names); + + /* + * Semantic checks +@@ -512,8 +624,47 @@ WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); + WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); + WARNING_IF_NOT_STRING(model_is_string, "model"); + WARNING_IF_NOT_STRING(status_is_string, "status"); ++WARNING_IF_NOT_STRING(label_is_string, "label"); ++ ++WARNING_IF_NOT_STRING_LIST(compatible_is_string_list, "compatible"); ++ ++static void check_names_is_string_list(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ struct property *prop; ++ ++ for_each_property(node, prop) { ++ const char *s = strrchr(prop->name, '-'); ++ if (!s || !streq(s, "-names")) ++ continue; ++ ++ c->data = prop->name; ++ check_is_string_list(c, dti, node); ++ } ++} ++WARNING(names_is_string_list, check_names_is_string_list, NULL); ++ ++static void check_alias_paths(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ struct property *prop; + +-static void fixup_addr_size_cells(struct check *c, struct node *dt, ++ if (!streq(node->name, "aliases")) ++ return; ++ ++ for_each_property(node, prop) { ++ if (!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)", ++ prop->val.val); ++ continue; ++ } ++ if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name)) ++ FAIL(c, dti, node, "aliases property name must include only lowercase and '-'"); ++ } ++} ++WARNING(alias_paths, check_alias_paths, NULL); ++ ++static void fixup_addr_size_cells(struct check *c, struct dt_info *dti, + struct node *node) + { + struct property *prop; +@@ -529,7 +680,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt, + if (prop) + node->size_cells = propval_cell(prop); + } +-WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, ++WARNING(addr_size_cells, fixup_addr_size_cells, NULL, + &address_cells_is_cell, &size_cells_is_cell); + + #define node_addr_cells(n) \ +@@ -537,7 +688,7 @@ WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, + #define node_size_cells(n) \ + (((n)->size_cells == -1) ? 1 : (n)->size_cells) + +-static void check_reg_format(struct check *c, struct node *dt, ++static void check_reg_format(struct check *c, struct dt_info *dti, + struct node *node) + { + struct property *prop; +@@ -548,25 +699,25 @@ static void check_reg_format(struct check *c, struct node *dt, + return; /* No "reg", that's fine */ + + if (!node->parent) { +- FAIL(c, "Root node has a \"reg\" property"); ++ FAIL(c, dti, node, "Root node has a \"reg\" property"); + return; + } + + if (prop->val.len == 0) +- FAIL(c, "\"reg\" property in %s is empty", node->fullpath); ++ FAIL_PROP(c, dti, node, prop, "property is empty"); + + addr_cells = node_addr_cells(node->parent); + size_cells = node_size_cells(node->parent); + entrylen = (addr_cells + size_cells) * sizeof(cell_t); + +- if ((prop->val.len % entrylen) != 0) +- FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " +- "(#address-cells == %d, #size-cells == %d)", +- node->fullpath, prop->val.len, addr_cells, size_cells); ++ if (!entrylen || (prop->val.len % entrylen) != 0) ++ FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) " ++ "(#address-cells == %d, #size-cells == %d)", ++ prop->val.len, addr_cells, size_cells); + } +-NODE_WARNING(reg_format, NULL, &addr_size_cells); ++WARNING(reg_format, check_reg_format, NULL, &addr_size_cells); + +-static void check_ranges_format(struct check *c, struct node *dt, ++static void check_ranges_format(struct check *c, struct dt_info *dti, + struct node *node) + { + struct property *prop; +@@ -577,7 +728,7 @@ static void check_ranges_format(struct check *c, struct node *dt, + return; + + if (!node->parent) { +- FAIL(c, "Root node has a \"ranges\" property"); ++ FAIL_PROP(c, dti, node, prop, "Root node has a \"ranges\" property"); + return; + } + +@@ -589,28 +740,237 @@ static void check_ranges_format(struct check *c, struct node *dt, + + if (prop->val.len == 0) { + if (p_addr_cells != c_addr_cells) +- FAIL(c, "%s has empty \"ranges\" property but its " +- "#address-cells (%d) differs from %s (%d)", +- node->fullpath, c_addr_cells, node->parent->fullpath, +- p_addr_cells); ++ FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " ++ "#address-cells (%d) differs from %s (%d)", ++ c_addr_cells, node->parent->fullpath, ++ p_addr_cells); + if (p_size_cells != c_size_cells) +- FAIL(c, "%s has empty \"ranges\" property but its " +- "#size-cells (%d) differs from %s (%d)", +- node->fullpath, c_size_cells, node->parent->fullpath, +- p_size_cells); ++ FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " ++ "#size-cells (%d) differs from %s (%d)", ++ c_size_cells, node->parent->fullpath, ++ p_size_cells); + } else if ((prop->val.len % entrylen) != 0) { +- FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) " +- "(parent #address-cells == %d, child #address-cells == %d, " +- "#size-cells == %d)", node->fullpath, prop->val.len, +- p_addr_cells, c_addr_cells, c_size_cells); ++ FAIL_PROP(c, dti, node, prop, "\"ranges\" property has invalid length (%d bytes) " ++ "(parent #address-cells == %d, child #address-cells == %d, " ++ "#size-cells == %d)", prop->val.len, ++ p_addr_cells, c_addr_cells, c_size_cells); ++ } ++} ++WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); ++ ++static const struct bus_type pci_bus = { ++ .name = "PCI", ++}; ++ ++static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node *node) ++{ ++ struct property *prop; ++ cell_t *cells; ++ ++ prop = get_property(node, "device_type"); ++ if (!prop || !streq(prop->val.val, "pci")) ++ return; ++ ++ node->bus = &pci_bus; ++ ++ if (!strprefixeq(node->name, node->basenamelen, "pci") && ++ !strprefixeq(node->name, node->basenamelen, "pcie")) ++ FAIL(c, dti, node, "node name is not \"pci\" or \"pcie\""); ++ ++ prop = get_property(node, "ranges"); ++ if (!prop) ++ FAIL(c, dti, node, "missing ranges for PCI bridge (or not a bridge)"); ++ ++ if (node_addr_cells(node) != 3) ++ FAIL(c, dti, node, "incorrect #address-cells for PCI bridge"); ++ if (node_size_cells(node) != 2) ++ FAIL(c, dti, node, "incorrect #size-cells for PCI bridge"); ++ ++ prop = get_property(node, "bus-range"); ++ if (!prop) ++ return; ++ ++ if (prop->val.len != (sizeof(cell_t) * 2)) { ++ FAIL_PROP(c, dti, node, prop, "value must be 2 cells"); ++ return; ++ } ++ cells = (cell_t *)prop->val.val; ++ if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1])) ++ FAIL_PROP(c, dti, node, prop, "1st cell must be less than or equal to 2nd cell"); ++ if (fdt32_to_cpu(cells[1]) > 0xff) ++ FAIL_PROP(c, dti, node, prop, "maximum bus number must be less than 256"); ++} ++WARNING(pci_bridge, check_pci_bridge, NULL, ++ &device_type_is_string, &addr_size_cells); ++ ++static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node) ++{ ++ struct property *prop; ++ unsigned int bus_num, min_bus, max_bus; ++ cell_t *cells; ++ ++ if (!node->parent || (node->parent->bus != &pci_bus)) ++ return; ++ ++ prop = get_property(node, "reg"); ++ if (!prop) ++ return; ++ ++ cells = (cell_t *)prop->val.val; ++ bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16; ++ ++ prop = get_property(node->parent, "bus-range"); ++ if (!prop) { ++ min_bus = max_bus = 0; ++ } else { ++ cells = (cell_t *)prop->val.val; ++ min_bus = fdt32_to_cpu(cells[0]); ++ max_bus = fdt32_to_cpu(cells[0]); ++ } ++ 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)", ++ bus_num, min_bus, max_bus); ++} ++WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, ®_format, &pci_bridge); ++ ++static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node) ++{ ++ struct property *prop; ++ const char *unitname = get_unitname(node); ++ char unit_addr[5]; ++ unsigned int dev, func, reg; ++ cell_t *cells; ++ ++ if (!node->parent || (node->parent->bus != &pci_bus)) ++ return; ++ ++ prop = get_property(node, "reg"); ++ if (!prop) { ++ FAIL(c, dti, node, "missing PCI reg property"); ++ return; ++ } ++ ++ cells = (cell_t *)prop->val.val; ++ if (cells[1] || cells[2]) ++ FAIL_PROP(c, dti, node, prop, "PCI reg config space address cells 2 and 3 must be 0"); ++ ++ reg = fdt32_to_cpu(cells[0]); ++ dev = (reg & 0xf800) >> 11; ++ func = (reg & 0x700) >> 8; ++ ++ if (reg & 0xff000000) ++ FAIL_PROP(c, dti, node, prop, "PCI reg address is not configuration space"); ++ if (reg & 0x000000ff) ++ FAIL_PROP(c, dti, node, prop, "PCI reg config space address register number must be 0"); ++ ++ if (func == 0) { ++ snprintf(unit_addr, sizeof(unit_addr), "%x", dev); ++ if (streq(unitname, unit_addr)) ++ return; ++ } ++ ++ snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func); ++ if (streq(unitname, unit_addr)) ++ return; ++ ++ FAIL(c, dti, node, "PCI unit address format error, expected \"%s\"", ++ unit_addr); ++} ++WARNING(pci_device_reg, check_pci_device_reg, NULL, ®_format, &pci_bridge); ++ ++static const struct bus_type simple_bus = { ++ .name = "simple-bus", ++}; ++ ++static bool node_is_compatible(struct node *node, const char *compat) ++{ ++ struct property *prop; ++ const char *str, *end; ++ ++ prop = get_property(node, "compatible"); ++ if (!prop) ++ return false; ++ ++ for (str = prop->val.val, end = str + prop->val.len; str < end; ++ str += strnlen(str, end - str) + 1) { ++ if (strprefixeq(str, end - str, compat)) ++ return true; + } ++ return false; ++} ++ ++static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) ++{ ++ if (node_is_compatible(node, "simple-bus")) ++ node->bus = &simple_bus; + } +-NODE_WARNING(ranges_format, NULL, &addr_size_cells); ++WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells); ++ ++static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node) ++{ ++ struct property *prop; ++ const char *unitname = get_unitname(node); ++ char unit_addr[17]; ++ unsigned int size; ++ uint64_t reg = 0; ++ cell_t *cells = NULL; ++ ++ if (!node->parent || (node->parent->bus != &simple_bus)) ++ return; ++ ++ prop = get_property(node, "reg"); ++ if (prop) ++ cells = (cell_t *)prop->val.val; ++ else { ++ prop = get_property(node, "ranges"); ++ if (prop && prop->val.len) ++ /* skip of child address */ ++ cells = ((cell_t *)prop->val.val) + node_addr_cells(node); ++ } ++ ++ if (!cells) { ++ if (node->parent->parent && !(node->bus == &simple_bus)) ++ FAIL(c, dti, node, "missing or empty reg/ranges property"); ++ return; ++ } ++ ++ size = node_addr_cells(node->parent); ++ while (size--) ++ reg = (reg << 32) | fdt32_to_cpu(*(cells++)); ++ ++ snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg); ++ if (!streq(unitname, unit_addr)) ++ FAIL(c, dti, node, "simple-bus unit address format error, expected \"%s\"", ++ unit_addr); ++} ++WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); ++ ++static void check_unit_address_format(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ const char *unitname = get_unitname(node); ++ ++ if (node->parent && node->parent->bus) ++ return; ++ ++ if (!unitname[0]) ++ return; ++ ++ if (!strncmp(unitname, "0x", 2)) { ++ FAIL(c, dti, node, "unit name should not have leading \"0x\""); ++ /* skip over 0x for next test */ ++ unitname += 2; ++ } ++ if (unitname[0] == '0' && isxdigit(unitname[1])) ++ FAIL(c, dti, node, "unit name should not have leading 0s"); ++} ++WARNING(unit_address_format, check_unit_address_format, NULL, ++ &node_name_format, &pci_bridge, &simple_bus_bridge); + + /* + * Style checks + */ +-static void check_avoid_default_addr_size(struct check *c, struct node *dt, ++static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti, + struct node *node) + { + struct property *reg, *ranges; +@@ -625,31 +985,377 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt, + return; + + if (node->parent->addr_cells == -1) +- FAIL(c, "Relying on default #address-cells value for %s", +- node->fullpath); ++ FAIL(c, dti, node, "Relying on default #address-cells value"); + + if (node->parent->size_cells == -1) +- FAIL(c, "Relying on default #size-cells value for %s", +- node->fullpath); ++ FAIL(c, dti, node, "Relying on default #size-cells value"); ++} ++WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, ++ &addr_size_cells); ++ ++static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ struct property *prop; ++ struct node *child; ++ bool has_reg = false; ++ ++ if (!node->parent || node->addr_cells < 0 || node->size_cells < 0) ++ return; ++ ++ if (get_property(node, "ranges") || !node->children) ++ return; ++ ++ for_each_child(node, child) { ++ prop = get_property(child, "reg"); ++ if (prop) ++ has_reg = true; ++ } ++ ++ if (!has_reg) ++ FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\" or child \"reg\" property"); + } +-NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); ++WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size); + + static void check_obsolete_chosen_interrupt_controller(struct check *c, +- struct node *dt) ++ struct dt_info *dti, ++ struct node *node) + { ++ struct node *dt = dti->dt; + struct node *chosen; + struct property *prop; + ++ if (node != dt) ++ return; ++ ++ + chosen = get_node_by_path(dt, "/chosen"); + if (!chosen) + return; + + prop = get_property(chosen, "interrupt-controller"); + if (prop) +- FAIL(c, "/chosen has obsolete \"interrupt-controller\" " +- "property"); ++ FAIL_PROP(c, dti, node, prop, ++ "/chosen has obsolete \"interrupt-controller\" property"); ++} ++WARNING(obsolete_chosen_interrupt_controller, ++ check_obsolete_chosen_interrupt_controller, NULL); ++ ++static void check_chosen_node_is_root(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ if (!streq(node->name, "chosen")) ++ return; ++ ++ if (node->parent != dti->dt) ++ FAIL(c, dti, node, "chosen node must be at root node"); + } +-TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); ++WARNING(chosen_node_is_root, check_chosen_node_is_root, NULL); ++ ++static void check_chosen_node_bootargs(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ struct property *prop; ++ ++ if (!streq(node->name, "chosen")) ++ return; ++ ++ prop = get_property(node, "bootargs"); ++ if (!prop) ++ return; ++ ++ c->data = prop->name; ++ check_is_string(c, dti, node); ++} ++WARNING(chosen_node_bootargs, check_chosen_node_bootargs, NULL); ++ ++static void check_chosen_node_stdout_path(struct check *c, struct dt_info *dti, ++ struct node *node) ++{ ++ struct property *prop; ++ ++ if (!streq(node->name, "chosen")) ++ return; ++ ++ prop = get_property(node, "stdout-path"); ++ if (!prop) { ++ prop = get_property(node, "linux,stdout-path"); ++ if (!prop) ++ return; ++ FAIL_PROP(c, dti, node, prop, "Use 'stdout-path' instead"); ++ } ++ ++ c->data = prop->name; ++ check_is_string(c, dti, node); ++} ++WARNING(chosen_node_stdout_path, check_chosen_node_stdout_path, NULL); ++ ++struct provider { ++ const char *prop_name; ++ const char *cell_name; ++ bool optional; ++}; ++ ++static void check_property_phandle_args(struct check *c, ++ struct dt_info *dti, ++ struct node *node, ++ struct property *prop, ++ const struct provider *provider) ++{ ++ struct node *root = dti->dt; ++ int cell, cellsize = 0; ++ ++ if (prop->val.len % sizeof(cell_t)) { ++ FAIL_PROP(c, dti, node, prop, ++ "property size (%d) is invalid, expected multiple of %zu", ++ prop->val.len, sizeof(cell_t)); ++ return; ++ } ++ ++ for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) { ++ struct node *provider_node; ++ struct property *cellprop; ++ int phandle; ++ ++ phandle = propval_cell_n(prop, cell); ++ /* ++ * Some bindings use a cell value 0 or -1 to skip over optional ++ * entries when each index position has a specific definition. ++ */ ++ if (phandle == 0 || phandle == -1) { ++ /* Give up if this is an overlay with external references */ ++ if (dti->dtsflags & DTSF_PLUGIN) ++ break; ++ ++ cellsize = 0; ++ continue; ++ } ++ ++ /* If we have markers, verify the current cell is a phandle */ ++ if (prop->val.markers) { ++ struct marker *m = prop->val.markers; ++ for_each_marker_of_type(m, REF_PHANDLE) { ++ if (m->offset == (cell * sizeof(cell_t))) ++ break; ++ } ++ if (!m) ++ FAIL_PROP(c, dti, node, prop, ++ "cell %d is not a phandle reference", ++ cell); ++ } ++ ++ provider_node = get_node_by_phandle(root, phandle); ++ if (!provider_node) { ++ FAIL_PROP(c, dti, node, prop, ++ "Could not get phandle node for (cell %d)", ++ cell); ++ break; ++ } ++ ++ cellprop = get_property(provider_node, provider->cell_name); ++ if (cellprop) { ++ cellsize = propval_cell(cellprop); ++ } else if (provider->optional) { ++ cellsize = 0; ++ } else { ++ FAIL(c, dti, node, "Missing property '%s' in node %s or bad phandle (referred from %s[%d])", ++ provider->cell_name, ++ provider_node->fullpath, ++ prop->name, cell); ++ break; ++ } ++ ++ if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) { ++ FAIL_PROP(c, dti, node, prop, ++ "property size (%d) too small for cell size %d", ++ prop->val.len, cellsize); ++ } ++ } ++} ++ ++static void check_provider_cells_property(struct check *c, ++ struct dt_info *dti, ++ struct node *node) ++{ ++ struct provider *provider = c->data; ++ struct property *prop; ++ ++ prop = get_property(node, provider->prop_name); ++ if (!prop) ++ return; ++ ++ check_property_phandle_args(c, dti, node, prop, provider); ++} ++#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \ ++ static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \ ++ WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references); ++ ++WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(dmas, "dmas", "#dma-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(hwlocks, "hwlocks", "#hwlock-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(interrupts_extended, "interrupts-extended", "#interrupt-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(io_channels, "io-channels", "#io-channel-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(iommus, "iommus", "#iommu-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(mboxes, "mboxes", "#mbox-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(msi_parent, "msi-parent", "#msi-cells", true); ++WARNING_PROPERTY_PHANDLE_CELLS(mux_controls, "mux-controls", "#mux-control-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(phys, "phys", "#phy-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(power_domains, "power-domains", "#power-domain-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(pwms, "pwms", "#pwm-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(resets, "resets", "#reset-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(sound_dai, "sound-dai", "#sound-dai-cells"); ++WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sensor-cells"); ++ ++static bool prop_is_gpio(struct property *prop) ++{ ++ char *str; ++ ++ /* ++ * *-gpios and *-gpio can appear in property names, ++ * so skip over any false matches (only one known ATM) ++ */ ++ if (strstr(prop->name, "nr-gpio")) ++ return false; ++ ++ str = strrchr(prop->name, '-'); ++ if (str) ++ str++; ++ else ++ str = prop->name; ++ if (!(streq(str, "gpios") || streq(str, "gpio"))) ++ return false; ++ ++ return true; ++} ++ ++static void check_gpios_property(struct check *c, ++ struct dt_info *dti, ++ struct node *node) ++{ ++ struct property *prop; ++ ++ /* Skip GPIO hog nodes which have 'gpios' property */ ++ if (get_property(node, "gpio-hog")) ++ return; ++ ++ for_each_property(node, prop) { ++ struct provider provider; ++ ++ if (!prop_is_gpio(prop)) ++ continue; ++ ++ provider.prop_name = prop->name; ++ provider.cell_name = "#gpio-cells"; ++ provider.optional = false; ++ check_property_phandle_args(c, dti, node, prop, &provider); ++ } ++ ++} ++WARNING(gpios_property, check_gpios_property, NULL, &phandle_references); ++ ++static void check_deprecated_gpio_property(struct check *c, ++ struct dt_info *dti, ++ struct node *node) ++{ ++ struct property *prop; ++ ++ for_each_property(node, prop) { ++ char *str; ++ ++ if (!prop_is_gpio(prop)) ++ continue; ++ ++ str = strstr(prop->name, "gpio"); ++ if (!streq(str, "gpio")) ++ continue; ++ ++ FAIL_PROP(c, dti, node, prop, ++ "'[*-]gpio' is deprecated, use '[*-]gpios' instead"); ++ } ++ ++} ++CHECK(deprecated_gpio_property, check_deprecated_gpio_property, NULL); ++ ++static bool node_is_interrupt_provider(struct node *node) ++{ ++ struct property *prop; ++ ++ prop = get_property(node, "interrupt-controller"); ++ if (prop) ++ return true; ++ ++ prop = get_property(node, "interrupt-map"); ++ if (prop) ++ return true; ++ ++ return false; ++} ++static void check_interrupts_property(struct check *c, ++ struct dt_info *dti, ++ struct node *node) ++{ ++ struct node *root = dti->dt; ++ struct node *irq_node = NULL, *parent = node; ++ struct property *irq_prop, *prop = NULL; ++ int irq_cells, phandle; ++ ++ irq_prop = get_property(node, "interrupts"); ++ if (!irq_prop) ++ return; ++ ++ if (irq_prop->val.len % sizeof(cell_t)) ++ FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu", ++ irq_prop->val.len, sizeof(cell_t)); ++ ++ while (parent && !prop) { ++ if (parent != node && node_is_interrupt_provider(parent)) { ++ irq_node = parent; ++ break; ++ } ++ ++ prop = get_property(parent, "interrupt-parent"); ++ if (prop) { ++ phandle = propval_cell(prop); ++ /* Give up if this is an overlay with external references */ ++ if ((phandle == 0 || phandle == -1) && ++ (dti->dtsflags & DTSF_PLUGIN)) ++ return; ++ ++ irq_node = get_node_by_phandle(root, phandle); ++ if (!irq_node) { ++ FAIL_PROP(c, dti, parent, prop, "Bad phandle"); ++ return; ++ } ++ if (!node_is_interrupt_provider(irq_node)) ++ FAIL(c, dti, irq_node, ++ "Missing interrupt-controller or interrupt-map property"); ++ ++ break; ++ } ++ ++ parent = parent->parent; ++ } ++ ++ if (!irq_node) { ++ FAIL(c, dti, node, "Missing interrupt-parent"); ++ return; ++ } ++ ++ prop = get_property(irq_node, "#interrupt-cells"); ++ if (!prop) { ++ FAIL(c, dti, irq_node, "Missing #interrupt-cells in interrupt-parent"); ++ return; ++ } ++ ++ irq_cells = propval_cell(prop); ++ if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) { ++ FAIL_PROP(c, dti, node, prop, ++ "size is (%d), expected multiple of %d", ++ irq_prop->val.len, (int)(irq_cells * sizeof(cell_t))); ++ } ++} ++WARNING(interrupts_property, check_interrupts_property, &phandle_references); + + static struct check *check_table[] = { + &duplicate_node_names, &duplicate_property_names, +@@ -663,11 +1369,52 @@ static struct check *check_table[] = { + + &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, + &device_type_is_string, &model_is_string, &status_is_string, ++ &label_is_string, ++ ++ &compatible_is_string_list, &names_is_string_list, ++ ++ &property_name_chars_strict, ++ &node_name_chars_strict, + + &addr_size_cells, ®_format, &ranges_format, + ++ &unit_address_vs_reg, ++ &unit_address_format, ++ ++ &pci_bridge, ++ &pci_device_reg, ++ &pci_device_bus_num, ++ ++ &simple_bus_bridge, ++ &simple_bus_reg, ++ + &avoid_default_addr_size, ++ &avoid_unnecessary_addr_size, + &obsolete_chosen_interrupt_controller, ++ &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, ++ ++ &clocks_property, ++ &cooling_device_property, ++ &dmas_property, ++ &hwlocks_property, ++ &interrupts_extended_property, ++ &io_channels_property, ++ &iommus_property, ++ &mboxes_property, ++ &msi_parent_property, ++ &mux_controls_property, ++ &phys_property, ++ &power_domains_property, ++ &pwms_property, ++ &resets_property, ++ &sound_dai_property, ++ &thermal_sensors_property, ++ ++ &deprecated_gpio_property, ++ &gpios_property, ++ &interrupts_property, ++ ++ &alias_paths, + + &always_fail, + }; +@@ -733,9 +1480,8 @@ void parse_checks_option(bool warn, bool error, const char *arg) + die("Unrecognized check name \"%s\"\n", name); + } + +-void process_checks(bool force, struct boot_info *bi) ++void process_checks(bool force, struct dt_info *dti) + { +- struct node *dt = bi->dt; + int i; + int error = 0; + +@@ -743,7 +1489,7 @@ void process_checks(bool force, struct boot_info *bi) + struct check *c = check_table[i]; + + if (c->warn || c->error) +- error = error || run_check(c, dt); ++ error = error || run_check(c, dti); + } + + if (error) { +diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c +index 8cae23746..aa37a16c8 100644 +--- a/scripts/dtc/data.c ++++ b/scripts/dtc/data.c +@@ -171,9 +171,9 @@ struct data data_merge(struct data d1, struct data d2) + struct data data_append_integer(struct data d, uint64_t value, int bits) + { + uint8_t value_8; +- uint16_t value_16; +- uint32_t value_32; +- uint64_t value_64; ++ fdt16_t value_16; ++ fdt32_t value_32; ++ fdt64_t value_64; + + switch (bits) { + case 8: +@@ -197,14 +197,14 @@ struct data data_append_integer(struct data d, uint64_t value, int bits) + } + } + +-struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) ++struct data data_append_re(struct data d, uint64_t address, uint64_t size) + { +- struct fdt_reserve_entry bere; ++ struct fdt_reserve_entry re; + +- bere.address = cpu_to_fdt64(re->address); +- bere.size = cpu_to_fdt64(re->size); ++ re.address = cpu_to_fdt64(address); ++ re.size = cpu_to_fdt64(size); + +- return data_append_data(d, &bere, sizeof(bere)); ++ return data_append_data(d, &re, sizeof(re)); + } + + struct data data_append_cell(struct data d, cell_t word) +diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l +index 0ee1caf03..fd825ebba 100644 +--- a/scripts/dtc/dtc-lexer.l ++++ b/scripts/dtc/dtc-lexer.l +@@ -62,7 +62,8 @@ static int dts_version = 1; + + static void push_input_file(const char *filename); + static bool pop_input_file(void); +-static void lexical_error(const char *fmt, ...); ++static void PRINTF(1, 2) lexical_error(const char *fmt, ...); ++ + %} + + %% +@@ -73,24 +74,32 @@ static void lexical_error(const char *fmt, ...); + } + + <*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { +- char *line, *tmp, *fn; ++ char *line, *fnstart, *fnend; ++ struct data fn; + /* skip text before line # */ + line = yytext; + while (!isdigit((unsigned char)*line)) + line++; +- /* skip digits in line # */ +- tmp = line; +- while (!isspace((unsigned char)*tmp)) +- tmp++; +- /* "NULL"-terminate line # */ +- *tmp = '\0'; +- /* start of filename */ +- fn = strchr(tmp + 1, '"') + 1; +- /* strip trailing " from filename */ +- tmp = strchr(fn, '"'); +- *tmp = 0; ++ ++ /* regexp ensures that first and list " ++ * in the whole yytext are those at ++ * beginning and end of the filename string */ ++ fnstart = memchr(yytext, '"', yyleng); ++ for (fnend = yytext + yyleng - 1; ++ *fnend != '"'; fnend--) ++ ; ++ assert(fnstart && fnend && (fnend > fnstart)); ++ ++ fn = data_copy_escape_string(fnstart + 1, ++ fnend - fnstart - 1); ++ ++ /* Don't allow nuls in filenames */ ++ if (memchr(fn.val, '\0', fn.len - 1)) ++ lexical_error("nul in line number directive"); ++ + /* -1 since #line is the number of the next line */ +- srcpos_set_line(xstrdup(fn), atoi(line) - 1); ++ srcpos_set_line(xstrdup(fn.val), atoi(line) - 1); ++ data_free(fn); + } + + <*><> { +@@ -113,6 +122,11 @@ static void lexical_error(const char *fmt, ...); + return DT_V1; + } + ++<*>"/plugin/" { ++ DPRINT("Keyword: /plugin/\n"); ++ return DT_PLUGIN; ++ } ++ + <*>"/memreserve/" { + DPRINT("Keyword: /memreserve/\n"); + BEGIN_DEFAULT(); +@@ -153,7 +167,10 @@ static void lexical_error(const char *fmt, ...); + errno = 0; + yylval.integer = strtoull(yytext, &e, 0); + +- assert(!(*e) || !e[strspn(e, "UL")]); ++ if (*e && e[strspn(e, "UL")]) { ++ lexical_error("Bad integer literal '%s'", ++ yytext); ++ } + + if (errno == ERANGE) + lexical_error("Integer literal '%s' out of range", +@@ -173,16 +190,16 @@ static void lexical_error(const char *fmt, ...); + if (d.len == 1) { + lexical_error("Empty character literal"); + yylval.integer = 0; +- return DT_CHAR_LITERAL; +- } +- +- yylval.integer = (unsigned char)d.val[0]; ++ } else { ++ yylval.integer = (unsigned char)d.val[0]; + +- if (d.len > 2) +- lexical_error("Character literal has %d" +- " characters instead of 1", +- d.len - 1); ++ if (d.len > 2) ++ lexical_error("Character literal has %d" ++ " characters instead of 1", ++ d.len - 1); ++ } + ++ data_free(d); + return DT_CHAR_LITERAL; + } + +diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped +index 11cd78e72..f032b24b2 100644 +--- a/scripts/dtc/dtc-lexer.lex.c_shipped ++++ b/scripts/dtc/dtc-lexer.lex.c_shipped +@@ -1,6 +1,6 @@ +-#line 2 "dtc-lexer.lex.c" ++#line 2 "dtc-lexer.l.c" + +-#line 4 "dtc-lexer.lex.c" ++#line 4 "dtc-lexer.l.c" + + #define YY_INT_ALIGNED short int + +@@ -8,8 +8,8 @@ + + #define FLEX_SCANNER + #define YY_FLEX_MAJOR_VERSION 2 +-#define YY_FLEX_MINOR_VERSION 5 +-#define YY_FLEX_SUBMINOR_VERSION 39 ++#define YY_FLEX_MINOR_VERSION 6 ++#define YY_FLEX_SUBMINOR_VERSION 4 + #if YY_FLEX_SUBMINOR_VERSION > 0 + #define FLEX_BETA + #endif +@@ -84,60 +84,48 @@ typedef unsigned int flex_uint32_t; + #define UINT32_MAX (4294967295U) + #endif + ++#ifndef SIZE_MAX ++#define SIZE_MAX (~(size_t)0) ++#endif ++ + #endif /* ! C99 */ + + #endif /* ! FLEXINT_H */ + +-#ifdef __cplusplus +- +-/* The "const" storage-class-modifier is valid. */ +-#define YY_USE_CONST +- +-#else /* ! __cplusplus */ +- +-/* C99 requires __STDC__ to be defined as 1. */ +-#if defined (__STDC__) +- +-#define YY_USE_CONST ++/* begin standard C++ headers. */ + +-#endif /* defined (__STDC__) */ +-#endif /* ! __cplusplus */ +- +-#ifdef YY_USE_CONST ++/* TODO: this is always defined, so inline it */ + #define yyconst const ++ ++#if defined(__GNUC__) && __GNUC__ >= 3 ++#define yynoreturn __attribute__((__noreturn__)) + #else +-#define yyconst ++#define yynoreturn + #endif + + /* Returned upon end-of-file. */ + #define YY_NULL 0 + +-/* Promotes a possibly negative, possibly signed char to an unsigned +- * integer for use as an array index. If the signed char is negative, +- * we want to instead treat it as an 8-bit unsigned char, hence the +- * double cast. ++/* Promotes a possibly negative, possibly signed char to an ++ * integer in range [0..255] for use as an array index. + */ +-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) ++#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + + /* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ + #define BEGIN (yy_start) = 1 + 2 * +- + /* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ + #define YY_START (((yy_start) - 1) / 2) + #define YYSTATE YY_START +- + /* Action number for EOF rule of a given start state. */ + #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +- + /* Special action meaning "start processing a new file". */ +-#define YY_NEW_FILE yyrestart(yyin ) +- ++#define YY_NEW_FILE yyrestart( yyin ) + #define YY_END_OF_BUFFER_CHAR 0 + + /* Size of default input buffer. */ +@@ -167,14 +155,14 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; + typedef size_t yy_size_t; + #endif + +-extern yy_size_t yyleng; ++extern int yyleng; + + extern FILE *yyin, *yyout; + + #define EOB_ACT_CONTINUE_SCAN 0 + #define EOB_ACT_END_OF_FILE 1 + #define EOB_ACT_LAST_MATCH 2 +- ++ + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +@@ -191,7 +179,6 @@ extern FILE *yyin, *yyout; + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +- + #define unput(c) yyunput( c, (yytext_ptr) ) + + #ifndef YY_STRUCT_YY_BUFFER_STATE +@@ -206,12 +193,12 @@ struct yy_buffer_state + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ +- yy_size_t yy_buf_size; ++ int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ +- yy_size_t yy_n_chars; ++ int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to +@@ -234,7 +221,7 @@ struct yy_buffer_state + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ +- ++ + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ +@@ -262,7 +249,7 @@ struct yy_buffer_state + /* Stack of input buffers. */ + static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ + static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ ++static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ + + /* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general +@@ -273,7 +260,6 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +- + /* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +@@ -281,11 +267,11 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + + /* yy_hold_char holds the character lost when yytext is formed. */ + static char yy_hold_char; +-static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ +-yy_size_t yyleng; ++static int yy_n_chars; /* number of characters read into yy_ch_buf */ ++int yyleng; + + /* Points to current character in buffer. */ +-static char *yy_c_buf_p = (char *) 0; ++static char *yy_c_buf_p = NULL; + static int yy_init = 0; /* whether we need to initialize */ + static int yy_start = 0; /* start state number */ + +@@ -294,87 +280,83 @@ static int yy_start = 0; /* start state number */ + */ + static int yy_did_buffer_switch_on_eof; + +-void yyrestart (FILE *input_file ); +-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +-void yy_delete_buffer (YY_BUFFER_STATE b ); +-void yy_flush_buffer (YY_BUFFER_STATE b ); +-void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +-void yypop_buffer_state (void ); +- +-static void yyensure_buffer_stack (void ); +-static void yy_load_buffer_state (void ); +-static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); ++void yyrestart ( FILE *input_file ); ++void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); ++YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); ++void yy_delete_buffer ( YY_BUFFER_STATE b ); ++void yy_flush_buffer ( YY_BUFFER_STATE b ); ++void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); ++void yypop_buffer_state ( void ); + +-#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) ++static void yyensure_buffer_stack ( void ); ++static void yy_load_buffer_state ( void ); ++static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); ++#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); ++YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); ++YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); ++YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +-void *yyalloc (yy_size_t ); +-void *yyrealloc (void *,yy_size_t ); +-void yyfree (void * ); ++void *yyalloc ( yy_size_t ); ++void *yyrealloc ( void *, yy_size_t ); ++void yyfree ( void * ); + + #define yy_new_buffer yy_create_buffer +- + #define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ +- yy_create_buffer(yyin,YY_BUF_SIZE ); \ ++ yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +- + #define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ +- yy_create_buffer(yyin,YY_BUF_SIZE ); \ ++ yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +- + #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + + /* Begin user sect3 */ + +-#define yywrap() 1 ++#define yywrap() (/*CONSTCOND*/1) + #define YY_SKIP_YYWRAP ++typedef flex_uint8_t YY_CHAR; + +-typedef unsigned char YY_CHAR; +- +-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; ++FILE *yyin = NULL, *yyout = NULL; + + typedef int yy_state_type; + + extern int yylineno; +- + int yylineno = 1; + + extern char *yytext; ++#ifdef yytext_ptr ++#undef yytext_ptr ++#endif + #define yytext_ptr yytext + +-static yy_state_type yy_get_previous_state (void ); +-static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +-static int yy_get_next_buffer (void ); +-static void yy_fatal_error (yyconst char msg[] ); ++static yy_state_type yy_get_previous_state ( void ); ++static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); ++static int yy_get_next_buffer ( void ); ++static void yynoreturn yy_fatal_error ( const char* msg ); + + /* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ + #define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ +- yyleng = (size_t) (yy_cp - yy_bp); \ ++ yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; +- +-#define YY_NUM_RULES 30 +-#define YY_END_OF_BUFFER 31 ++#define YY_NUM_RULES 31 ++#define YY_END_OF_BUFFER 32 + /* This struct is not used in this scanner, + but its presence is necessary. */ + struct yy_trans_info +@@ -382,28 +364,29 @@ struct yy_trans_info + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +-static yyconst flex_int16_t yy_accept[159] = ++static const flex_int16_t yy_accept[166] = + { 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 31, 29, +- 18, 18, 29, 29, 29, 29, 29, 29, 29, 29, +- 29, 29, 29, 29, 29, 29, 15, 16, 16, 29, +- 16, 10, 10, 18, 26, 0, 3, 0, 27, 12, +- 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, +- 21, 23, 25, 24, 22, 0, 9, 28, 0, 0, +- 0, 14, 14, 16, 16, 16, 10, 10, 10, 0, +- 12, 0, 11, 0, 0, 0, 20, 0, 0, 0, +- 0, 0, 0, 0, 0, 16, 10, 10, 10, 0, +- 13, 19, 0, 0, 0, 0, 0, 0, 0, 0, +- +- 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 16, 6, 0, 0, 0, 0, 0, 0, 2, +- 0, 0, 0, 0, 0, 0, 0, 0, 4, 17, +- 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, +- 5, 8, 0, 0, 0, 0, 7, 0 ++ 0, 0, 0, 0, 0, 0, 0, 0, 32, 30, ++ 19, 19, 30, 30, 30, 30, 30, 30, 30, 30, ++ 30, 30, 30, 30, 30, 30, 16, 17, 17, 30, ++ 17, 11, 11, 19, 27, 0, 3, 0, 28, 13, ++ 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, ++ 0, 22, 24, 26, 25, 23, 0, 10, 29, 0, ++ 0, 0, 15, 15, 17, 17, 17, 11, 11, 11, ++ 0, 13, 0, 12, 0, 0, 0, 21, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 17, 11, 11, ++ 11, 0, 14, 20, 0, 0, 0, 0, 0, 0, ++ ++ 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 17, 7, 0, 0, 0, ++ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 4, 18, 0, 0, 5, 2, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 1, 0, 0, 0, 0, 6, 9, 0, ++ 0, 0, 0, 8, 0 + } ; + +-static yyconst flex_int32_t yy_ec[256] = ++static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, +@@ -416,9 +399,9 @@ static yyconst flex_int32_t yy_ec[256] = + 22, 22, 22, 22, 24, 22, 22, 25, 22, 22, + 1, 26, 27, 1, 22, 1, 21, 28, 29, 30, + +- 31, 21, 22, 22, 32, 22, 22, 33, 34, 35, +- 36, 37, 22, 38, 39, 40, 41, 42, 22, 25, +- 43, 22, 44, 45, 46, 1, 1, 1, 1, 1, ++ 31, 21, 32, 22, 33, 22, 22, 34, 35, 36, ++ 37, 38, 22, 39, 40, 41, 42, 43, 22, 25, ++ 44, 22, 45, 46, 47, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +@@ -435,163 +418,165 @@ static yyconst flex_int32_t yy_ec[256] = + 1, 1, 1, 1, 1 + } ; + +-static yyconst flex_int32_t yy_meta[47] = ++static const YY_CHAR yy_meta[48] = + { 0, + 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, + 2, 2, 4, 5, 5, 5, 6, 1, 1, 1, + 7, 8, 8, 8, 8, 1, 1, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, +- 8, 8, 8, 3, 1, 4 ++ 8, 8, 8, 8, 3, 1, 4 + } ; + +-static yyconst flex_int16_t yy_base[173] = ++static const flex_int16_t yy_base[180] = + { 0, +- 0, 383, 34, 382, 65, 381, 37, 105, 387, 391, +- 54, 111, 367, 110, 109, 109, 112, 41, 366, 104, +- 367, 338, 124, 117, 0, 144, 391, 0, 121, 0, +- 135, 155, 140, 179, 391, 160, 391, 379, 391, 0, +- 368, 141, 391, 167, 370, 376, 346, 103, 342, 345, +- 391, 391, 391, 391, 391, 358, 391, 391, 175, 342, +- 338, 391, 355, 0, 185, 339, 184, 347, 346, 0, +- 0, 322, 175, 357, 175, 363, 352, 324, 330, 323, +- 332, 326, 201, 324, 329, 322, 391, 333, 181, 309, +- 391, 341, 340, 313, 320, 338, 178, 311, 146, 317, +- +- 314, 315, 335, 331, 303, 300, 309, 299, 308, 188, +- 336, 335, 391, 305, 320, 281, 283, 271, 203, 288, +- 281, 271, 266, 264, 245, 242, 208, 104, 391, 391, +- 244, 218, 204, 219, 206, 224, 201, 212, 204, 229, +- 215, 208, 207, 200, 219, 391, 233, 221, 200, 181, +- 391, 391, 149, 122, 86, 41, 391, 391, 245, 251, +- 259, 263, 267, 273, 280, 284, 292, 300, 304, 310, +- 318, 326 ++ 0, 393, 35, 392, 66, 391, 38, 107, 397, 401, ++ 55, 113, 377, 112, 111, 111, 114, 42, 376, 106, ++ 377, 347, 126, 120, 0, 147, 401, 0, 124, 0, ++ 137, 158, 170, 163, 401, 153, 401, 389, 401, 0, ++ 378, 120, 401, 131, 380, 386, 355, 139, 351, 355, ++ 351, 401, 401, 401, 401, 401, 367, 401, 401, 185, ++ 350, 346, 401, 364, 0, 185, 347, 189, 356, 355, ++ 0, 0, 330, 180, 366, 141, 372, 361, 332, 338, ++ 331, 341, 334, 326, 205, 331, 337, 329, 401, 341, ++ 167, 316, 401, 349, 348, 320, 328, 346, 180, 318, ++ ++ 324, 209, 324, 320, 322, 342, 338, 309, 306, 315, ++ 305, 315, 312, 192, 342, 341, 401, 293, 306, 282, ++ 268, 252, 255, 203, 285, 282, 272, 268, 252, 233, ++ 232, 239, 208, 107, 401, 401, 238, 211, 401, 211, ++ 212, 208, 228, 203, 215, 207, 233, 222, 212, 211, ++ 203, 227, 401, 237, 225, 204, 185, 401, 401, 149, ++ 128, 88, 42, 401, 401, 253, 259, 267, 271, 275, ++ 281, 288, 292, 300, 308, 312, 318, 326, 334 + } ; + +-static yyconst flex_int16_t yy_def[173] = ++static const flex_int16_t yy_def[180] = + { 0, +- 158, 1, 1, 3, 158, 5, 1, 1, 158, 158, +- 158, 158, 158, 159, 160, 161, 158, 158, 158, 158, +- 162, 158, 158, 158, 163, 162, 158, 164, 165, 164, +- 164, 158, 158, 158, 158, 159, 158, 159, 158, 166, +- 158, 161, 158, 161, 167, 168, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 162, 158, 158, 158, 158, +- 158, 158, 162, 164, 165, 164, 158, 158, 158, 169, +- 166, 170, 161, 167, 167, 168, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 164, 158, 158, 169, 170, +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- +- 158, 164, 158, 158, 158, 158, 158, 158, 158, 171, +- 158, 164, 158, 158, 158, 158, 158, 158, 171, 158, +- 171, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 172, 158, 158, 158, 172, 158, 172, 158, 158, 158, +- 158, 158, 158, 158, 158, 158, 158, 0, 158, 158, +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 158, 158 ++ 165, 1, 1, 3, 165, 5, 1, 1, 165, 165, ++ 165, 165, 165, 166, 167, 168, 165, 165, 165, 165, ++ 169, 165, 165, 165, 170, 169, 165, 171, 172, 171, ++ 171, 165, 165, 165, 165, 166, 165, 166, 165, 173, ++ 165, 168, 165, 168, 174, 175, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 169, 165, 165, 165, ++ 165, 165, 165, 169, 171, 172, 171, 165, 165, 165, ++ 176, 173, 177, 168, 174, 174, 175, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 171, 165, 165, ++ 176, 177, 165, 165, 165, 165, 165, 165, 165, 165, ++ ++ 165, 165, 165, 165, 171, 165, 165, 165, 165, 165, ++ 165, 165, 165, 178, 165, 171, 165, 165, 165, 165, ++ 165, 165, 165, 178, 165, 178, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 179, 165, 165, ++ 165, 179, 165, 179, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 0, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165, 165 + } ; + +-static yyconst flex_int16_t yy_nxt[438] = ++static const flex_int16_t yy_nxt[449] = + { 0, + 10, 11, 12, 11, 13, 14, 10, 15, 16, 10, + 10, 10, 17, 10, 10, 10, 10, 18, 19, 20, + 21, 21, 21, 21, 21, 10, 10, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, +- 21, 21, 21, 10, 22, 10, 24, 25, 25, 25, +- 32, 33, 33, 157, 26, 34, 34, 34, 51, 52, +- 27, 26, 26, 26, 26, 10, 11, 12, 11, 13, +- 14, 28, 15, 16, 28, 28, 28, 24, 28, 28, +- 28, 10, 18, 19, 20, 29, 29, 29, 29, 29, +- 30, 10, 29, 29, 29, 29, 29, 29, 29, 29, +- +- 29, 29, 29, 29, 29, 29, 29, 29, 10, 22, +- 10, 23, 34, 34, 34, 37, 39, 43, 32, 33, +- 33, 45, 54, 55, 46, 59, 45, 64, 156, 46, +- 64, 64, 64, 79, 44, 38, 59, 57, 134, 47, +- 135, 48, 80, 49, 47, 50, 48, 99, 61, 43, +- 50, 110, 41, 67, 67, 67, 60, 63, 63, 63, +- 57, 155, 68, 69, 63, 37, 44, 66, 67, 67, +- 67, 63, 63, 63, 63, 73, 59, 68, 69, 70, +- 34, 34, 34, 43, 75, 38, 154, 92, 83, 83, +- 83, 64, 44, 120, 64, 64, 64, 67, 67, 67, +- +- 44, 57, 99, 68, 69, 107, 68, 69, 120, 127, +- 108, 153, 152, 121, 83, 83, 83, 133, 133, 133, +- 146, 133, 133, 133, 146, 140, 140, 140, 121, 141, +- 140, 140, 140, 151, 141, 158, 150, 149, 148, 144, +- 147, 143, 142, 139, 147, 36, 36, 36, 36, 36, +- 36, 36, 36, 40, 138, 137, 136, 40, 40, 42, +- 42, 42, 42, 42, 42, 42, 42, 56, 56, 56, +- 56, 62, 132, 62, 64, 131, 130, 64, 129, 64, +- 64, 65, 128, 158, 65, 65, 65, 65, 71, 127, +- 71, 71, 74, 74, 74, 74, 74, 74, 74, 74, +- +- 76, 76, 76, 76, 76, 76, 76, 76, 89, 126, +- 89, 90, 125, 90, 90, 124, 90, 90, 119, 119, +- 119, 119, 119, 119, 119, 119, 145, 145, 145, 145, +- 145, 145, 145, 145, 123, 122, 59, 59, 118, 117, +- 116, 115, 114, 113, 45, 112, 108, 111, 109, 106, +- 105, 104, 46, 103, 91, 87, 102, 101, 100, 98, +- 97, 96, 95, 94, 93, 77, 75, 91, 88, 87, +- 86, 57, 85, 84, 57, 82, 81, 78, 77, 75, +- 72, 158, 58, 57, 53, 35, 158, 31, 23, 23, +- 9, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 158, 158 ++ 21, 21, 21, 21, 10, 22, 10, 24, 25, 25, ++ 25, 32, 33, 33, 164, 26, 34, 34, 34, 52, ++ 53, 27, 26, 26, 26, 26, 10, 11, 12, 11, ++ 13, 14, 28, 15, 16, 28, 28, 28, 24, 28, ++ 28, 28, 10, 18, 19, 20, 29, 29, 29, 29, ++ 29, 30, 10, 29, 29, 29, 29, 29, 29, 29, ++ ++ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, ++ 10, 22, 10, 23, 34, 34, 34, 37, 39, 43, ++ 32, 33, 33, 45, 55, 56, 46, 60, 43, 45, ++ 65, 163, 46, 65, 65, 65, 44, 38, 60, 74, ++ 58, 47, 141, 48, 142, 44, 49, 47, 50, 48, ++ 76, 51, 62, 94, 50, 41, 44, 51, 37, 61, ++ 64, 64, 64, 58, 34, 34, 34, 64, 162, 80, ++ 67, 68, 68, 68, 64, 64, 64, 64, 38, 81, ++ 69, 70, 71, 68, 68, 68, 60, 161, 43, 69, ++ 70, 65, 69, 70, 65, 65, 65, 125, 85, 85, ++ ++ 85, 58, 68, 68, 68, 44, 102, 110, 125, 133, ++ 102, 69, 70, 111, 114, 160, 159, 126, 85, 85, ++ 85, 140, 140, 140, 140, 140, 140, 153, 126, 147, ++ 147, 147, 153, 148, 147, 147, 147, 158, 148, 165, ++ 157, 156, 155, 151, 150, 149, 146, 154, 145, 144, ++ 143, 139, 154, 36, 36, 36, 36, 36, 36, 36, ++ 36, 40, 138, 137, 136, 40, 40, 42, 42, 42, ++ 42, 42, 42, 42, 42, 57, 57, 57, 57, 63, ++ 135, 63, 65, 134, 165, 65, 133, 65, 65, 66, ++ 132, 131, 66, 66, 66, 66, 72, 130, 72, 72, ++ ++ 75, 75, 75, 75, 75, 75, 75, 75, 77, 77, ++ 77, 77, 77, 77, 77, 77, 91, 129, 91, 92, ++ 128, 92, 92, 127, 92, 92, 124, 124, 124, 124, ++ 124, 124, 124, 124, 152, 152, 152, 152, 152, 152, ++ 152, 152, 60, 60, 123, 122, 121, 120, 119, 118, ++ 117, 45, 116, 111, 115, 113, 112, 109, 108, 107, ++ 46, 106, 93, 89, 105, 104, 103, 101, 100, 99, ++ 98, 97, 96, 95, 78, 76, 93, 90, 89, 88, ++ 58, 87, 86, 58, 84, 83, 82, 79, 78, 76, ++ 73, 165, 59, 58, 54, 35, 165, 31, 23, 23, ++ ++ 9, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165 + } ; + +-static yyconst flex_int16_t yy_chk[438] = ++static const flex_int16_t yy_chk[449] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +- 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, +- 7, 7, 7, 156, 3, 11, 11, 11, 18, 18, +- 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, ++ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, ++ 3, 7, 7, 7, 163, 3, 11, 11, 11, 18, ++ 18, 3, 3, 3, 3, 3, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, +- 5, 8, 12, 12, 12, 14, 15, 16, 8, 8, +- 8, 17, 20, 20, 17, 23, 24, 29, 155, 24, +- 29, 29, 29, 48, 16, 14, 31, 29, 128, 17, +- 128, 17, 48, 17, 24, 17, 24, 99, 24, 42, +- 24, 99, 15, 33, 33, 33, 23, 26, 26, 26, +- 26, 154, 33, 33, 26, 36, 42, 31, 32, 32, +- 32, 26, 26, 26, 26, 44, 59, 32, 32, 32, +- 34, 34, 34, 73, 75, 36, 153, 75, 59, 59, +- 59, 65, 44, 110, 65, 65, 65, 67, 67, 67, +- +- 73, 65, 83, 89, 89, 97, 67, 67, 119, 127, +- 97, 150, 149, 110, 83, 83, 83, 133, 133, 133, +- 141, 127, 127, 127, 145, 136, 136, 136, 119, 136, +- 140, 140, 140, 148, 140, 147, 144, 143, 142, 139, +- 141, 138, 137, 135, 145, 159, 159, 159, 159, 159, +- 159, 159, 159, 160, 134, 132, 131, 160, 160, 161, +- 161, 161, 161, 161, 161, 161, 161, 162, 162, 162, +- 162, 163, 126, 163, 164, 125, 124, 164, 123, 164, +- 164, 165, 122, 121, 165, 165, 165, 165, 166, 120, +- 166, 166, 167, 167, 167, 167, 167, 167, 167, 167, +- +- 168, 168, 168, 168, 168, 168, 168, 168, 169, 118, +- 169, 170, 117, 170, 170, 116, 170, 170, 171, 171, +- 171, 171, 171, 171, 171, 171, 172, 172, 172, 172, +- 172, 172, 172, 172, 115, 114, 112, 111, 109, 108, +- 107, 106, 105, 104, 103, 102, 101, 100, 98, 96, +- 95, 94, 93, 92, 90, 88, 86, 85, 84, 82, +- 81, 80, 79, 78, 77, 76, 74, 72, 69, 68, +- 66, 63, 61, 60, 56, 50, 49, 47, 46, 45, ++ 5, 5, 5, 8, 12, 12, 12, 14, 15, 16, ++ 8, 8, 8, 17, 20, 20, 17, 23, 42, 24, ++ 29, 162, 24, 29, 29, 29, 16, 14, 31, 44, ++ 29, 17, 134, 17, 134, 42, 17, 24, 17, 24, ++ 76, 17, 24, 76, 24, 15, 44, 24, 36, 23, ++ 26, 26, 26, 26, 34, 34, 34, 26, 161, 48, ++ 31, 32, 32, 32, 26, 26, 26, 26, 36, 48, ++ 32, 32, 32, 33, 33, 33, 60, 160, 74, 91, ++ 91, 66, 33, 33, 66, 66, 66, 114, 60, 60, ++ ++ 60, 66, 68, 68, 68, 74, 85, 99, 124, 133, ++ 102, 68, 68, 99, 102, 157, 156, 114, 85, 85, ++ 85, 133, 133, 133, 140, 140, 140, 148, 124, 143, ++ 143, 143, 152, 143, 147, 147, 147, 155, 147, 154, ++ 151, 150, 149, 146, 145, 144, 142, 148, 141, 138, ++ 137, 132, 152, 166, 166, 166, 166, 166, 166, 166, ++ 166, 167, 131, 130, 129, 167, 167, 168, 168, 168, ++ 168, 168, 168, 168, 168, 169, 169, 169, 169, 170, ++ 128, 170, 171, 127, 126, 171, 125, 171, 171, 172, ++ 123, 122, 172, 172, 172, 172, 173, 121, 173, 173, ++ ++ 174, 174, 174, 174, 174, 174, 174, 174, 175, 175, ++ 175, 175, 175, 175, 175, 175, 176, 120, 176, 177, ++ 119, 177, 177, 118, 177, 177, 178, 178, 178, 178, ++ 178, 178, 178, 178, 179, 179, 179, 179, 179, 179, ++ 179, 179, 116, 115, 113, 112, 111, 110, 109, 108, ++ 107, 106, 105, 104, 103, 101, 100, 98, 97, 96, ++ 95, 94, 92, 90, 88, 87, 86, 84, 83, 82, ++ 81, 80, 79, 78, 77, 75, 73, 70, 69, 67, ++ 64, 62, 61, 57, 51, 50, 49, 47, 46, 45, + 41, 38, 22, 21, 19, 13, 9, 6, 4, 2, +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, + +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +- 158, 158, 158, 158, 158, 158, 158 ++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, ++ 165, 165, 165, 165, 165, 165, 165, 165 + } ; + + static yy_state_type yy_last_accepting_state; +@@ -608,7 +593,7 @@ int yy_flex_debug = 0; + #define YY_MORE_ADJ 0 + #define YY_RESTORE_YY_MORE_OFFSET + char *yytext; +-#line 1 "dtc-lexer.l" ++#line 1 "" + /* + * (C) Copyright David Gibson , IBM Corporation. 2005. + * +@@ -632,7 +617,7 @@ char *yytext; + + + +-#line 37 "dtc-lexer.l" ++#line 37 "" + #include "dtc.h" + #include "srcpos.h" + #include "dtc-parser.tab.h" +@@ -661,8 +646,10 @@ static int dts_version = 1; + + static void push_input_file(const char *filename); + static bool pop_input_file(void); +-static void lexical_error(const char *fmt, ...); +-#line 666 "dtc-lexer.lex.c" ++static void PRINTF(1, 2) lexical_error(const char *fmt, ...); ++ ++#line 652 "dtc-lexer.l.c" ++#line 653 "dtc-lexer.l.c" + + #define INITIAL 0 + #define BYTESTRING 1 +@@ -681,36 +668,36 @@ static void lexical_error(const char *fmt, ...); + #define YY_EXTRA_TYPE void * + #endif + +-static int yy_init_globals (void ); ++static int yy_init_globals ( void ); + + /* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +-int yylex_destroy (void ); ++int yylex_destroy ( void ); + +-int yyget_debug (void ); ++int yyget_debug ( void ); + +-void yyset_debug (int debug_flag ); ++void yyset_debug ( int debug_flag ); + +-YY_EXTRA_TYPE yyget_extra (void ); ++YY_EXTRA_TYPE yyget_extra ( void ); + +-void yyset_extra (YY_EXTRA_TYPE user_defined ); ++void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +-FILE *yyget_in (void ); ++FILE *yyget_in ( void ); + +-void yyset_in (FILE * in_str ); ++void yyset_in ( FILE * _in_str ); + +-FILE *yyget_out (void ); ++FILE *yyget_out ( void ); + +-void yyset_out (FILE * out_str ); ++void yyset_out ( FILE * _out_str ); + +-yy_size_t yyget_leng (void ); ++ int yyget_leng ( void ); + +-char *yyget_text (void ); ++char *yyget_text ( void ); + +-int yyget_lineno (void ); ++int yyget_lineno ( void ); + +-void yyset_lineno (int line_number ); ++void yyset_lineno ( int _line_number ); + + /* Macros after this point can all be overridden by user definitions in + * section 1. +@@ -718,26 +705,29 @@ void yyset_lineno (int line_number ); + + #ifndef YY_SKIP_YYWRAP + #ifdef __cplusplus +-extern "C" int yywrap (void ); ++extern "C" int yywrap ( void ); + #else +-extern int yywrap (void ); ++extern int yywrap ( void ); ++#endif + #endif ++ ++#ifndef YY_NO_UNPUT ++ + #endif + + #ifndef yytext_ptr +-static void yy_flex_strncpy (char *,yyconst char *,int ); ++static void yy_flex_strncpy ( char *, const char *, int ); + #endif + + #ifdef YY_NEED_STRLEN +-static int yy_flex_strlen (yyconst char * ); ++static int yy_flex_strlen ( const char * ); + #endif + + #ifndef YY_NO_INPUT +- + #ifdef __cplusplus +-static int yyinput (void ); ++static int yyinput ( void ); + #else +-static int input (void ); ++static int input ( void ); + #endif + + #endif +@@ -757,7 +747,7 @@ static int input (void ); + /* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) ++#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) + #endif + + /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, +@@ -768,7 +758,7 @@ static int input (void ); + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ +- size_t n; \ ++ int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ +@@ -781,7 +771,7 @@ static int input (void ); + else \ + { \ + errno=0; \ +- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ ++ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ +@@ -836,7 +826,7 @@ extern int yylex (void); + + /* Code executed at the end of each rule. */ + #ifndef YY_BREAK +-#define YY_BREAK break; ++#define YY_BREAK /*LINTED*/break; + #endif + + #define YY_RULE_SETUP \ +@@ -849,9 +839,9 @@ extern int yylex (void); + */ + YY_DECL + { +- register yy_state_type yy_current_state; +- register char *yy_cp, *yy_bp; +- register int yy_act; ++ yy_state_type yy_current_state; ++ char *yy_cp, *yy_bp; ++ int yy_act; + + if ( !(yy_init) ) + { +@@ -873,18 +863,18 @@ YY_DECL + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = +- yy_create_buffer(yyin,YY_BUF_SIZE ); ++ yy_create_buffer( yyin, YY_BUF_SIZE ); + } + +- yy_load_buffer_state( ); ++ yy_load_buffer_state( ); + } + + { +-#line 68 "dtc-lexer.l" ++#line 69 "" + +-#line 886 "dtc-lexer.lex.c" ++#line 876 "dtc-lexer.l.c" + +- while ( 1 ) /* loops until end-of-file is reached */ ++ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + +@@ -901,7 +891,7 @@ YY_DECL + yy_match: + do + { +- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; ++ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; +@@ -910,13 +900,13 @@ yy_match: + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; +- if ( yy_current_state >= 159 ) +- yy_c = yy_meta[(unsigned int) yy_c]; ++ if ( yy_current_state >= 166 ) ++ yy_c = yy_meta[yy_c]; + } +- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } +- while ( yy_current_state != 158 ); ++ while ( yy_current_state != 165 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + +@@ -939,7 +929,7 @@ do_action: /* This label is used only to access EOF actions. */ + case 1: + /* rule 1 can match eol */ + YY_RULE_SETUP +-#line 69 "dtc-lexer.l" ++#line 70 "" + { + char *name = strchr(yytext, '\"') + 1; + yytext[yyleng-1] = '\0'; +@@ -949,33 +939,41 @@ YY_RULE_SETUP + case 2: + /* rule 2 can match eol */ + YY_RULE_SETUP +-#line 75 "dtc-lexer.l" ++#line 76 "" + { +- char *line, *tmp, *fn; ++ char *line, *fnstart, *fnend; ++ struct data fn; + /* skip text before line # */ + line = yytext; + while (!isdigit((unsigned char)*line)) + line++; +- /* skip digits in line # */ +- tmp = line; +- while (!isspace((unsigned char)*tmp)) +- tmp++; +- /* "NULL"-terminate line # */ +- *tmp = '\0'; +- /* start of filename */ +- fn = strchr(tmp + 1, '"') + 1; +- /* strip trailing " from filename */ +- tmp = strchr(fn, '"'); +- *tmp = 0; ++ ++ /* regexp ensures that first and list " ++ * in the whole yytext are those at ++ * beginning and end of the filename string */ ++ fnstart = memchr(yytext, '"', yyleng); ++ for (fnend = yytext + yyleng - 1; ++ *fnend != '"'; fnend--) ++ ; ++ assert(fnstart && fnend && (fnend > fnstart)); ++ ++ fn = data_copy_escape_string(fnstart + 1, ++ fnend - fnstart - 1); ++ ++ /* Don't allow nuls in filenames */ ++ if (memchr(fn.val, '\0', fn.len - 1)) ++ lexical_error("nul in line number directive"); ++ + /* -1 since #line is the number of the next line */ +- srcpos_set_line(xstrdup(fn), atoi(line) - 1); ++ srcpos_set_line(xstrdup(fn.val), atoi(line) - 1); ++ data_free(fn); + } + YY_BREAK + case YY_STATE_EOF(INITIAL): + case YY_STATE_EOF(BYTESTRING): + case YY_STATE_EOF(PROPNODENAME): + case YY_STATE_EOF(V1): +-#line 96 "dtc-lexer.l" ++#line 105 "" + { + if (!pop_input_file()) { + yyterminate(); +@@ -985,7 +983,7 @@ case YY_STATE_EOF(V1): + case 3: + /* rule 3 can match eol */ + YY_RULE_SETUP +-#line 102 "dtc-lexer.l" ++#line 111 "" + { + DPRINT("String: %s\n", yytext); + yylval.data = data_copy_escape_string(yytext+1, +@@ -995,7 +993,7 @@ YY_RULE_SETUP + YY_BREAK + case 4: + YY_RULE_SETUP +-#line 109 "dtc-lexer.l" ++#line 118 "" + { + DPRINT("Keyword: /dts-v1/\n"); + dts_version = 1; +@@ -1005,25 +1003,33 @@ YY_RULE_SETUP + YY_BREAK + case 5: + YY_RULE_SETUP +-#line 116 "dtc-lexer.l" ++#line 125 "" ++{ ++ DPRINT("Keyword: /plugin/\n"); ++ return DT_PLUGIN; ++ } ++ YY_BREAK ++case 6: ++YY_RULE_SETUP ++#line 130 "" + { + DPRINT("Keyword: /memreserve/\n"); + BEGIN_DEFAULT(); + return DT_MEMRESERVE; + } + YY_BREAK +-case 6: ++case 7: + YY_RULE_SETUP +-#line 122 "dtc-lexer.l" ++#line 136 "" + { + DPRINT("Keyword: /bits/\n"); + BEGIN_DEFAULT(); + return DT_BITS; + } + YY_BREAK +-case 7: ++case 8: + YY_RULE_SETUP +-#line 128 "dtc-lexer.l" ++#line 142 "" + { + DPRINT("Keyword: /delete-property/\n"); + DPRINT("\n"); +@@ -1031,9 +1037,9 @@ YY_RULE_SETUP + return DT_DEL_PROP; + } + YY_BREAK +-case 8: ++case 9: + YY_RULE_SETUP +-#line 135 "dtc-lexer.l" ++#line 149 "" + { + DPRINT("Keyword: /delete-node/\n"); + DPRINT("\n"); +@@ -1041,9 +1047,9 @@ YY_RULE_SETUP + return DT_DEL_NODE; + } + YY_BREAK +-case 9: ++case 10: + YY_RULE_SETUP +-#line 142 "dtc-lexer.l" ++#line 156 "" + { + DPRINT("Label: %s\n", yytext); + yylval.labelref = xstrdup(yytext); +@@ -1051,9 +1057,9 @@ YY_RULE_SETUP + return DT_LABEL; + } + YY_BREAK +-case 10: ++case 11: + YY_RULE_SETUP +-#line 149 "dtc-lexer.l" ++#line 163 "" + { + char *e; + DPRINT("Integer Literal: '%s'\n", yytext); +@@ -1061,7 +1067,10 @@ YY_RULE_SETUP + errno = 0; + yylval.integer = strtoull(yytext, &e, 0); + +- assert(!(*e) || !e[strspn(e, "UL")]); ++ if (*e && e[strspn(e, "UL")]) { ++ lexical_error("Bad integer literal '%s'", ++ yytext); ++ } + + if (errno == ERANGE) + lexical_error("Integer literal '%s' out of range", +@@ -1073,10 +1082,10 @@ YY_RULE_SETUP + return DT_LITERAL; + } + YY_BREAK +-case 11: +-/* rule 11 can match eol */ ++case 12: ++/* rule 12 can match eol */ + YY_RULE_SETUP +-#line 168 "dtc-lexer.l" ++#line 185 "" + { + struct data d; + DPRINT("Character literal: %s\n", yytext); +@@ -1085,31 +1094,31 @@ YY_RULE_SETUP + if (d.len == 1) { + lexical_error("Empty character literal"); + yylval.integer = 0; +- return DT_CHAR_LITERAL; +- } ++ } else { ++ yylval.integer = (unsigned char)d.val[0]; + +- yylval.integer = (unsigned char)d.val[0]; +- +- if (d.len > 2) +- lexical_error("Character literal has %d" +- " characters instead of 1", +- d.len - 1); ++ if (d.len > 2) ++ lexical_error("Character literal has %d" ++ " characters instead of 1", ++ d.len - 1); ++ } + ++ data_free(d); + return DT_CHAR_LITERAL; + } + YY_BREAK +-case 12: ++case 13: + YY_RULE_SETUP +-#line 189 "dtc-lexer.l" ++#line 206 "" + { /* label reference */ + DPRINT("Ref: %s\n", yytext+1); + yylval.labelref = xstrdup(yytext+1); + return DT_REF; + } + YY_BREAK +-case 13: ++case 14: + YY_RULE_SETUP +-#line 195 "dtc-lexer.l" ++#line 212 "" + { /* new-style path reference */ + yytext[yyleng-1] = '\0'; + DPRINT("Ref: %s\n", yytext+2); +@@ -1117,27 +1126,27 @@ YY_RULE_SETUP + return DT_REF; + } + YY_BREAK +-case 14: ++case 15: + YY_RULE_SETUP +-#line 202 "dtc-lexer.l" ++#line 219 "" + { + yylval.byte = strtol(yytext, NULL, 16); + DPRINT("Byte: %02x\n", (int)yylval.byte); + return DT_BYTE; + } + YY_BREAK +-case 15: ++case 16: + YY_RULE_SETUP +-#line 208 "dtc-lexer.l" ++#line 225 "" + { + DPRINT("/BYTESTRING\n"); + BEGIN_DEFAULT(); + return ']'; + } + YY_BREAK +-case 16: ++case 17: + YY_RULE_SETUP +-#line 214 "dtc-lexer.l" ++#line 231 "" + { + DPRINT("PropNodeName: %s\n", yytext); + yylval.propnodename = xstrdup((yytext[0] == '\\') ? +@@ -1146,75 +1155,75 @@ YY_RULE_SETUP + return DT_PROPNODENAME; + } + YY_BREAK +-case 17: ++case 18: + YY_RULE_SETUP +-#line 222 "dtc-lexer.l" ++#line 239 "" + { + DPRINT("Binary Include\n"); + return DT_INCBIN; + } + YY_BREAK +-case 18: +-/* rule 18 can match eol */ +-YY_RULE_SETUP +-#line 227 "dtc-lexer.l" +-/* eat whitespace */ +- YY_BREAK + case 19: + /* rule 19 can match eol */ + YY_RULE_SETUP +-#line 228 "dtc-lexer.l" +-/* eat C-style comments */ ++#line 244 "" ++/* eat whitespace */ + YY_BREAK + case 20: + /* rule 20 can match eol */ + YY_RULE_SETUP +-#line 229 "dtc-lexer.l" +-/* eat C++-style comments */ ++#line 245 "" ++/* eat C-style comments */ + YY_BREAK + case 21: ++/* rule 21 can match eol */ + YY_RULE_SETUP +-#line 231 "dtc-lexer.l" +-{ return DT_LSHIFT; }; ++#line 246 "" ++/* eat C++-style comments */ + YY_BREAK + case 22: + YY_RULE_SETUP +-#line 232 "dtc-lexer.l" +-{ return DT_RSHIFT; }; ++#line 248 "" ++{ return DT_LSHIFT; }; + YY_BREAK + case 23: + YY_RULE_SETUP +-#line 233 "dtc-lexer.l" +-{ return DT_LE; }; ++#line 249 "" ++{ return DT_RSHIFT; }; + YY_BREAK + case 24: + YY_RULE_SETUP +-#line 234 "dtc-lexer.l" +-{ return DT_GE; }; ++#line 250 "" ++{ return DT_LE; }; + YY_BREAK + case 25: + YY_RULE_SETUP +-#line 235 "dtc-lexer.l" +-{ return DT_EQ; }; ++#line 251 "" ++{ return DT_GE; }; + YY_BREAK + case 26: + YY_RULE_SETUP +-#line 236 "dtc-lexer.l" +-{ return DT_NE; }; ++#line 252 "" ++{ return DT_EQ; }; + YY_BREAK + case 27: + YY_RULE_SETUP +-#line 237 "dtc-lexer.l" +-{ return DT_AND; }; ++#line 253 "" ++{ return DT_NE; }; + YY_BREAK + case 28: + YY_RULE_SETUP +-#line 238 "dtc-lexer.l" +-{ return DT_OR; }; ++#line 254 "" ++{ return DT_AND; }; + YY_BREAK + case 29: + YY_RULE_SETUP +-#line 240 "dtc-lexer.l" ++#line 255 "" ++{ return DT_OR; }; ++ YY_BREAK ++case 30: ++YY_RULE_SETUP ++#line 257 "" + { + DPRINT("Char: %c (\\x%02x)\n", yytext[0], + (unsigned)yytext[0]); +@@ -1230,12 +1239,12 @@ YY_RULE_SETUP + return yytext[0]; + } + YY_BREAK +-case 30: ++case 31: + YY_RULE_SETUP +-#line 255 "dtc-lexer.l" ++#line 272 "" + ECHO; + YY_BREAK +-#line 1239 "dtc-lexer.lex.c" ++#line 1248 "dtc-lexer.l.c" + + case YY_END_OF_BUFFER: + { +@@ -1312,7 +1321,7 @@ ECHO; + { + (yy_did_buffer_switch_on_eof) = 0; + +- if ( yywrap( ) ) ++ if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up +@@ -1377,9 +1386,9 @@ ECHO; + */ + static int yy_get_next_buffer (void) + { +- register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; +- register char *source = (yytext_ptr); +- register int number_to_move, i; ++ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; ++ char *source = (yytext_ptr); ++ int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) +@@ -1408,7 +1417,7 @@ static int yy_get_next_buffer (void) + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ +- number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; ++ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); +@@ -1421,7 +1430,7 @@ static int yy_get_next_buffer (void) + + else + { +- yy_size_t num_to_read = ++ int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) +@@ -1435,7 +1444,7 @@ static int yy_get_next_buffer (void) + + if ( b->yy_is_our_buffer ) + { +- yy_size_t new_size = b->yy_buf_size * 2; ++ int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; +@@ -1444,11 +1453,12 @@ static int yy_get_next_buffer (void) + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ +- yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); ++ yyrealloc( (void *) b->yy_ch_buf, ++ (yy_size_t) (b->yy_buf_size + 2) ); + } + else + /* Can't grow it, we don't own it. */ +- b->yy_ch_buf = 0; ++ b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( +@@ -1476,7 +1486,7 @@ static int yy_get_next_buffer (void) + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; +- yyrestart(yyin ); ++ yyrestart( yyin ); + } + + else +@@ -1490,12 +1500,15 @@ static int yy_get_next_buffer (void) + else + ret_val = EOB_ACT_CONTINUE_SCAN; + +- if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { ++ if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ +- yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); +- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); ++ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); ++ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( ++ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); ++ /* "- 2" to take care of EOB's */ ++ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; +@@ -1511,15 +1524,15 @@ static int yy_get_next_buffer (void) + + static yy_state_type yy_get_previous_state (void) + { +- register yy_state_type yy_current_state; +- register char *yy_cp; ++ yy_state_type yy_current_state; ++ char *yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { +- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); ++ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; +@@ -1528,10 +1541,10 @@ static int yy_get_next_buffer (void) + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; +- if ( yy_current_state >= 159 ) +- yy_c = yy_meta[(unsigned int) yy_c]; ++ if ( yy_current_state >= 166 ) ++ yy_c = yy_meta[yy_c]; + } +- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +@@ -1544,10 +1557,10 @@ static int yy_get_next_buffer (void) + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) + { +- register int yy_is_jam; +- register char *yy_cp = (yy_c_buf_p); ++ int yy_is_jam; ++ char *yy_cp = (yy_c_buf_p); + +- register YY_CHAR yy_c = 1; ++ YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; +@@ -1556,15 +1569,19 @@ static int yy_get_next_buffer (void) + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; +- if ( yy_current_state >= 159 ) +- yy_c = yy_meta[(unsigned int) yy_c]; ++ if ( yy_current_state >= 166 ) ++ yy_c = yy_meta[yy_c]; + } +- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; +- yy_is_jam = (yy_current_state == 158); ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++ yy_is_jam = (yy_current_state == 165); + + return yy_is_jam ? 0 : yy_current_state; + } + ++#ifndef YY_NO_UNPUT ++ ++#endif ++ + #ifndef YY_NO_INPUT + #ifdef __cplusplus + static int yyinput (void) +@@ -1589,7 +1606,7 @@ static int yy_get_next_buffer (void) + + else + { /* need more input */ +- yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); ++ int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) +@@ -1606,14 +1623,14 @@ static int yy_get_next_buffer (void) + */ + + /* Reset buffer status. */ +- yyrestart(yyin ); ++ yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { +- if ( yywrap( ) ) +- return EOF; ++ if ( yywrap( ) ) ++ return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +@@ -1652,11 +1669,11 @@ static int yy_get_next_buffer (void) + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = +- yy_create_buffer(yyin,YY_BUF_SIZE ); ++ yy_create_buffer( yyin, YY_BUF_SIZE ); + } + +- yy_init_buffer(YY_CURRENT_BUFFER,input_file ); +- yy_load_buffer_state( ); ++ yy_init_buffer( YY_CURRENT_BUFFER, input_file ); ++ yy_load_buffer_state( ); + } + + /** Switch to a different input buffer. +@@ -1684,7 +1701,7 @@ static int yy_get_next_buffer (void) + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; +- yy_load_buffer_state( ); ++ yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag +@@ -1712,7 +1729,7 @@ static void yy_load_buffer_state (void) + { + YY_BUFFER_STATE b; + +- b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); ++ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + +@@ -1721,13 +1738,13 @@ static void yy_load_buffer_state (void) + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ +- b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); ++ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + +- yy_init_buffer(b,file ); ++ yy_init_buffer( b, file ); + + return b; + } +@@ -1746,9 +1763,9 @@ static void yy_load_buffer_state (void) + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) +- yyfree((void *) b->yy_ch_buf ); ++ yyfree( (void *) b->yy_ch_buf ); + +- yyfree((void *) b ); ++ yyfree( (void *) b ); + } + + /* Initializes or reinitializes a buffer. +@@ -1760,7 +1777,7 @@ static void yy_load_buffer_state (void) + { + int oerrno = errno; + +- yy_flush_buffer(b ); ++ yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; +@@ -1803,7 +1820,7 @@ static void yy_load_buffer_state (void) + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) +- yy_load_buffer_state( ); ++ yy_load_buffer_state( ); + } + + /** Pushes the new state onto the stack. The new state becomes +@@ -1834,7 +1851,7 @@ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ +- yy_load_buffer_state( ); ++ yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } + +@@ -1853,7 +1870,7 @@ void yypop_buffer_state (void) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { +- yy_load_buffer_state( ); ++ yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } + } +@@ -1871,15 +1888,15 @@ static void yyensure_buffer_stack (void) + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ +- num_to_alloc = 1; ++ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); +- ++ + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); +- ++ + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; +@@ -1888,7 +1905,7 @@ static void yyensure_buffer_stack (void) + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ +- int grow_size = 8 /* arbitrary grow size */; ++ yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc +@@ -1908,7 +1925,7 @@ static void yyensure_buffer_stack (void) + * @param base the character buffer + * @param size the size in bytes of the character buffer + * +- * @return the newly allocated buffer state object. ++ * @return the newly allocated buffer state object. + */ + YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) + { +@@ -1918,23 +1935,23 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ +- return 0; ++ return NULL; + +- b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); ++ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + +- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ ++ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; +- b->yy_input_file = 0; ++ b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + +- yy_switch_to_buffer(b ); ++ yy_switch_to_buffer( b ); + + return b; + } +@@ -1947,10 +1964,10 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +-YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) ++YY_BUFFER_STATE yy_scan_string (const char * yystr ) + { + +- return yy_scan_bytes(yystr,strlen(yystr) ); ++ return yy_scan_bytes( yystr, (int) strlen(yystr) ); + } + + /** Setup the input buffer state to scan the given bytes. The next call to yylex() will +@@ -1960,16 +1977,16 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) + * + * @return the newly allocated buffer state object. + */ +-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) ++YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; +- yy_size_t i; ++ int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ +- n = _yybytes_len + 2; +- buf = (char *) yyalloc(n ); ++ n = (yy_size_t) (_yybytes_len + 2); ++ buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + +@@ -1978,7 +1995,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + +- b = yy_scan_buffer(buf,n ); ++ b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + +@@ -1994,9 +2011,9 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len + #define YY_EXIT_FAILURE 2 + #endif + +-static void yy_fatal_error (yyconst char* msg ) ++static void yynoreturn yy_fatal_error (const char* msg ) + { +- (void) fprintf( stderr, "%s\n", msg ); ++ fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + +@@ -2024,7 +2041,7 @@ static void yy_fatal_error (yyconst char* msg ) + */ + int yyget_lineno (void) + { +- ++ + return yylineno; + } + +@@ -2047,7 +2064,7 @@ FILE *yyget_out (void) + /** Get the length of the current token. + * + */ +-yy_size_t yyget_leng (void) ++int yyget_leng (void) + { + return yyleng; + } +@@ -2062,29 +2079,29 @@ char *yyget_text (void) + } + + /** Set the current line number. +- * @param line_number ++ * @param _line_number line number + * + */ +-void yyset_lineno (int line_number ) ++void yyset_lineno (int _line_number ) + { + +- yylineno = line_number; ++ yylineno = _line_number; + } + + /** Set the input stream. This does not discard the current + * input buffer. +- * @param in_str A readable stream. ++ * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +-void yyset_in (FILE * in_str ) ++void yyset_in (FILE * _in_str ) + { +- yyin = in_str ; ++ yyin = _in_str ; + } + +-void yyset_out (FILE * out_str ) ++void yyset_out (FILE * _out_str ) + { +- yyout = out_str ; ++ yyout = _out_str ; + } + + int yyget_debug (void) +@@ -2092,9 +2109,9 @@ int yyget_debug (void) + return yy_flex_debug; + } + +-void yyset_debug (int bdebug ) ++void yyset_debug (int _bdebug ) + { +- yy_flex_debug = bdebug ; ++ yy_flex_debug = _bdebug ; + } + + static int yy_init_globals (void) +@@ -2103,10 +2120,10 @@ static int yy_init_globals (void) + * This function is called from yylex_destroy(), so don't allocate here. + */ + +- (yy_buffer_stack) = 0; ++ (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; +- (yy_c_buf_p) = (char *) 0; ++ (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + +@@ -2115,8 +2132,8 @@ static int yy_init_globals (void) + yyin = stdin; + yyout = stdout; + #else +- yyin = (FILE *) 0; +- yyout = (FILE *) 0; ++ yyin = NULL; ++ yyout = NULL; + #endif + + /* For future reference: Set errno on error, since we are called by +@@ -2131,7 +2148,7 @@ int yylex_destroy (void) + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ +- yy_delete_buffer(YY_CURRENT_BUFFER ); ++ yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } +@@ -2152,18 +2169,19 @@ int yylex_destroy (void) + */ + + #ifndef yytext_ptr +-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) ++static void yy_flex_strncpy (char* s1, const char * s2, int n ) + { +- register int i; ++ ++ int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } + #endif + + #ifdef YY_NEED_STRLEN +-static int yy_flex_strlen (yyconst char * s ) ++static int yy_flex_strlen (const char * s ) + { +- register int n; ++ int n; + for ( n = 0; s[n]; ++n ) + ; + +@@ -2173,11 +2191,12 @@ static int yy_flex_strlen (yyconst char * s ) + + void *yyalloc (yy_size_t size ) + { +- return (void *) malloc( size ); ++ return malloc(size); + } + + void *yyrealloc (void * ptr, yy_size_t size ) + { ++ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter +@@ -2185,18 +2204,17 @@ void *yyrealloc (void * ptr, yy_size_t size ) + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ +- return (void *) realloc( (char *) ptr, size ); ++ return realloc(ptr, size); + } + + void yyfree (void * ptr ) + { +- free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ ++ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ + } + + #define YYTABLES_NAME "yytables" + +-#line 254 "dtc-lexer.l" +- ++#line 272 "" + + + static void push_input_file(const char *filename) +@@ -2207,7 +2225,7 @@ static void push_input_file(const char *filename) + + yyin = current_srcfile->f; + +- yypush_buffer_state(yy_create_buffer(yyin,YY_BUF_SIZE)); ++ yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE)); + } + + +diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped +index 27fac4b9c..06a6e9414 100644 +--- a/scripts/dtc/dtc-parser.tab.c_shipped ++++ b/scripts/dtc/dtc-parser.tab.c_shipped +@@ -1,8 +1,8 @@ +-/* A Bison parser, made by GNU Bison 3.0.2. */ ++/* A Bison parser, made by GNU Bison 3.0.4. */ + + /* Bison implementation for Yacc-like parsers in C + +- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. ++ Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by +@@ -44,7 +44,7 @@ + #define YYBISON 1 + + /* Bison version. */ +-#define YYBISON_VERSION "3.0.2" ++#define YYBISON_VERSION "3.0.4" + + /* Skeleton name. */ + #define YYSKELETON_NAME "yacc.c" +@@ -65,6 +65,7 @@ + #line 20 "dtc-parser.y" /* yacc.c:339 */ + + #include ++#include + + #include "dtc.h" + #include "srcpos.h" +@@ -77,10 +78,10 @@ extern void yyerror(char const *s); + treesource_error = true; \ + } while (0) + +-extern struct boot_info *the_boot_info; ++extern struct dt_info *parser_output; + extern bool treesource_error; + +-#line 84 "dtc-parser.tab.c" /* yacc.c:339 */ ++#line 85 "dtc-parser.tab.c" /* yacc.c:339 */ + + # ifndef YY_NULLPTR + # if defined __cplusplus && 201103L <= __cplusplus +@@ -116,35 +117,36 @@ extern int yydebug; + enum yytokentype + { + DT_V1 = 258, +- DT_MEMRESERVE = 259, +- DT_LSHIFT = 260, +- DT_RSHIFT = 261, +- DT_LE = 262, +- DT_GE = 263, +- DT_EQ = 264, +- DT_NE = 265, +- DT_AND = 266, +- DT_OR = 267, +- DT_BITS = 268, +- DT_DEL_PROP = 269, +- DT_DEL_NODE = 270, +- DT_PROPNODENAME = 271, +- DT_LITERAL = 272, +- DT_CHAR_LITERAL = 273, +- DT_BYTE = 274, +- DT_STRING = 275, +- DT_LABEL = 276, +- DT_REF = 277, +- DT_INCBIN = 278 ++ DT_PLUGIN = 259, ++ DT_MEMRESERVE = 260, ++ DT_LSHIFT = 261, ++ DT_RSHIFT = 262, ++ DT_LE = 263, ++ DT_GE = 264, ++ DT_EQ = 265, ++ DT_NE = 266, ++ DT_AND = 267, ++ DT_OR = 268, ++ DT_BITS = 269, ++ DT_DEL_PROP = 270, ++ DT_DEL_NODE = 271, ++ DT_PROPNODENAME = 272, ++ DT_LITERAL = 273, ++ DT_CHAR_LITERAL = 274, ++ DT_BYTE = 275, ++ DT_STRING = 276, ++ DT_LABEL = 277, ++ DT_REF = 278, ++ DT_INCBIN = 279 + }; + #endif + + /* Value type. */ + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +-typedef union YYSTYPE YYSTYPE; ++ + union YYSTYPE + { +-#line 38 "dtc-parser.y" /* yacc.c:355 */ ++#line 39 "dtc-parser.y" /* yacc.c:355 */ + + char *propnodename; + char *labelref; +@@ -162,9 +164,12 @@ union YYSTYPE + struct node *nodelist; + struct reserve_info *re; + uint64_t integer; ++ unsigned int flags; + +-#line 167 "dtc-parser.tab.c" /* yacc.c:355 */ ++#line 170 "dtc-parser.tab.c" /* yacc.c:355 */ + }; ++ ++typedef union YYSTYPE YYSTYPE; + # define YYSTYPE_IS_TRIVIAL 1 + # define YYSTYPE_IS_DECLARED 1 + #endif +@@ -192,7 +197,7 @@ int yyparse (void); + + /* Copy the second part of user declarations. */ + +-#line 196 "dtc-parser.tab.c" /* yacc.c:358 */ ++#line 201 "dtc-parser.tab.c" /* yacc.c:358 */ + + #ifdef short + # undef short +@@ -434,23 +439,23 @@ union yyalloc + #endif /* !YYCOPY_NEEDED */ + + /* YYFINAL -- State number of the termination state. */ +-#define YYFINAL 4 ++#define YYFINAL 6 + /* YYLAST -- Last index in YYTABLE. */ +-#define YYLAST 133 ++#define YYLAST 140 + + /* YYNTOKENS -- Number of terminals. */ +-#define YYNTOKENS 47 ++#define YYNTOKENS 48 + /* YYNNTS -- Number of nonterminals. */ +-#define YYNNTS 28 ++#define YYNNTS 30 + /* YYNRULES -- Number of rules. */ +-#define YYNRULES 79 ++#define YYNRULES 85 + /* YYNSTATES -- Number of states. */ +-#define YYNSTATES 141 ++#define YYNSTATES 151 + + /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ + #define YYUNDEFTOK 2 +-#define YYMAXUTOK 278 ++#define YYMAXUTOK 279 + + #define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) +@@ -462,16 +467,16 @@ static const yytype_uint8 yytranslate[] = + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +- 2, 2, 2, 46, 2, 2, 2, 44, 40, 2, +- 32, 34, 43, 41, 33, 42, 2, 25, 2, 2, +- 2, 2, 2, 2, 2, 2, 2, 2, 37, 24, +- 35, 28, 29, 36, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 47, 2, 2, 2, 45, 41, 2, ++ 33, 35, 44, 42, 34, 43, 2, 26, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 38, 25, ++ 36, 29, 30, 37, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +- 2, 30, 2, 31, 39, 2, 2, 2, 2, 2, ++ 2, 31, 2, 32, 40, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +- 2, 2, 2, 26, 38, 27, 45, 2, 2, 2, ++ 2, 2, 2, 27, 39, 28, 46, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +@@ -486,21 +491,22 @@ static const yytype_uint8 yytranslate[] = + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, +- 15, 16, 17, 18, 19, 20, 21, 22, 23 ++ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 + }; + + #if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ + static const yytype_uint16 yyrline[] = + { +- 0, 104, 104, 113, 116, 123, 127, 135, 139, 143, +- 153, 168, 176, 179, 186, 190, 194, 198, 206, 210, +- 214, 218, 222, 238, 248, 256, 259, 263, 270, 286, +- 291, 310, 324, 331, 332, 333, 340, 344, 345, 349, +- 350, 354, 355, 359, 360, 364, 365, 369, 370, 374, +- 375, 376, 380, 381, 382, 383, 384, 388, 389, 390, +- 394, 395, 396, 400, 401, 402, 403, 407, 408, 409, +- 410, 415, 418, 422, 430, 433, 437, 445, 449, 453 ++ 0, 109, 109, 117, 121, 128, 129, 139, 142, 149, ++ 153, 161, 165, 169, 180, 191, 210, 225, 233, 236, ++ 243, 247, 251, 255, 263, 267, 271, 275, 279, 295, ++ 305, 313, 316, 320, 327, 343, 348, 367, 381, 388, ++ 389, 390, 397, 401, 402, 406, 407, 411, 412, 416, ++ 417, 421, 422, 426, 427, 431, 432, 433, 437, 438, ++ 439, 440, 441, 445, 446, 447, 451, 452, 453, 457, ++ 458, 467, 476, 480, 481, 482, 483, 488, 491, 495, ++ 503, 506, 510, 518, 522, 526 + }; + #endif + +@@ -509,19 +515,20 @@ static const yytype_uint16 yyrline[] = + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ + static const char *const yytname[] = + { +- "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT", +- "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR", +- "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL", +- "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", +- "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'", +- "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'", +- "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile", +- "memreserves", "memreserve", "devicetree", "nodedef", "proplist", +- "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim", +- "integer_expr", "integer_trinary", "integer_or", "integer_and", +- "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq", +- "integer_rela", "integer_shift", "integer_add", "integer_mul", +- "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR ++ "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE", ++ "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", ++ "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", ++ "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", ++ "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", ++ "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", ++ "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile", ++ "header", "headers", "memreserves", "memreserve", "devicetree", ++ "nodedef", "proplist", "propdef", "propdata", "propdataprefix", ++ "arrayprefix", "integer_prim", "integer_expr", "integer_trinary", ++ "integer_or", "integer_and", "integer_bitor", "integer_bitxor", ++ "integer_bitand", "integer_eq", "integer_rela", "integer_shift", ++ "integer_add", "integer_mul", "integer_unary", "bytestring", "subnodes", ++ "subnode", YY_NULLPTR + }; + #endif + +@@ -532,16 +539,16 @@ static const yytype_uint16 yytoknum[] = + { + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, +- 275, 276, 277, 278, 59, 47, 123, 125, 61, 62, +- 91, 93, 40, 44, 41, 60, 63, 58, 124, 94, +- 38, 43, 45, 42, 37, 126, 33 ++ 275, 276, 277, 278, 279, 59, 47, 123, 125, 61, ++ 62, 91, 93, 40, 44, 41, 60, 63, 58, 124, ++ 94, 38, 43, 45, 42, 37, 126, 33 + }; + # endif + +-#define YYPACT_NINF -38 ++#define YYPACT_NINF -81 + + #define yypact_value_is_default(Yystate) \ +- (!!((Yystate) == (-38))) ++ (!!((Yystate) == (-81))) + + #define YYTABLE_NINF -1 + +@@ -552,21 +559,22 @@ static const yytype_uint16 yytoknum[] = + STATE-NUM. */ + static const yytype_int8 yypact[] = + { +- 21, 11, 45, 10, -38, 9, 10, 15, 10, -38, +- -38, -9, 9, -38, 56, 40, -38, -9, -9, -9, +- -38, 51, -38, -6, 75, 49, 52, 48, 50, 3, +- 66, 33, 0, -38, 65, -38, -38, 68, 56, 56, +- -38, -38, -38, -38, -9, -9, -9, -9, -9, -9, +- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, +- -9, -9, -9, -38, 42, 69, -38, -38, 75, 55, +- 49, 52, 48, 50, 3, 3, 66, 66, 66, 66, +- 33, 33, 0, 0, -38, -38, -38, 78, 79, -11, +- 42, -38, 70, 42, -38, -9, 72, 74, -38, -38, +- -38, -38, -38, 76, -38, -38, -38, -38, -38, 18, +- -1, -38, -38, -38, -38, 82, -38, -38, -38, 71, +- -38, -38, 32, 67, 81, -3, -38, -38, -38, -38, +- -38, 43, -38, -38, -38, 9, -38, 73, 9, 77, +- -38 ++ 11, 17, 23, 11, 10, 56, -81, -81, 21, 10, ++ -5, 10, 39, -81, -81, -13, 21, -81, 44, 44, ++ 43, -81, -81, -13, -13, -13, -81, 38, -81, -2, ++ 67, 53, 55, 57, 41, 1, 75, 42, -19, -81, ++ 58, -81, -81, -81, 73, 74, 44, 44, -81, -81, ++ -81, -81, -13, -13, -13, -13, -13, -13, -13, -13, ++ -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, ++ -13, -81, 46, 76, 44, -81, -81, 67, 61, 53, ++ 55, 57, 41, 1, 1, 75, 75, 75, 75, 42, ++ 42, -19, -19, -81, -81, -81, 83, 85, 45, 46, ++ -81, 77, 46, -81, -81, -13, 78, 79, -81, -81, ++ -81, -81, -81, 81, -81, -81, -81, -81, -81, 16, ++ 22, -81, -81, -81, -81, 89, -81, -81, -81, 80, ++ -81, -81, -6, 72, 88, 35, -81, -81, -81, -81, ++ -81, 52, -81, -81, -81, 21, -81, 82, 21, 84, ++ -81 + }; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. +@@ -574,37 +582,38 @@ static const yytype_int8 yypact[] = + means the default is an error. */ + static const yytype_uint8 yydefact[] = + { +- 0, 0, 0, 3, 1, 0, 0, 0, 3, 33, +- 34, 0, 0, 6, 0, 2, 4, 0, 0, 0, +- 67, 0, 36, 37, 39, 41, 43, 45, 47, 49, +- 52, 59, 62, 66, 0, 12, 7, 0, 0, 0, +- 68, 69, 70, 35, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 5, 7, 3, 1, 6, 0, 0, ++ 0, 7, 0, 39, 40, 0, 0, 10, 0, 0, ++ 2, 8, 4, 0, 0, 0, 73, 0, 42, 43, ++ 45, 47, 49, 51, 53, 55, 58, 65, 68, 72, ++ 0, 18, 13, 11, 0, 0, 0, 0, 74, 75, ++ 76, 41, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 5, 74, 0, 9, 8, 40, 0, +- 42, 44, 46, 48, 50, 51, 55, 56, 54, 53, +- 57, 58, 60, 61, 64, 63, 65, 0, 0, 0, +- 0, 13, 0, 74, 10, 0, 0, 0, 15, 25, +- 77, 17, 79, 0, 76, 75, 38, 16, 78, 0, +- 0, 11, 24, 14, 26, 0, 18, 27, 21, 0, +- 71, 29, 0, 0, 0, 0, 32, 31, 19, 30, +- 28, 0, 72, 73, 20, 0, 23, 0, 0, 0, +- 22 ++ 0, 9, 80, 0, 0, 15, 12, 46, 0, 48, ++ 50, 52, 54, 56, 57, 61, 62, 60, 59, 63, ++ 64, 66, 67, 70, 69, 71, 0, 0, 0, 0, ++ 19, 0, 80, 16, 14, 0, 0, 0, 21, 31, ++ 83, 23, 85, 0, 82, 81, 44, 22, 84, 0, ++ 0, 17, 30, 20, 32, 0, 24, 33, 27, 0, ++ 77, 35, 0, 0, 0, 0, 38, 37, 25, 36, ++ 34, 0, 78, 79, 26, 0, 29, 0, 0, 0, ++ 28 + }; + + /* YYPGOTO[NTERM-NUM]. */ + static const yytype_int8 yypgoto[] = + { +- -38, -38, 96, 99, -38, -37, -38, -20, -38, -38, +- -38, -5, 62, 13, -38, 80, 63, 84, 64, 61, +- 28, 14, 24, 25, -14, -38, 20, 26 ++ -81, -81, -81, 107, 100, 103, -81, -18, -81, -80, ++ -81, -81, -81, -8, 62, 9, -81, 65, 64, 66, ++ 69, 63, 30, 15, 26, 27, -21, -81, 20, 24 + }; + + /* YYDEFGOTO[NTERM-NUM]. */ +-static const yytype_int8 yydefgoto[] = ++static const yytype_int16 yydefgoto[] = + { +- -1, 2, 7, 8, 15, 36, 64, 91, 109, 110, +- 122, 20, 21, 22, 23, 24, 25, 26, 27, 28, +- 29, 30, 31, 32, 33, 125, 92, 93 ++ -1, 2, 3, 4, 10, 11, 20, 42, 72, 100, ++ 119, 120, 132, 26, 27, 28, 29, 30, 31, 32, ++ 33, 34, 35, 36, 37, 38, 39, 135, 101, 102 + }; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If +@@ -612,85 +621,90 @@ static const yytype_int8 yydefgoto[] = + number is the opposite. If YYTABLE_NINF, syntax error. */ + static const yytype_uint8 yytable[] = + { +- 12, 66, 67, 40, 41, 42, 44, 34, 9, 10, +- 52, 53, 115, 98, 5, 35, 132, 99, 133, 116, +- 117, 118, 119, 11, 1, 60, 9, 10, 134, 120, +- 45, 6, 54, 17, 121, 3, 18, 19, 55, 112, +- 14, 11, 113, 61, 62, 4, 84, 85, 86, 9, +- 10, 114, 100, 126, 127, 37, 87, 88, 89, 50, +- 51, 128, 38, 90, 11, 39, 76, 77, 78, 79, +- 101, 56, 57, 104, 58, 59, 135, 136, 74, 75, +- 80, 81, 35, 82, 83, 43, 46, 47, 49, 63, +- 65, 48, 95, 94, 96, 97, 107, 103, 108, 123, +- 111, 131, 130, 124, 16, 13, 138, 69, 106, 70, +- 73, 140, 72, 105, 0, 0, 102, 129, 0, 0, +- 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, +- 137, 71, 0, 139 ++ 16, 43, 48, 49, 50, 13, 14, 68, 40, 60, ++ 61, 52, 13, 14, 1, 8, 136, 137, 18, 111, ++ 15, 19, 114, 6, 138, 69, 70, 15, 75, 76, ++ 23, 62, 9, 24, 25, 53, 125, 63, 122, 13, ++ 14, 123, 5, 126, 127, 128, 129, 93, 94, 95, ++ 124, 58, 59, 130, 15, 142, 104, 143, 131, 44, ++ 12, 96, 97, 98, 22, 45, 46, 144, 99, 47, ++ 108, 41, 41, 51, 109, 85, 86, 87, 88, 54, ++ 110, 64, 65, 71, 66, 67, 145, 146, 83, 84, ++ 89, 90, 55, 91, 92, 56, 73, 74, 57, 105, ++ 106, 103, 107, 117, 118, 113, 121, 133, 140, 141, ++ 7, 21, 17, 134, 116, 78, 148, 77, 79, 150, ++ 82, 80, 115, 112, 139, 81, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 147, 0, 0, ++ 149 + }; + + static const yytype_int16 yycheck[] = + { +- 5, 38, 39, 17, 18, 19, 12, 12, 17, 18, +- 7, 8, 13, 24, 4, 26, 19, 28, 21, 20, +- 21, 22, 23, 32, 3, 25, 17, 18, 31, 30, +- 36, 21, 29, 42, 35, 24, 45, 46, 35, 21, +- 25, 32, 24, 43, 44, 0, 60, 61, 62, 17, +- 18, 33, 89, 21, 22, 15, 14, 15, 16, 9, +- 10, 29, 22, 21, 32, 25, 52, 53, 54, 55, +- 90, 5, 6, 93, 41, 42, 33, 34, 50, 51, +- 56, 57, 26, 58, 59, 34, 11, 38, 40, 24, +- 22, 39, 37, 24, 16, 16, 24, 27, 24, 17, +- 24, 20, 35, 32, 8, 6, 33, 45, 95, 46, +- 49, 34, 48, 93, -1, -1, 90, 122, -1, -1, +- -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, +- 135, 47, -1, 138 ++ 8, 19, 23, 24, 25, 18, 19, 26, 16, 8, ++ 9, 13, 18, 19, 3, 5, 22, 23, 23, 99, ++ 33, 26, 102, 0, 30, 44, 45, 33, 46, 47, ++ 43, 30, 22, 46, 47, 37, 14, 36, 22, 18, ++ 19, 25, 25, 21, 22, 23, 24, 68, 69, 70, ++ 34, 10, 11, 31, 33, 20, 74, 22, 36, 16, ++ 4, 15, 16, 17, 25, 22, 23, 32, 22, 26, ++ 25, 27, 27, 35, 29, 60, 61, 62, 63, 12, ++ 98, 6, 7, 25, 42, 43, 34, 35, 58, 59, ++ 64, 65, 39, 66, 67, 40, 23, 23, 41, 38, ++ 17, 25, 17, 25, 25, 28, 25, 18, 36, 21, ++ 3, 11, 9, 33, 105, 53, 34, 52, 54, 35, ++ 57, 55, 102, 99, 132, 56, -1, -1, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, 145, -1, -1, ++ 148 + }; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ + static const yytype_uint8 yystos[] = + { +- 0, 3, 48, 24, 0, 4, 21, 49, 50, 17, +- 18, 32, 58, 50, 25, 51, 49, 42, 45, 46, +- 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, +- 68, 69, 70, 71, 58, 26, 52, 15, 22, 25, +- 71, 71, 71, 34, 12, 36, 11, 38, 39, 40, +- 9, 10, 7, 8, 29, 35, 5, 6, 41, 42, +- 25, 43, 44, 24, 53, 22, 52, 52, 62, 59, +- 63, 64, 65, 66, 67, 67, 68, 68, 68, 68, +- 69, 69, 70, 70, 71, 71, 71, 14, 15, 16, +- 21, 54, 73, 74, 24, 37, 16, 16, 24, 28, +- 52, 54, 74, 27, 54, 73, 60, 24, 24, 55, +- 56, 24, 21, 24, 33, 13, 20, 21, 22, 23, +- 30, 35, 57, 17, 32, 72, 21, 22, 29, 58, +- 35, 20, 19, 21, 31, 33, 34, 58, 33, 58, +- 34 ++ 0, 3, 49, 50, 51, 25, 0, 51, 5, 22, ++ 52, 53, 4, 18, 19, 33, 61, 53, 23, 26, ++ 54, 52, 25, 43, 46, 47, 61, 62, 63, 64, ++ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, ++ 61, 27, 55, 55, 16, 22, 23, 26, 74, 74, ++ 74, 35, 13, 37, 12, 39, 40, 41, 10, 11, ++ 8, 9, 30, 36, 6, 7, 42, 43, 26, 44, ++ 45, 25, 56, 23, 23, 55, 55, 65, 62, 66, ++ 67, 68, 69, 70, 70, 71, 71, 71, 71, 72, ++ 72, 73, 73, 74, 74, 74, 15, 16, 17, 22, ++ 57, 76, 77, 25, 55, 38, 17, 17, 25, 29, ++ 55, 57, 77, 28, 57, 76, 63, 25, 25, 58, ++ 59, 25, 22, 25, 34, 14, 21, 22, 23, 24, ++ 31, 36, 60, 18, 33, 75, 22, 23, 30, 61, ++ 36, 21, 20, 22, 32, 34, 35, 61, 34, 61, ++ 35 + }; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ + static const yytype_uint8 yyr1[] = + { +- 0, 47, 48, 49, 49, 50, 50, 51, 51, 51, +- 51, 52, 53, 53, 54, 54, 54, 54, 55, 55, +- 55, 55, 55, 55, 55, 56, 56, 56, 57, 57, +- 57, 57, 57, 58, 58, 58, 59, 60, 60, 61, +- 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, +- 66, 66, 67, 67, 67, 67, 67, 68, 68, 68, +- 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, +- 71, 72, 72, 72, 73, 73, 73, 74, 74, 74 ++ 0, 48, 49, 50, 50, 51, 51, 52, 52, 53, ++ 53, 54, 54, 54, 54, 54, 54, 55, 56, 56, ++ 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, ++ 58, 59, 59, 59, 60, 60, 60, 60, 60, 61, ++ 61, 61, 62, 63, 63, 64, 64, 65, 65, 66, ++ 66, 67, 67, 68, 68, 69, 69, 69, 70, 70, ++ 70, 70, 70, 71, 71, 71, 72, 72, 72, 73, ++ 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, ++ 76, 76, 76, 77, 77, 77 + }; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ + static const yytype_uint8 yyr2[] = + { +- 0, 2, 4, 0, 2, 4, 2, 2, 3, 3, +- 4, 5, 0, 2, 4, 2, 3, 2, 2, 3, +- 4, 2, 9, 5, 2, 0, 2, 2, 3, 1, +- 2, 2, 2, 1, 1, 3, 1, 1, 5, 1, +- 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, +- 3, 3, 1, 3, 3, 3, 3, 3, 3, 1, +- 3, 3, 1, 3, 3, 3, 1, 1, 2, 2, +- 2, 0, 2, 2, 0, 2, 2, 2, 3, 2 ++ 0, 2, 3, 2, 4, 1, 2, 0, 2, 4, ++ 2, 2, 3, 2, 4, 3, 4, 5, 0, 2, ++ 4, 2, 3, 2, 2, 3, 4, 2, 9, 5, ++ 2, 0, 2, 2, 3, 1, 2, 2, 2, 1, ++ 1, 3, 1, 1, 5, 1, 3, 1, 3, 1, ++ 3, 1, 3, 1, 3, 1, 3, 3, 1, 3, ++ 3, 3, 3, 3, 3, 1, 3, 3, 1, 3, ++ 3, 3, 1, 1, 2, 2, 2, 0, 2, 2, ++ 0, 2, 2, 2, 3, 2 + }; + + +@@ -1460,79 +1474,144 @@ yyreduce: + switch (yyn) + { + case 2: +-#line 105 "dtc-parser.y" /* yacc.c:1646 */ ++#line 110 "dtc-parser.y" /* yacc.c:1646 */ + { +- the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node), +- guess_boot_cpuid((yyvsp[0].node))); ++ parser_output = build_dt_info((yyvsp[-2].flags), (yyvsp[-1].re), (yyvsp[0].node), ++ guess_boot_cpuid((yyvsp[0].node))); + } +-#line 1469 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1483 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 3: +-#line 113 "dtc-parser.y" /* yacc.c:1646 */ ++#line 118 "dtc-parser.y" /* yacc.c:1646 */ + { +- (yyval.re) = NULL; ++ (yyval.flags) = DTSF_V1; + } +-#line 1477 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1491 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 4: +-#line 117 "dtc-parser.y" /* yacc.c:1646 */ ++#line 122 "dtc-parser.y" /* yacc.c:1646 */ ++ { ++ (yyval.flags) = DTSF_V1 | DTSF_PLUGIN; ++ } ++#line 1499 "dtc-parser.tab.c" /* yacc.c:1646 */ ++ break; ++ ++ case 6: ++#line 130 "dtc-parser.y" /* yacc.c:1646 */ ++ { ++ if ((yyvsp[0].flags) != (yyvsp[-1].flags)) ++ ERROR(&(yylsp[0]), "Header flags don't match earlier ones"); ++ (yyval.flags) = (yyvsp[-1].flags); ++ } ++#line 1509 "dtc-parser.tab.c" /* yacc.c:1646 */ ++ break; ++ ++ case 7: ++#line 139 "dtc-parser.y" /* yacc.c:1646 */ ++ { ++ (yyval.re) = NULL; ++ } ++#line 1517 "dtc-parser.tab.c" /* yacc.c:1646 */ ++ break; ++ ++ case 8: ++#line 143 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re)); + } +-#line 1485 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1525 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 5: +-#line 124 "dtc-parser.y" /* yacc.c:1646 */ ++ case 9: ++#line 150 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer)); + } +-#line 1493 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1533 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 6: +-#line 128 "dtc-parser.y" /* yacc.c:1646 */ ++ case 10: ++#line 154 "dtc-parser.y" /* yacc.c:1646 */ + { + add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref)); + (yyval.re) = (yyvsp[0].re); + } +-#line 1502 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1542 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 7: +-#line 136 "dtc-parser.y" /* yacc.c:1646 */ ++ case 11: ++#line 162 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.node) = name_node((yyvsp[0].node), ""); + } +-#line 1510 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1550 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 8: +-#line 140 "dtc-parser.y" /* yacc.c:1646 */ ++ case 12: ++#line 166 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node)); + } +-#line 1518 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1558 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 9: +-#line 144 "dtc-parser.y" /* yacc.c:1646 */ ++ case 13: ++#line 170 "dtc-parser.y" /* yacc.c:1646 */ + { +- struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref)); ++ /* ++ * We rely on the rule being always: ++ * versioninfo plugindecl memreserves devicetree ++ * so $-1 is what we want (plugindecl) ++ */ ++ if (!((yyvsp[(-1) - (2)].flags) & DTSF_PLUGIN)) ++ ERROR(&(yylsp[0]), "Label or path %s not found", (yyvsp[-1].labelref)); ++ (yyval.node) = add_orphan_node(name_node(build_node(NULL, NULL), ""), (yyvsp[0].node), (yyvsp[-1].labelref)); ++ } ++#line 1573 "dtc-parser.tab.c" /* yacc.c:1646 */ ++ break; + +- if (target) ++ case 14: ++#line 181 "dtc-parser.y" /* yacc.c:1646 */ ++ { ++ struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref)); ++ ++ if (target) { ++ add_label(&target->labels, (yyvsp[-2].labelref)); + merge_nodes(target, (yyvsp[0].node)); +- else ++ } else + ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref)); ++ (yyval.node) = (yyvsp[-3].node); ++ } ++#line 1588 "dtc-parser.tab.c" /* yacc.c:1646 */ ++ break; ++ ++ case 15: ++#line 192 "dtc-parser.y" /* yacc.c:1646 */ ++ { ++ struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref)); ++ ++ if (target) { ++ merge_nodes(target, (yyvsp[0].node)); ++ } else { ++ /* ++ * We rely on the rule being always: ++ * versioninfo plugindecl memreserves devicetree ++ * so $-1 is what we want (plugindecl) ++ */ ++ if ((yyvsp[(-1) - (3)].flags) & DTSF_PLUGIN) ++ add_orphan_node((yyvsp[-2].node), (yyvsp[0].node), (yyvsp[-1].labelref)); ++ else ++ ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref)); ++ } + (yyval.node) = (yyvsp[-2].node); + } +-#line 1532 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1611 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 10: +-#line 154 "dtc-parser.y" /* yacc.c:1646 */ ++ case 16: ++#line 211 "dtc-parser.y" /* yacc.c:1646 */ + { + struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref)); + +@@ -1544,100 +1623,100 @@ yyreduce: + + (yyval.node) = (yyvsp[-3].node); + } +-#line 1548 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1627 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 11: +-#line 169 "dtc-parser.y" /* yacc.c:1646 */ ++ case 17: ++#line 226 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist)); + } +-#line 1556 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1635 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 12: +-#line 176 "dtc-parser.y" /* yacc.c:1646 */ ++ case 18: ++#line 233 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.proplist) = NULL; + } +-#line 1564 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1643 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 13: +-#line 180 "dtc-parser.y" /* yacc.c:1646 */ ++ case 19: ++#line 237 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist)); + } +-#line 1572 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1651 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 14: +-#line 187 "dtc-parser.y" /* yacc.c:1646 */ ++ case 20: ++#line 244 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data)); + } +-#line 1580 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1659 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 15: +-#line 191 "dtc-parser.y" /* yacc.c:1646 */ ++ case 21: ++#line 248 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data); + } +-#line 1588 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1667 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 16: +-#line 195 "dtc-parser.y" /* yacc.c:1646 */ ++ case 22: ++#line 252 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.prop) = build_property_delete((yyvsp[-1].propnodename)); + } +-#line 1596 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 17: +-#line 199 "dtc-parser.y" /* yacc.c:1646 */ ++ case 23: ++#line 256 "dtc-parser.y" /* yacc.c:1646 */ + { + add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref)); + (yyval.prop) = (yyvsp[0].prop); + } +-#line 1605 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1684 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 18: +-#line 207 "dtc-parser.y" /* yacc.c:1646 */ ++ case 24: ++#line 264 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data)); + } +-#line 1613 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1692 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 19: +-#line 211 "dtc-parser.y" /* yacc.c:1646 */ ++ case 25: ++#line 268 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data); + } +-#line 1621 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1700 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 20: +-#line 215 "dtc-parser.y" /* yacc.c:1646 */ ++ case 26: ++#line 272 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data)); + } +-#line 1629 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1708 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 21: +-#line 219 "dtc-parser.y" /* yacc.c:1646 */ ++ case 27: ++#line 276 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref)); + } +-#line 1637 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1716 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 22: +-#line 223 "dtc-parser.y" /* yacc.c:1646 */ ++ case 28: ++#line 280 "dtc-parser.y" /* yacc.c:1646 */ + { + FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL); + struct data d; +@@ -1653,11 +1732,11 @@ yyreduce: + (yyval.data) = data_merge((yyvsp[-8].data), d); + fclose(f); + } +-#line 1657 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1736 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 23: +-#line 239 "dtc-parser.y" /* yacc.c:1646 */ ++ case 29: ++#line 296 "dtc-parser.y" /* yacc.c:1646 */ + { + FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL); + struct data d = empty_data; +@@ -1667,43 +1746,43 @@ yyreduce: + (yyval.data) = data_merge((yyvsp[-4].data), d); + fclose(f); + } +-#line 1671 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1750 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 24: +-#line 249 "dtc-parser.y" /* yacc.c:1646 */ ++ case 30: ++#line 306 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); + } +-#line 1679 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1758 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 25: +-#line 256 "dtc-parser.y" /* yacc.c:1646 */ ++ case 31: ++#line 313 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = empty_data; + } +-#line 1687 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1766 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 26: +-#line 260 "dtc-parser.y" /* yacc.c:1646 */ ++ case 32: ++#line 317 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = (yyvsp[-1].data); + } +-#line 1695 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1774 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 27: +-#line 264 "dtc-parser.y" /* yacc.c:1646 */ ++ case 33: ++#line 321 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); + } +-#line 1703 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1782 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 28: +-#line 271 "dtc-parser.y" /* yacc.c:1646 */ ++ case 34: ++#line 328 "dtc-parser.y" /* yacc.c:1646 */ + { + unsigned long long bits; + +@@ -1719,20 +1798,20 @@ yyreduce: + (yyval.array).data = empty_data; + (yyval.array).bits = bits; + } +-#line 1723 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1802 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 29: +-#line 287 "dtc-parser.y" /* yacc.c:1646 */ ++ case 35: ++#line 344 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.array).data = empty_data; + (yyval.array).bits = 32; + } +-#line 1732 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1811 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 30: +-#line 292 "dtc-parser.y" /* yacc.c:1646 */ ++ case 36: ++#line 349 "dtc-parser.y" /* yacc.c:1646 */ + { + if ((yyvsp[-1].array).bits < 64) { + uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1; +@@ -1751,11 +1830,11 @@ yyreduce: + + (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits); + } +-#line 1755 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1834 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 31: +-#line 311 "dtc-parser.y" /* yacc.c:1646 */ ++ case 37: ++#line 368 "dtc-parser.y" /* yacc.c:1646 */ + { + uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits); + +@@ -1769,233 +1848,247 @@ yyreduce: + + (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits); + } +-#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1852 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 32: +-#line 325 "dtc-parser.y" /* yacc.c:1646 */ ++ case 38: ++#line 382 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref)); + } +-#line 1781 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1860 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 35: +-#line 334 "dtc-parser.y" /* yacc.c:1646 */ ++ case 41: ++#line 391 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.integer) = (yyvsp[-1].integer); + } +-#line 1789 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1868 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 38: +-#line 345 "dtc-parser.y" /* yacc.c:1646 */ ++ case 44: ++#line 402 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); } +-#line 1795 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1874 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 40: +-#line 350 "dtc-parser.y" /* yacc.c:1646 */ ++ case 46: ++#line 407 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); } +-#line 1801 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1880 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 42: +-#line 355 "dtc-parser.y" /* yacc.c:1646 */ ++ case 48: ++#line 412 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); } +-#line 1807 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1886 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 44: +-#line 360 "dtc-parser.y" /* yacc.c:1646 */ ++ case 50: ++#line 417 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); } +-#line 1813 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1892 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 46: +-#line 365 "dtc-parser.y" /* yacc.c:1646 */ ++ case 52: ++#line 422 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); } +-#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1898 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 48: +-#line 370 "dtc-parser.y" /* yacc.c:1646 */ ++ case 54: ++#line 427 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); } +-#line 1825 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1904 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 50: +-#line 375 "dtc-parser.y" /* yacc.c:1646 */ ++ case 56: ++#line 432 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); } +-#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1910 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 51: +-#line 376 "dtc-parser.y" /* yacc.c:1646 */ ++ case 57: ++#line 433 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); } +-#line 1837 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1916 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 53: +-#line 381 "dtc-parser.y" /* yacc.c:1646 */ ++ case 59: ++#line 438 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); } +-#line 1843 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1922 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 54: +-#line 382 "dtc-parser.y" /* yacc.c:1646 */ ++ case 60: ++#line 439 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); } +-#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1928 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 55: +-#line 383 "dtc-parser.y" /* yacc.c:1646 */ ++ case 61: ++#line 440 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); } +-#line 1855 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1934 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 56: +-#line 384 "dtc-parser.y" /* yacc.c:1646 */ ++ case 62: ++#line 441 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); } +-#line 1861 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1940 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 57: +-#line 388 "dtc-parser.y" /* yacc.c:1646 */ ++ case 63: ++#line 445 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); } +-#line 1867 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1946 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 58: +-#line 389 "dtc-parser.y" /* yacc.c:1646 */ ++ case 64: ++#line 446 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); } +-#line 1873 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1952 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 60: +-#line 394 "dtc-parser.y" /* yacc.c:1646 */ ++ case 66: ++#line 451 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); } +-#line 1879 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1958 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 61: +-#line 395 "dtc-parser.y" /* yacc.c:1646 */ ++ case 67: ++#line 452 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); } +-#line 1885 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1964 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 63: +-#line 400 "dtc-parser.y" /* yacc.c:1646 */ ++ case 69: ++#line 457 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); } +-#line 1891 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 1970 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 64: +-#line 401 "dtc-parser.y" /* yacc.c:1646 */ +- { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); } +-#line 1897 "dtc-parser.tab.c" /* yacc.c:1646 */ ++ case 70: ++#line 459 "dtc-parser.y" /* yacc.c:1646 */ ++ { ++ if ((yyvsp[0].integer) != 0) { ++ (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); ++ } else { ++ ERROR(&(yyloc), "Division by zero"); ++ (yyval.integer) = 0; ++ } ++ } ++#line 1983 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 65: +-#line 402 "dtc-parser.y" /* yacc.c:1646 */ +- { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); } +-#line 1903 "dtc-parser.tab.c" /* yacc.c:1646 */ ++ case 71: ++#line 468 "dtc-parser.y" /* yacc.c:1646 */ ++ { ++ if ((yyvsp[0].integer) != 0) { ++ (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); ++ } else { ++ ERROR(&(yyloc), "Division by zero"); ++ (yyval.integer) = 0; ++ } ++ } ++#line 1996 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 68: +-#line 408 "dtc-parser.y" /* yacc.c:1646 */ ++ case 74: ++#line 481 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = -(yyvsp[0].integer); } +-#line 1909 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2002 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 69: +-#line 409 "dtc-parser.y" /* yacc.c:1646 */ ++ case 75: ++#line 482 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = ~(yyvsp[0].integer); } +-#line 1915 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2008 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 70: +-#line 410 "dtc-parser.y" /* yacc.c:1646 */ ++ case 76: ++#line 483 "dtc-parser.y" /* yacc.c:1646 */ + { (yyval.integer) = !(yyvsp[0].integer); } +-#line 1921 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2014 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 71: +-#line 415 "dtc-parser.y" /* yacc.c:1646 */ ++ case 77: ++#line 488 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = empty_data; + } +-#line 1929 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2022 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 72: +-#line 419 "dtc-parser.y" /* yacc.c:1646 */ ++ case 78: ++#line 492 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte)); + } +-#line 1937 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2030 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 73: +-#line 423 "dtc-parser.y" /* yacc.c:1646 */ ++ case 79: ++#line 496 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); + } +-#line 1945 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2038 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 74: +-#line 430 "dtc-parser.y" /* yacc.c:1646 */ ++ case 80: ++#line 503 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.nodelist) = NULL; + } +-#line 1953 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2046 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 75: +-#line 434 "dtc-parser.y" /* yacc.c:1646 */ ++ case 81: ++#line 507 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist)); + } +-#line 1961 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2054 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 76: +-#line 438 "dtc-parser.y" /* yacc.c:1646 */ ++ case 82: ++#line 511 "dtc-parser.y" /* yacc.c:1646 */ + { + ERROR(&(yylsp[0]), "Properties must precede subnodes"); + YYERROR; + } +-#line 1970 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2063 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 77: +-#line 446 "dtc-parser.y" /* yacc.c:1646 */ ++ case 83: ++#line 519 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename)); + } +-#line 1978 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2071 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 78: +-#line 450 "dtc-parser.y" /* yacc.c:1646 */ ++ case 84: ++#line 523 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename)); + } +-#line 1986 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2079 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + +- case 79: +-#line 454 "dtc-parser.y" /* yacc.c:1646 */ ++ case 85: ++#line 527 "dtc-parser.y" /* yacc.c:1646 */ + { + add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref)); + (yyval.node) = (yyvsp[0].node); + } +-#line 1995 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2088 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + +-#line 1999 "dtc-parser.tab.c" /* yacc.c:1646 */ ++#line 2092 "dtc-parser.tab.c" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires +@@ -2230,7 +2323,7 @@ yyreturn: + #endif + return yyresult; + } +-#line 460 "dtc-parser.y" /* yacc.c:1906 */ ++#line 533 "dtc-parser.y" /* yacc.c:1906 */ + + + void yyerror(char const *s) +diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped +index 30867c688..6aa512c1b 100644 +--- a/scripts/dtc/dtc-parser.tab.h_shipped ++++ b/scripts/dtc/dtc-parser.tab.h_shipped +@@ -1,8 +1,8 @@ +-/* A Bison parser, made by GNU Bison 3.0.2. */ ++/* A Bison parser, made by GNU Bison 3.0.4. */ + + /* Bison interface for Yacc-like parsers in C + +- Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. ++ Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by +@@ -46,35 +46,36 @@ extern int yydebug; + enum yytokentype + { + DT_V1 = 258, +- DT_MEMRESERVE = 259, +- DT_LSHIFT = 260, +- DT_RSHIFT = 261, +- DT_LE = 262, +- DT_GE = 263, +- DT_EQ = 264, +- DT_NE = 265, +- DT_AND = 266, +- DT_OR = 267, +- DT_BITS = 268, +- DT_DEL_PROP = 269, +- DT_DEL_NODE = 270, +- DT_PROPNODENAME = 271, +- DT_LITERAL = 272, +- DT_CHAR_LITERAL = 273, +- DT_BYTE = 274, +- DT_STRING = 275, +- DT_LABEL = 276, +- DT_REF = 277, +- DT_INCBIN = 278 ++ DT_PLUGIN = 259, ++ DT_MEMRESERVE = 260, ++ DT_LSHIFT = 261, ++ DT_RSHIFT = 262, ++ DT_LE = 263, ++ DT_GE = 264, ++ DT_EQ = 265, ++ DT_NE = 266, ++ DT_AND = 267, ++ DT_OR = 268, ++ DT_BITS = 269, ++ DT_DEL_PROP = 270, ++ DT_DEL_NODE = 271, ++ DT_PROPNODENAME = 272, ++ DT_LITERAL = 273, ++ DT_CHAR_LITERAL = 274, ++ DT_BYTE = 275, ++ DT_STRING = 276, ++ DT_LABEL = 277, ++ DT_REF = 278, ++ DT_INCBIN = 279 + }; + #endif + + /* Value type. */ + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +-typedef union YYSTYPE YYSTYPE; ++ + union YYSTYPE + { +-#line 38 "dtc-parser.y" /* yacc.c:1909 */ ++#line 39 "dtc-parser.y" /* yacc.c:1909 */ + + char *propnodename; + char *labelref; +@@ -92,9 +93,12 @@ union YYSTYPE + struct node *nodelist; + struct reserve_info *re; + uint64_t integer; ++ unsigned int flags; + +-#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */ ++#line 99 "dtc-parser.tab.h" /* yacc.c:1909 */ + }; ++ ++typedef union YYSTYPE YYSTYPE; + # define YYSTYPE_IS_TRIVIAL 1 + # define YYSTYPE_IS_DECLARED 1 + #endif +diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y +index ea57e0a05..44af170ab 100644 +--- a/scripts/dtc/dtc-parser.y ++++ b/scripts/dtc/dtc-parser.y +@@ -19,6 +19,7 @@ + */ + %{ + #include ++#include + + #include "dtc.h" + #include "srcpos.h" +@@ -31,7 +32,7 @@ extern void yyerror(char const *s); + treesource_error = true; \ + } while (0) + +-extern struct boot_info *the_boot_info; ++extern struct dt_info *parser_output; + extern bool treesource_error; + %} + +@@ -52,9 +53,11 @@ extern bool treesource_error; + struct node *nodelist; + struct reserve_info *re; + uint64_t integer; ++ unsigned int flags; + } + + %token DT_V1 ++%token DT_PLUGIN + %token DT_MEMRESERVE + %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR + %token DT_BITS +@@ -71,6 +74,8 @@ extern bool treesource_error; + + %type propdata + %type propdataprefix ++%type header ++%type headers + %type memreserve + %type memreserves + %type arrayprefix +@@ -101,10 +106,31 @@ extern bool treesource_error; + %% + + sourcefile: +- DT_V1 ';' memreserves devicetree ++ headers memreserves devicetree + { +- the_boot_info = build_boot_info($3, $4, +- guess_boot_cpuid($4)); ++ parser_output = build_dt_info($1, $2, $3, ++ guess_boot_cpuid($3)); ++ } ++ ; ++ ++header: ++ DT_V1 ';' ++ { ++ $$ = DTSF_V1; ++ } ++ | DT_V1 ';' DT_PLUGIN ';' ++ { ++ $$ = DTSF_V1 | DTSF_PLUGIN; ++ } ++ ; ++ ++headers: ++ header ++ | header headers ++ { ++ if ($2 != $1) ++ ERROR(&@2, "Header flags don't match earlier ones"); ++ $$ = $1; + } + ; + +@@ -140,14 +166,45 @@ devicetree: + { + $$ = merge_nodes($1, $3); + } ++ | DT_REF nodedef ++ { ++ /* ++ * We rely on the rule being always: ++ * versioninfo plugindecl memreserves devicetree ++ * so $-1 is what we want (plugindecl) ++ */ ++ if (!($-1 & DTSF_PLUGIN)) ++ ERROR(&@2, "Label or path %s not found", $1); ++ $$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1); ++ } ++ | devicetree DT_LABEL DT_REF nodedef ++ { ++ struct node *target = get_node_by_ref($1, $3); ++ ++ if (target) { ++ add_label(&target->labels, $2); ++ merge_nodes(target, $4); ++ } else ++ ERROR(&@3, "Label or path %s not found", $3); ++ $$ = $1; ++ } + | devicetree DT_REF nodedef + { + struct node *target = get_node_by_ref($1, $2); + +- if (target) ++ if (target) { + merge_nodes(target, $3); +- else +- ERROR(&@2, "Label or path %s not found", $2); ++ } else { ++ /* ++ * We rely on the rule being always: ++ * versioninfo plugindecl memreserves devicetree ++ * so $-1 is what we want (plugindecl) ++ */ ++ if ($-1 & DTSF_PLUGIN) ++ add_orphan_node($1, $3, $2); ++ else ++ ERROR(&@2, "Label or path %s not found", $2); ++ } + $$ = $1; + } + | devicetree DT_DEL_NODE DT_REF ';' +@@ -398,8 +455,24 @@ integer_add: + + integer_mul: + integer_mul '*' integer_unary { $$ = $1 * $3; } +- | integer_mul '/' integer_unary { $$ = $1 / $3; } +- | integer_mul '%' integer_unary { $$ = $1 % $3; } ++ | integer_mul '/' integer_unary ++ { ++ if ($3 != 0) { ++ $$ = $1 / $3; ++ } else { ++ ERROR(&@$, "Division by zero"); ++ $$ = 0; ++ } ++ } ++ | integer_mul '%' integer_unary ++ { ++ if ($3 != 0) { ++ $$ = $1 % $3; ++ } else { ++ ERROR(&@$, "Division by zero"); ++ $$ = 0; ++ } ++ } + | integer_unary + ; + +diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c +index 8c4add69a..c36994e6e 100644 +--- a/scripts/dtc/dtc.c ++++ b/scripts/dtc/dtc.c +@@ -18,6 +18,8 @@ + * USA + */ + ++#include ++ + #include "dtc.h" + #include "srcpos.h" + +@@ -28,7 +30,16 @@ int quiet; /* Level of quietness */ + int reservenum; /* Number of memory reservation slots */ + int minsize; /* Minimum blob size */ + int padsize; /* Additional padding to blob */ +-int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */ ++int alignsize; /* Additional padding to blob accroding to the alignsize */ ++int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */ ++int generate_symbols; /* enable symbols & fixup support */ ++int generate_fixups; /* suppress generation of fixups on symbol support */ ++int auto_label_aliases; /* auto generate labels -> aliases */ ++ ++static int is_power_of_2(int x) ++{ ++ return (x > 0) && ((x & (x - 1)) == 0); ++} + + static void fill_fullpaths(struct node *tree, const char *prefix) + { +@@ -48,10 +59,8 @@ static void fill_fullpaths(struct node *tree, const char *prefix) + } + + /* Usage related data. */ +-#define FDT_VERSION(version) _FDT_VERSION(version) +-#define _FDT_VERSION(version) #version + static const char usage_synopsis[] = "dtc [options] "; +-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv"; ++static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv"; + static struct option const usage_long_opts[] = { + {"quiet", no_argument, NULL, 'q'}, + {"in-format", a_argument, NULL, 'I'}, +@@ -62,6 +71,7 @@ static struct option const usage_long_opts[] = { + {"reserve", a_argument, NULL, 'R'}, + {"space", a_argument, NULL, 'S'}, + {"pad", a_argument, NULL, 'p'}, ++ {"align", a_argument, NULL, 'a'}, + {"boot-cpu", a_argument, NULL, 'b'}, + {"force", no_argument, NULL, 'f'}, + {"include", a_argument, NULL, 'i'}, +@@ -69,6 +79,8 @@ static struct option const usage_long_opts[] = { + {"phandle", a_argument, NULL, 'H'}, + {"warning", a_argument, NULL, 'W'}, + {"error", a_argument, NULL, 'E'}, ++ {"symbols", no_argument, NULL, '@'}, ++ {"auto-alias", no_argument, NULL, 'A'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {NULL, no_argument, NULL, 0x0}, +@@ -84,11 +96,12 @@ static const char * const usage_opts_help[] = { + "\t\tdts - device tree source text\n" + "\t\tdtb - device tree blob\n" + "\t\tasm - assembler source", +- "\n\tBlob version to produce, defaults to "FDT_VERSION(DEFAULT_FDT_VERSION)" (for dtb and asm output)", ++ "\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)", + "\n\tOutput dependency file", + "\n\tMake space for reserve map entries (for dtb and asm output)", + "\n\tMake the blob at least long (extra space)", + "\n\tAdd padding to the blob of long (extra space)", ++ "\n\tMake the blob align to the (extra space)", + "\n\tSet the physical boot cpu", + "\n\tTry to produce output even if the input tree has errors", + "\n\tAdd a path to search for include files", +@@ -99,16 +112,62 @@ static const char * const usage_opts_help[] = { + "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties", + "\n\tEnable/disable warnings (prefix with \"no-\")", + "\n\tEnable/disable errors (prefix with \"no-\")", ++ "\n\tEnable generation of symbols", ++ "\n\tEnable auto-alias of labels", + "\n\tPrint this help and exit", + "\n\tPrint version and exit", + NULL, + }; + ++static const char *guess_type_by_name(const char *fname, const char *fallback) ++{ ++ const char *s; ++ ++ s = strrchr(fname, '.'); ++ if (s == NULL) ++ return fallback; ++ if (!strcasecmp(s, ".dts")) ++ return "dts"; ++ if (!strcasecmp(s, ".dtb")) ++ return "dtb"; ++ return fallback; ++} ++ ++static const char *guess_input_format(const char *fname, const char *fallback) ++{ ++ struct stat statbuf; ++ fdt32_t magic; ++ FILE *f; ++ ++ if (stat(fname, &statbuf) != 0) ++ return fallback; ++ ++ if (S_ISDIR(statbuf.st_mode)) ++ return "fs"; ++ ++ if (!S_ISREG(statbuf.st_mode)) ++ return fallback; ++ ++ f = fopen(fname, "r"); ++ if (f == NULL) ++ return fallback; ++ if (fread(&magic, 4, 1, f) != 1) { ++ fclose(f); ++ return fallback; ++ } ++ fclose(f); ++ ++ if (fdt32_to_cpu(magic) == FDT_MAGIC) ++ return "dtb"; ++ ++ return guess_type_by_name(fname, fallback); ++} ++ + int main(int argc, char *argv[]) + { +- struct boot_info *bi; +- const char *inform = "dts"; +- const char *outform = "dts"; ++ struct dt_info *dti; ++ const char *inform = NULL; ++ const char *outform = NULL; + const char *outname = "-"; + const char *depname = NULL; + bool force = false, sort = false; +@@ -122,6 +181,7 @@ int main(int argc, char *argv[]) + reservenum = 0; + minsize = 0; + padsize = 0; ++ alignsize = 0; + + while ((opt = util_getopt_long()) != EOF) { + switch (opt) { +@@ -149,6 +209,12 @@ int main(int argc, char *argv[]) + case 'p': + padsize = strtol(optarg, NULL, 0); + break; ++ case 'a': ++ alignsize = strtol(optarg, NULL, 0); ++ if (!is_power_of_2(alignsize)) ++ die("Invalid argument \"%d\" to -a option\n", ++ alignsize); ++ break; + case 'f': + force = true; + break; +@@ -187,6 +253,13 @@ int main(int argc, char *argv[]) + parse_checks_option(false, true, optarg); + break; + ++ case '@': ++ generate_symbols = 1; ++ break; ++ case 'A': ++ auto_label_aliases = 1; ++ break; ++ + case 'h': + usage(NULL); + default: +@@ -213,28 +286,58 @@ int main(int argc, char *argv[]) + fprintf(depfile, "%s:", outname); + } + ++ if (inform == NULL) ++ inform = guess_input_format(arg, "dts"); ++ if (outform == NULL) { ++ outform = guess_type_by_name(outname, NULL); ++ if (outform == NULL) { ++ if (streq(inform, "dts")) ++ outform = "dtb"; ++ else ++ outform = "dts"; ++ } ++ } + if (streq(inform, "dts")) +- bi = dt_from_source(arg); ++ dti = dt_from_source(arg); + else if (streq(inform, "fs")) +- bi = dt_from_fs(arg); ++ dti = dt_from_fs(arg); + else if(streq(inform, "dtb")) +- bi = dt_from_blob(arg); ++ dti = dt_from_blob(arg); + else + die("Unknown input format \"%s\"\n", inform); + ++ dti->outname = outname; ++ + if (depfile) { + fputc('\n', depfile); + fclose(depfile); + } + + if (cmdline_boot_cpuid != -1) +- bi->boot_cpuid_phys = cmdline_boot_cpuid; ++ dti->boot_cpuid_phys = cmdline_boot_cpuid; ++ ++ fill_fullpaths(dti->dt, ""); ++ ++ /* on a plugin, generate by default */ ++ if (dti->dtsflags & DTSF_PLUGIN) { ++ generate_fixups = 1; ++ } + +- fill_fullpaths(bi->dt, ""); +- process_checks(force, bi); ++ process_checks(force, dti); ++ ++ if (auto_label_aliases) ++ generate_label_tree(dti, "aliases", false); ++ ++ if (generate_symbols) ++ generate_label_tree(dti, "__symbols__", true); ++ ++ if (generate_fixups) { ++ generate_fixups_tree(dti, "__fixups__"); ++ generate_local_fixups_tree(dti, "__local_fixups__"); ++ } + + if (sort) +- sort_tree(bi); ++ sort_tree(dti); + + if (streq(outname, "-")) { + outf = stdout; +@@ -246,11 +349,11 @@ int main(int argc, char *argv[]) + } + + if (streq(outform, "dts")) { +- dt_to_source(outf, bi); ++ dt_to_source(outf, dti); + } else if (streq(outform, "dtb")) { +- dt_to_blob(outf, bi, outversion); ++ dt_to_blob(outf, dti, outversion); + } else if (streq(outform, "asm")) { +- dt_to_asm(outf, bi, outversion); ++ dt_to_asm(outf, dti, outversion); + } else if (streq(outform, "null")) { + /* do nothing */ + } else { +diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h +index 56212c8df..3b18a42b8 100644 +--- a/scripts/dtc/dtc.h ++++ b/scripts/dtc/dtc.h +@@ -1,5 +1,5 @@ +-#ifndef _DTC_H +-#define _DTC_H ++#ifndef DTC_H ++#define DTC_H + + /* + * (C) Copyright David Gibson , IBM Corporation. 2005. +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -43,7 +44,6 @@ + #define debug(...) + #endif + +- + #define DEFAULT_FDT_VERSION 17 + + /* +@@ -53,7 +53,11 @@ extern int quiet; /* Level of quietness */ + extern int reservenum; /* Number of memory reservation slots */ + extern int minsize; /* Minimum blob size */ + extern int padsize; /* Additional padding to blob */ ++extern int alignsize; /* Additional padding to blob accroding to the alignsize */ + extern int phandle_format; /* Use linux,phandle or phandle properties */ ++extern int generate_symbols; /* generate symbols for nodes with labels */ ++extern int generate_fixups; /* generate fixups */ ++extern int auto_label_aliases; /* auto generate labels -> aliases */ + + #define PHANDLE_LEGACY 0x1 + #define PHANDLE_EPAPR 0x2 +@@ -63,7 +67,8 @@ typedef uint32_t cell_t; + + + #define streq(a, b) (strcmp((a), (b)) == 0) +-#define strneq(a, b, n) (strncmp((a), (b), (n)) == 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 ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +@@ -110,7 +115,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m, + 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_integer(struct data d, uint64_t word, int bits); +-struct data data_append_re(struct data d, const struct fdt_reserve_entry *re); ++struct data data_append_re(struct data d, uint64_t address, uint64_t size); + struct data data_append_addr(struct data d, uint64_t addr); + struct data data_append_byte(struct data d, uint8_t byte); + struct data data_append_zeroes(struct data d, int len); +@@ -132,6 +137,10 @@ struct label { + struct label *next; + }; + ++struct bus_type { ++ const char *name; ++}; ++ + struct property { + bool deleted; + char *name; +@@ -158,6 +167,7 @@ struct node { + int addr_cells, size_cells; + + struct label *labels; ++ const struct bus_type *bus; + }; + + #define for_each_label_withdel(l0, l) \ +@@ -194,6 +204,7 @@ struct node *build_node_delete(void); + struct node *name_node(struct node *node, char *name); + struct node *chain_node(struct node *first, struct node *list); + struct node *merge_nodes(struct node *old_node, struct node *new_node); ++struct node *add_orphan_node(struct node *old_node, struct node *new_node, char *ref); + + void add_property(struct node *node, struct property *prop); + void delete_property_by_name(struct node *node, char *name); +@@ -201,10 +212,13 @@ void delete_property(struct property *prop); + void add_child(struct node *parent, struct node *child); + void delete_node_by_name(struct node *parent, char *name); + void delete_node(struct node *node); ++void append_to_property(struct node *node, ++ char *name, const void *data, int len); + + const char *get_unitname(struct node *node); + struct property *get_property(struct node *node, const char *propname); + cell_t propval_cell(struct property *prop); ++cell_t propval_cell_n(struct property *prop, int n); + struct property *get_property_by_label(struct node *tree, const char *label, + struct node **node); + struct marker *get_marker_label(struct node *tree, const char *label, +@@ -221,7 +235,7 @@ uint32_t guess_boot_cpuid(struct node *tree); + /* Boot info (tree plus memreserve information */ + + struct reserve_info { +- struct fdt_reserve_entry re; ++ uint64_t address, size; + + struct reserve_info *next; + +@@ -235,35 +249,45 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, + struct reserve_info *new); + + +-struct boot_info { ++struct dt_info { ++ unsigned int dtsflags; + struct reserve_info *reservelist; +- struct node *dt; /* the device tree */ + uint32_t boot_cpuid_phys; ++ struct node *dt; /* the device tree */ ++ const char *outname; /* filename being written to, "-" for stdout */ + }; + +-struct boot_info *build_boot_info(struct reserve_info *reservelist, +- struct node *tree, uint32_t boot_cpuid_phys); +-void sort_tree(struct boot_info *bi); ++/* DTS version flags definitions */ ++#define DTSF_V1 0x0001 /* /dts-v1/ */ ++#define DTSF_PLUGIN 0x0002 /* /plugin/ */ ++ ++struct dt_info *build_dt_info(unsigned int dtsflags, ++ struct reserve_info *reservelist, ++ struct node *tree, uint32_t boot_cpuid_phys); ++void sort_tree(struct dt_info *dti); ++void generate_label_tree(struct dt_info *dti, char *name, bool allocph); ++void generate_fixups_tree(struct dt_info *dti, char *name); ++void generate_local_fixups_tree(struct dt_info *dti, char *name); + + /* Checks */ + + void parse_checks_option(bool warn, bool error, const char *arg); +-void process_checks(bool force, struct boot_info *bi); ++void process_checks(bool force, struct dt_info *dti); + + /* Flattened trees */ + +-void dt_to_blob(FILE *f, struct boot_info *bi, int version); +-void dt_to_asm(FILE *f, struct boot_info *bi, int version); ++void dt_to_blob(FILE *f, struct dt_info *dti, int version); ++void dt_to_asm(FILE *f, struct dt_info *dti, int version); + +-struct boot_info *dt_from_blob(const char *fname); ++struct dt_info *dt_from_blob(const char *fname); + + /* Tree source */ + +-void dt_to_source(FILE *f, struct boot_info *bi); +-struct boot_info *dt_from_source(const char *f); ++void dt_to_source(FILE *f, struct dt_info *dti); ++struct dt_info *dt_from_source(const char *f); + + /* FS trees */ + +-struct boot_info *dt_from_fs(const char *dirname); ++struct dt_info *dt_from_fs(const char *dirname); + +-#endif /* _DTC_H */ ++#endif /* DTC_H */ +diff --git a/scripts/dtc/fdt.c b/scripts/dtc/fdt.c +index 2ce6a4417..7855a1787 100644 +--- a/scripts/dtc/fdt.c ++++ b/scripts/dtc/fdt.c +@@ -76,18 +76,19 @@ int fdt_check_header(const void *fdt) + + const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) + { +- const char *p; ++ unsigned absoffset = offset + fdt_off_dt_struct(fdt); ++ ++ if ((absoffset < offset) ++ || ((absoffset + len) < absoffset) ++ || (absoffset + len) > fdt_totalsize(fdt)) ++ return NULL; + + if (fdt_version(fdt) >= 0x11) + if (((offset + len) < offset) + || ((offset + len) > fdt_size_dt_struct(fdt))) + return NULL; + +- p = _fdt_offset_ptr(fdt, offset); +- +- if (p + len < p) +- return NULL; +- return p; ++ return fdt_offset_ptr_(fdt, offset); + } + + uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) +@@ -122,6 +123,9 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + + fdt32_to_cpu(*lenp); ++ if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && ++ ((offset - fdt32_to_cpu(*lenp)) % 8) != 0) ++ offset += 4; + break; + + case FDT_END: +@@ -140,7 +144,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) + return tag; + } + +-int _fdt_check_node_offset(const void *fdt, int offset) ++int fdt_check_node_offset_(const void *fdt, int offset) + { + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) +@@ -149,7 +153,7 @@ int _fdt_check_node_offset(const void *fdt, int offset) + return 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) + || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) +@@ -164,7 +168,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth) + uint32_t tag; + + if (offset >= 0) +- if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) ++ if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0) + return nextoffset; + + do { +@@ -226,7 +230,7 @@ int fdt_next_subnode(const void *fdt, int offset) + return offset; + } + +-const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) ++const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) + { + int len = strlen(s) + 1; + const char *last = strtab + tabsize - len; +diff --git a/scripts/dtc/fdt.h b/scripts/dtc/fdt.h +index 526aedb51..74961f902 100644 +--- a/scripts/dtc/fdt.h ++++ b/scripts/dtc/fdt.h +@@ -1,5 +1,5 @@ +-#ifndef _FDT_H +-#define _FDT_H ++#ifndef FDT_H ++#define FDT_H + /* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. +@@ -108,4 +108,4 @@ struct fdt_property { + #define FDT_V16_SIZE FDT_V3_SIZE + #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) + +-#endif /* _FDT_H */ ++#endif /* FDT_H */ +diff --git a/scripts/dtc/fdt_empty_tree.c b/scripts/dtc/fdt_empty_tree.c +index f72d13b1d..f2ae9b77c 100644 +--- a/scripts/dtc/fdt_empty_tree.c ++++ b/scripts/dtc/fdt_empty_tree.c +@@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize) + + return fdt_open_into(buf, buf, bufsize); + } +- +diff --git a/scripts/dtc/fdt_ro.c b/scripts/dtc/fdt_ro.c +index 50007f61c..dfb3236da 100644 +--- a/scripts/dtc/fdt_ro.c ++++ b/scripts/dtc/fdt_ro.c +@@ -55,12 +55,13 @@ + + #include "libfdt_internal.h" + +-static int _fdt_nodename_eq(const void *fdt, int offset, ++static int fdt_nodename_eq_(const void *fdt, int offset, + const char *s, int len) + { +- const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); ++ int olen; ++ const char *p = fdt_get_name(fdt, offset, &olen); + +- if (! p) ++ if (!p || olen < len) + /* short match */ + return 0; + +@@ -80,7 +81,7 @@ const char *fdt_string(const void *fdt, int stroffset) + return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; + } + +-static int _fdt_string_eq(const void *fdt, int stroffset, ++static int fdt_string_eq_(const void *fdt, int stroffset, + const char *s, int len) + { + const char *p = fdt_string(fdt, stroffset); +@@ -88,11 +89,37 @@ static int _fdt_string_eq(const void *fdt, int stroffset, + return (strlen(p) == len) && (memcmp(p, s, len) == 0); + } + ++uint32_t fdt_get_max_phandle(const void *fdt) ++{ ++ uint32_t max_phandle = 0; ++ int offset; ++ ++ for (offset = fdt_next_node(fdt, -1, NULL);; ++ offset = fdt_next_node(fdt, offset, NULL)) { ++ uint32_t phandle; ++ ++ if (offset == -FDT_ERR_NOTFOUND) ++ return max_phandle; ++ ++ if (offset < 0) ++ return (uint32_t)-1; ++ ++ phandle = fdt_get_phandle(fdt, offset); ++ if (phandle == (uint32_t)-1) ++ continue; ++ ++ if (phandle > max_phandle) ++ max_phandle = phandle; ++ } ++ ++ return 0; ++} ++ + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) + { + FDT_CHECK_HEADER(fdt); +- *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); +- *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); ++ *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address); ++ *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); + return 0; + } + +@@ -100,12 +127,12 @@ int fdt_num_mem_rsv(const void *fdt) + { + int i = 0; + +- while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) ++ while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0) + i++; + return i; + } + +-static int _nextprop(const void *fdt, int offset) ++static int nextprop_(const void *fdt, int offset) + { + uint32_t tag; + int nextoffset; +@@ -140,7 +167,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) +- && _fdt_nodename_eq(fdt, offset, name, namelen)) ++ && fdt_nodename_eq_(fdt, offset, name, namelen)) + return offset; + + if (depth < 0) +@@ -154,9 +181,9 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, + return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); + } + +-int fdt_path_offset(const void *fdt, const char *path) ++int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) + { +- const char *end = path + strlen(path); ++ const char *end = path + namelen; + const char *p = path; + int offset = 0; + +@@ -164,7 +191,7 @@ int fdt_path_offset(const void *fdt, const char *path) + + /* see if we have an alias */ + if (*path != '/') { +- const char *q = strchr(path, '/'); ++ const char *q = memchr(path, '/', end - p); + + if (!q) + q = end; +@@ -177,14 +204,15 @@ int fdt_path_offset(const void *fdt, const char *path) + p = q; + } + +- while (*p) { ++ while (p < end) { + const char *q; + +- while (*p == '/') ++ while (*p == '/') { + p++; +- if (! *p) +- return offset; +- q = strchr(p, '/'); ++ if (p == end) ++ return offset; ++ } ++ q = memchr(p, '/', end - p); + if (! q) + q = end; + +@@ -198,19 +226,42 @@ int fdt_path_offset(const void *fdt, const char *path) + return offset; + } + ++int fdt_path_offset(const void *fdt, const char *path) ++{ ++ return fdt_path_offset_namelen(fdt, path, strlen(path)); ++} ++ + const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) + { +- const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); ++ const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); ++ const char *nameptr; + int err; + + if (((err = fdt_check_header(fdt)) != 0) +- || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) ++ || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) + goto fail; + ++ nameptr = nh->name; ++ ++ if (fdt_version(fdt) < 0x10) { ++ /* ++ * For old FDT versions, match the naming conventions of V16: ++ * give only the leaf name (after all /). The actual tree ++ * contents are loosely checked. ++ */ ++ const char *leaf; ++ leaf = strrchr(nameptr, '/'); ++ if (leaf == NULL) { ++ err = -FDT_ERR_BADSTRUCTURE; ++ goto fail; ++ } ++ nameptr = leaf+1; ++ } ++ + if (len) +- *len = strlen(nh->name); ++ *len = strlen(nameptr); + +- return nh->name; ++ return nameptr; + + fail: + if (len) +@@ -222,34 +273,34 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset) + { + int offset; + +- if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) ++ if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) + return offset; + +- return _nextprop(fdt, offset); ++ return nextprop_(fdt, offset); + } + + int fdt_next_property_offset(const void *fdt, int offset) + { +- if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) ++ if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) + return offset; + +- return _nextprop(fdt, offset); ++ return nextprop_(fdt, offset); + } + +-const struct fdt_property *fdt_get_property_by_offset(const void *fdt, +- int offset, +- int *lenp) ++static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, ++ int offset, ++ int *lenp) + { + int err; + const struct fdt_property *prop; + +- if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { ++ if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } + +- prop = _fdt_offset_ptr(fdt, offset); ++ prop = fdt_offset_ptr_(fdt, offset); + + if (lenp) + *lenp = fdt32_to_cpu(prop->len); +@@ -257,23 +308,44 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + return prop; + } + +-const struct fdt_property *fdt_get_property_namelen(const void *fdt, +- int offset, +- const char *name, +- int namelen, int *lenp) ++const struct fdt_property *fdt_get_property_by_offset(const void *fdt, ++ int offset, ++ int *lenp) ++{ ++ /* Prior to version 16, properties may need realignment ++ * and this API does not work. fdt_getprop_*() will, however. */ ++ ++ if (fdt_version(fdt) < 0x10) { ++ if (lenp) ++ *lenp = -FDT_ERR_BADVERSION; ++ return NULL; ++ } ++ ++ return fdt_get_property_by_offset_(fdt, offset, lenp); ++} ++ ++static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, ++ int offset, ++ const char *name, ++ int namelen, ++ int *lenp, ++ int *poffset) + { + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; + +- if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { ++ if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) { + offset = -FDT_ERR_INTERNAL; + break; + } +- if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), +- name, namelen)) ++ if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), ++ name, namelen)) { ++ if (poffset) ++ *poffset = offset; + return prop; ++ } + } + + if (lenp) +@@ -281,6 +353,25 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, + return NULL; + } + ++ ++const struct fdt_property *fdt_get_property_namelen(const void *fdt, ++ int offset, ++ const char *name, ++ int namelen, int *lenp) ++{ ++ /* Prior to version 16, properties may need realignment ++ * and this API does not work. fdt_getprop_*() will, however. */ ++ if (fdt_version(fdt) < 0x10) { ++ if (lenp) ++ *lenp = -FDT_ERR_BADVERSION; ++ return NULL; ++ } ++ ++ return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp, ++ NULL); ++} ++ ++ + const struct fdt_property *fdt_get_property(const void *fdt, + int nodeoffset, + const char *name, int *lenp) +@@ -292,12 +383,18 @@ const struct fdt_property *fdt_get_property(const void *fdt, + const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) + { ++ int poffset; + const struct fdt_property *prop; + +- prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); +- if (! prop) ++ prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, ++ &poffset); ++ if (!prop) + return NULL; + ++ /* Handle realignment */ ++ if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && ++ fdt32_to_cpu(prop->len) >= 8) ++ return prop->data + 4; + return prop->data; + } + +@@ -306,11 +403,16 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, + { + const struct fdt_property *prop; + +- prop = fdt_get_property_by_offset(fdt, offset, lenp); ++ prop = fdt_get_property_by_offset_(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) + *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); ++ ++ /* Handle realignment */ ++ if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && ++ fdt32_to_cpu(prop->len) >= 8) ++ return prop->data + 4; + return prop->data; + } + +@@ -532,6 +634,106 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) + return 0; + } + ++int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) ++{ ++ const char *list, *end; ++ int length, count = 0; ++ ++ list = fdt_getprop(fdt, nodeoffset, property, &length); ++ if (!list) ++ return length; ++ ++ end = list + length; ++ ++ while (list < end) { ++ length = strnlen(list, end - list) + 1; ++ ++ /* Abort if the last string isn't properly NUL-terminated. */ ++ if (list + length > end) ++ return -FDT_ERR_BADVALUE; ++ ++ list += length; ++ count++; ++ } ++ ++ return count; ++} ++ ++int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, ++ const char *string) ++{ ++ int length, len, idx = 0; ++ const char *list, *end; ++ ++ list = fdt_getprop(fdt, nodeoffset, property, &length); ++ if (!list) ++ return length; ++ ++ len = strlen(string) + 1; ++ end = list + length; ++ ++ while (list < end) { ++ length = strnlen(list, end - list) + 1; ++ ++ /* Abort if the last string isn't properly NUL-terminated. */ ++ if (list + length > end) ++ return -FDT_ERR_BADVALUE; ++ ++ if (length == len && memcmp(list, string, length) == 0) ++ return idx; ++ ++ list += length; ++ idx++; ++ } ++ ++ return -FDT_ERR_NOTFOUND; ++} ++ ++const char *fdt_stringlist_get(const void *fdt, int nodeoffset, ++ const char *property, int idx, ++ int *lenp) ++{ ++ const char *list, *end; ++ int length; ++ ++ list = fdt_getprop(fdt, nodeoffset, property, &length); ++ if (!list) { ++ if (lenp) ++ *lenp = length; ++ ++ return NULL; ++ } ++ ++ end = list + length; ++ ++ while (list < end) { ++ length = strnlen(list, end - list) + 1; ++ ++ /* Abort if the last string isn't properly NUL-terminated. */ ++ if (list + length > end) { ++ if (lenp) ++ *lenp = -FDT_ERR_BADVALUE; ++ ++ return NULL; ++ } ++ ++ if (idx == 0) { ++ if (lenp) ++ *lenp = length - 1; ++ ++ return list; ++ } ++ ++ list += length; ++ idx--; ++ } ++ ++ if (lenp) ++ *lenp = -FDT_ERR_NOTFOUND; ++ ++ return NULL; ++} ++ + int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible) + { +@@ -541,10 +743,8 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, + prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; +- if (fdt_stringlist_contains(prop, len, compatible)) +- return 0; +- else +- return 1; ++ ++ return !fdt_stringlist_contains(prop, len, compatible); + } + + int fdt_node_offset_by_compatible(const void *fdt, int startoffset, +diff --git a/scripts/dtc/fdt_rw.c b/scripts/dtc/fdt_rw.c +index 70adec6c3..9b829051e 100644 +--- a/scripts/dtc/fdt_rw.c ++++ b/scripts/dtc/fdt_rw.c +@@ -55,8 +55,8 @@ + + #include "libfdt_internal.h" + +-static int _fdt_blocks_misordered(const void *fdt, +- int mem_rsv_size, int struct_size) ++static int fdt_blocks_misordered_(const void *fdt, ++ int mem_rsv_size, int struct_size) + { + return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) + || (fdt_off_dt_struct(fdt) < +@@ -67,13 +67,13 @@ static int _fdt_blocks_misordered(const void *fdt, + (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); + } + +-static int _fdt_rw_check_header(void *fdt) ++static int fdt_rw_check_header_(void *fdt) + { + FDT_CHECK_HEADER(fdt); + + if (fdt_version(fdt) < 17) + return -FDT_ERR_BADVERSION; +- if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), ++ if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_BADLAYOUT; + if (fdt_version(fdt) > 17) +@@ -84,35 +84,37 @@ static int _fdt_rw_check_header(void *fdt) + + #define FDT_RW_CHECK_HEADER(fdt) \ + { \ +- int __err; \ +- if ((__err = _fdt_rw_check_header(fdt)) != 0) \ +- return __err; \ ++ int err_; \ ++ if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ ++ return err_; \ + } + +-static inline int _fdt_data_size(void *fdt) ++static inline int fdt_data_size_(void *fdt) + { + return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + } + +-static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) ++static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) + { + char *p = splicepoint; +- char *end = (char *)fdt + _fdt_data_size(fdt); ++ char *end = (char *)fdt + fdt_data_size_(fdt); + + if (((p + oldlen) < p) || ((p + oldlen) > end)) + return -FDT_ERR_BADOFFSET; ++ if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) ++ return -FDT_ERR_BADOFFSET; + if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) + return -FDT_ERR_NOSPACE; + memmove(p + newlen, p + oldlen, end - p - oldlen); + return 0; + } + +-static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, ++static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p, + int oldn, int newn) + { + int delta = (newn - oldn) * sizeof(*p); + int err; +- err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); ++ err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); + if (err) + return err; + fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); +@@ -120,13 +122,13 @@ static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, + return 0; + } + +-static int _fdt_splice_struct(void *fdt, void *p, ++static int fdt_splice_struct_(void *fdt, void *p, + int oldlen, int newlen) + { + int delta = newlen - oldlen; + int err; + +- if ((err = _fdt_splice(fdt, p, oldlen, newlen))) ++ if ((err = fdt_splice_(fdt, p, oldlen, newlen))) + return err; + + fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); +@@ -134,20 +136,20 @@ static int _fdt_splice_struct(void *fdt, void *p, + return 0; + } + +-static int _fdt_splice_string(void *fdt, int newlen) ++static int fdt_splice_string_(void *fdt, int newlen) + { + void *p = (char *)fdt + + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + int err; + +- if ((err = _fdt_splice(fdt, p, 0, newlen))) ++ if ((err = fdt_splice_(fdt, p, 0, newlen))) + return err; + + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); + return 0; + } + +-static int _fdt_find_add_string(void *fdt, const char *s) ++static int fdt_find_add_string_(void *fdt, const char *s) + { + char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); + const char *p; +@@ -155,13 +157,13 @@ static int _fdt_find_add_string(void *fdt, const char *s) + int len = strlen(s) + 1; + int err; + +- p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); ++ p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); + if (p) + /* found it */ + return (p - strtab); + + new = strtab + fdt_size_dt_strings(fdt); +- err = _fdt_splice_string(fdt, len); ++ err = fdt_splice_string_(fdt, len); + if (err) + return err; + +@@ -176,8 +178,8 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) + + FDT_RW_CHECK_HEADER(fdt); + +- re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); +- err = _fdt_splice_mem_rsv(fdt, re, 0, 1); ++ re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); ++ err = fdt_splice_mem_rsv_(fdt, re, 0, 1); + if (err) + return err; + +@@ -188,31 +190,27 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) + + int fdt_del_mem_rsv(void *fdt, int n) + { +- struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); +- int err; ++ struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); + + FDT_RW_CHECK_HEADER(fdt); + + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; + +- err = _fdt_splice_mem_rsv(fdt, re, 1, 0); +- if (err) +- return err; +- return 0; ++ return fdt_splice_mem_rsv_(fdt, re, 1, 0); + } + +-static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, ++static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) + { + int oldlen; + int err; + + *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); +- if (! (*prop)) ++ if (!*prop) + return oldlen; + +- if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), ++ if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(len)))) + return err; + +@@ -220,7 +218,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, + return 0; + } + +-static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, ++static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) + { + int proplen; +@@ -228,17 +226,17 @@ static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, + int namestroff; + int err; + +- if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) ++ if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) + return nextoffset; + +- namestroff = _fdt_find_add_string(fdt, name); ++ namestroff = fdt_find_add_string_(fdt, name); + if (namestroff < 0) + return namestroff; + +- *prop = _fdt_offset_ptr_w(fdt, nextoffset); ++ *prop = fdt_offset_ptr_w_(fdt, nextoffset); + proplen = sizeof(**prop) + FDT_TAGALIGN(len); + +- err = _fdt_splice_struct(fdt, *prop, 0, proplen); ++ err = fdt_splice_struct_(fdt, *prop, 0, proplen); + if (err) + return err; + +@@ -262,7 +260,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) + + newlen = strlen(name); + +- err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), ++ err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1), + FDT_TAGALIGN(newlen+1)); + if (err) + return err; +@@ -271,21 +269,36 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) + return 0; + } + +-int fdt_setprop(void *fdt, int nodeoffset, const char *name, +- const void *val, int len) ++int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, ++ int len, void **prop_data) + { + struct fdt_property *prop; + int err; + + FDT_RW_CHECK_HEADER(fdt); + +- err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); ++ err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); + if (err == -FDT_ERR_NOTFOUND) +- err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); ++ err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); ++ if (err) ++ return err; ++ ++ *prop_data = prop->data; ++ return 0; ++} ++ ++int fdt_setprop(void *fdt, int nodeoffset, const char *name, ++ const void *val, int len) ++{ ++ void *prop_data; ++ int err; ++ ++ err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); + if (err) + return err; + +- memcpy(prop->data, val, len); ++ if (len) ++ memcpy(prop_data, val, len); + return 0; + } + +@@ -300,7 +313,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; +- err = _fdt_splice_struct(fdt, prop->data, ++ err = fdt_splice_struct_(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) +@@ -308,7 +321,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { +- err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); ++ err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); +@@ -324,11 +337,11 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name) + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); +- if (! prop) ++ if (!prop) + return len; + + proplen = sizeof(*prop) + FDT_TAGALIGN(len); +- return _fdt_splice_struct(fdt, prop, proplen, 0); ++ return fdt_splice_struct_(fdt, prop, proplen, 0); + } + + int fdt_add_subnode_namelen(void *fdt, int parentoffset, +@@ -356,10 +369,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, + tag = fdt_next_tag(fdt, offset, &nextoffset); + } while ((tag == FDT_PROP) || (tag == FDT_NOP)); + +- nh = _fdt_offset_ptr_w(fdt, offset); ++ nh = fdt_offset_ptr_w_(fdt, offset); + nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; + +- err = _fdt_splice_struct(fdt, nh, 0, nodelen); ++ err = fdt_splice_struct_(fdt, nh, 0, nodelen); + if (err) + return err; + +@@ -383,15 +396,15 @@ int fdt_del_node(void *fdt, int nodeoffset) + + FDT_RW_CHECK_HEADER(fdt); + +- endoffset = _fdt_node_end_offset(fdt, nodeoffset); ++ endoffset = fdt_node_end_offset_(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + +- return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), ++ return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset), + endoffset - nodeoffset, 0); + } + +-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_off, struct_off, strings_off; +@@ -437,7 +450,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) + return struct_size; + } + +- if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { ++ if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { + /* no further work necessary */ + err = fdt_move(fdt, buf, bufsize); + if (err) +@@ -465,7 +478,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) + return -FDT_ERR_NOSPACE; + } + +- _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); ++ fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); +@@ -485,8 +498,8 @@ int fdt_pack(void *fdt) + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); +- _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); +- fdt_set_totalsize(fdt, _fdt_data_size(fdt)); ++ fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); ++ fdt_set_totalsize(fdt, fdt_data_size_(fdt)); + + return 0; + } +diff --git a/scripts/dtc/fdt_strerror.c b/scripts/dtc/fdt_strerror.c +index e6c3ceee8..9677a1887 100644 +--- a/scripts/dtc/fdt_strerror.c ++++ b/scripts/dtc/fdt_strerror.c +@@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = { + + FDT_ERRTABENT(FDT_ERR_BADOFFSET), + FDT_ERRTABENT(FDT_ERR_BADPATH), ++ FDT_ERRTABENT(FDT_ERR_BADPHANDLE), + FDT_ERRTABENT(FDT_ERR_BADSTATE), + + FDT_ERRTABENT(FDT_ERR_TRUNCATED), +@@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = { + FDT_ERRTABENT(FDT_ERR_BADVERSION), + FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT(FDT_ERR_BADLAYOUT), ++ FDT_ERRTABENT(FDT_ERR_INTERNAL), ++ FDT_ERRTABENT(FDT_ERR_BADNCELLS), ++ FDT_ERRTABENT(FDT_ERR_BADVALUE), ++ FDT_ERRTABENT(FDT_ERR_BADOVERLAY), ++ FDT_ERRTABENT(FDT_ERR_NOPHANDLES), + }; + #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) + +diff --git a/scripts/dtc/fdt_sw.c b/scripts/dtc/fdt_sw.c +index 6a804859f..6d33cc29d 100644 +--- a/scripts/dtc/fdt_sw.c ++++ b/scripts/dtc/fdt_sw.c +@@ -55,7 +55,7 @@ + + #include "libfdt_internal.h" + +-static int _fdt_sw_check_header(void *fdt) ++static int fdt_sw_check_header_(void *fdt) + { + if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; +@@ -66,11 +66,11 @@ static int _fdt_sw_check_header(void *fdt) + #define FDT_SW_CHECK_HEADER(fdt) \ + { \ + int err; \ +- if ((err = _fdt_sw_check_header(fdt)) != 0) \ ++ if ((err = fdt_sw_check_header_(fdt)) != 0) \ + return err; \ + } + +-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); + int spaceleft; +@@ -82,7 +82,7 @@ static void *_fdt_grab_space(void *fdt, size_t len) + return NULL; + + fdt_set_size_dt_struct(fdt, offset + len); +- return _fdt_offset_ptr_w(fdt, offset); ++ return fdt_offset_ptr_w_(fdt, offset); + } + + int fdt_create(void *buf, int bufsize) +@@ -174,7 +174,7 @@ int fdt_begin_node(void *fdt, const char *name) + + FDT_SW_CHECK_HEADER(fdt); + +- nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); ++ nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); + if (! nh) + return -FDT_ERR_NOSPACE; + +@@ -189,7 +189,7 @@ int fdt_end_node(void *fdt) + + FDT_SW_CHECK_HEADER(fdt); + +- en = _fdt_grab_space(fdt, FDT_TAGSIZE); ++ en = fdt_grab_space_(fdt, FDT_TAGSIZE); + if (! en) + return -FDT_ERR_NOSPACE; + +@@ -197,7 +197,7 @@ int fdt_end_node(void *fdt) + return 0; + } + +-static int _fdt_find_add_string(void *fdt, const char *s) ++static int fdt_find_add_string_(void *fdt, const char *s) + { + char *strtab = (char *)fdt + fdt_totalsize(fdt); + const char *p; +@@ -205,7 +205,7 @@ static int _fdt_find_add_string(void *fdt, const char *s) + int len = strlen(s) + 1; + int struct_top, offset; + +- p = _fdt_find_string(strtab - strtabsize, strtabsize, s); ++ p = fdt_find_string_(strtab - strtabsize, strtabsize, s); + if (p) + return p - strtab; + +@@ -220,25 +220,37 @@ static int _fdt_find_add_string(void *fdt, const char *s) + return offset; + } + +-int fdt_property(void *fdt, const char *name, const void *val, int len) ++int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) + { + struct fdt_property *prop; + int nameoff; + + FDT_SW_CHECK_HEADER(fdt); + +- nameoff = _fdt_find_add_string(fdt, name); ++ nameoff = fdt_find_add_string_(fdt, name); + if (nameoff == 0) + return -FDT_ERR_NOSPACE; + +- prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); ++ prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); + if (! prop) + return -FDT_ERR_NOSPACE; + + prop->tag = cpu_to_fdt32(FDT_PROP); + prop->nameoff = cpu_to_fdt32(nameoff); + prop->len = cpu_to_fdt32(len); +- memcpy(prop->data, val, len); ++ *valp = prop->data; ++ return 0; ++} ++ ++int fdt_property(void *fdt, const char *name, const void *val, int len) ++{ ++ void *ptr; ++ int ret; ++ ++ ret = fdt_property_placeholder(fdt, name, len, &ptr); ++ if (ret) ++ return ret; ++ memcpy(ptr, val, len); + return 0; + } + +@@ -253,7 +265,7 @@ int fdt_finish(void *fdt) + FDT_SW_CHECK_HEADER(fdt); + + /* Add terminator */ +- end = _fdt_grab_space(fdt, sizeof(*end)); ++ end = fdt_grab_space_(fdt, sizeof(*end)); + if (! end) + return -FDT_ERR_NOSPACE; + *end = cpu_to_fdt32(FDT_END); +@@ -269,7 +281,7 @@ int fdt_finish(void *fdt) + while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { + if (tag == FDT_PROP) { + struct fdt_property *prop = +- _fdt_offset_ptr_w(fdt, offset); ++ fdt_offset_ptr_w_(fdt, offset); + int nameoff; + + nameoff = fdt32_to_cpu(prop->nameoff); +diff --git a/scripts/dtc/fdt_wip.c b/scripts/dtc/fdt_wip.c +index c5bbb68d3..534c1cbbb 100644 +--- a/scripts/dtc/fdt_wip.c ++++ b/scripts/dtc/fdt_wip.c +@@ -55,24 +55,45 @@ + + #include "libfdt_internal.h" + ++int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, ++ const char *name, int namelen, ++ uint32_t idx, const void *val, ++ int len) ++{ ++ void *propval; ++ int proplen; ++ ++ propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, ++ &proplen); ++ if (!propval) ++ return proplen; ++ ++ if (proplen < (len + idx)) ++ return -FDT_ERR_NOSPACE; ++ ++ memcpy((char *)propval + idx, val, len); ++ return 0; ++} ++ + int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) + { +- void *propval; ++ const void *propval; + int proplen; + +- propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); +- if (! propval) ++ propval = fdt_getprop(fdt, nodeoffset, name, &proplen); ++ if (!propval) + return proplen; + + if (proplen != len) + return -FDT_ERR_NOSPACE; + +- memcpy(propval, val, len); +- return 0; ++ return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, ++ strlen(name), 0, ++ val, len); + } + +-static void _fdt_nop_region(void *start, int len) ++static void fdt_nop_region_(void *start, int len) + { + fdt32_t *p; + +@@ -86,15 +107,15 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name) + int len; + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); +- if (! prop) ++ if (!prop) + return len; + +- _fdt_nop_region(prop, len + sizeof(*prop)); ++ fdt_nop_region_(prop, len + sizeof(*prop)); + + return 0; + } + +-int _fdt_node_end_offset(void *fdt, int offset) ++int fdt_node_end_offset_(void *fdt, int offset) + { + int depth = 0; + +@@ -108,11 +129,11 @@ int fdt_nop_node(void *fdt, int nodeoffset) + { + int endoffset; + +- endoffset = _fdt_node_end_offset(fdt, nodeoffset); ++ endoffset = fdt_node_end_offset_(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + +- _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), ++ fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0), + endoffset - nodeoffset); + return 0; + } +diff --git a/scripts/dtc/fdtdump.c b/scripts/dtc/fdtdump.c +index 95a6a2016..7d460a50b 100644 +--- a/scripts/dtc/fdtdump.c ++++ b/scripts/dtc/fdtdump.c +@@ -1,17 +1,16 @@ ++// SPDX-License-Identifier: GPL-2.0 + /* + * fdtdump.c - Contributed by Pantelis Antoniou + */ + +-#include + #include + #include + #include + #include + #include + +-#include +-#include + #include ++#include + + #include "util.h" + +@@ -19,29 +18,33 @@ + #define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) + #define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) + +-static const char *tagname(uint32_t tag) ++static void print_data(const char *data, int len) + { +- static const char * const names[] = { +-#define TN(t) [t] = #t +- TN(FDT_BEGIN_NODE), +- TN(FDT_END_NODE), +- TN(FDT_PROP), +- TN(FDT_NOP), +- TN(FDT_END), +-#undef TN +- }; +- if (tag < ARRAY_SIZE(names)) +- if (names[tag]) +- return names[tag]; +- return "FDT_???"; ++ int i; ++ const char *p = data; ++ ++ /* no data, don't print */ ++ if (len == 0) ++ return; ++ ++ if (util_is_printable_string(data, len)) { ++ printf(" = \"%s\"", (const char *)data); ++ } else if ((len % 4) == 0) { ++ printf(" = <"); ++ for (i = 0; i < len; i += 4) ++ printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)), ++ i < (len - 4) ? " " : ""); ++ printf(">"); ++ } else { ++ printf(" = ["); ++ for (i = 0; i < len; i++) ++ printf("%02x%s", *p++, i < len - 1 ? " " : ""); ++ printf("]"); ++ } + } + +-#define dumpf(fmt, args...) \ +- do { if (debug) printf("// " fmt, ## args); } while (0) +- +-static void dump_blob(void *blob, bool debug) ++static void dump_blob(void *blob) + { +- uintptr_t blob_off = (uintptr_t)blob; + struct fdt_header *bph = blob; + uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); + uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); +@@ -88,15 +91,14 @@ static void dump_blob(void *blob, bool debug) + if (addr == 0 && size == 0) + break; + +- printf("/memreserve/ %#llx %#llx;\n", ++ printf("/memreserve/ %llx %llx;\n", + (unsigned long long)addr, (unsigned long long)size); + } + + p = p_struct; + while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { + +- dumpf("%04zx: tag: 0x%08x (%s)\n", +- (uintptr_t)p - blob_off - 4, tag, tagname(tag)); ++ /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + + if (tag == FDT_BEGIN_NODE) { + s = p; +@@ -135,93 +137,27 @@ static void dump_blob(void *blob, bool debug) + + p = PALIGN(p + sz, 4); + +- dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s); +- dumpf("%04zx: value\n", (uintptr_t)t - blob_off); + printf("%*s%s", depth * shift, "", s); +- utilfdt_print_data(t, sz); ++ print_data(t, sz); + printf(";\n"); + } + } + +-/* Usage related data. */ +-static const char usage_synopsis[] = "fdtdump [options] "; +-static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS; +-static struct option const usage_long_opts[] = { +- {"debug", no_argument, NULL, 'd'}, +- {"scan", no_argument, NULL, 's'}, +- USAGE_COMMON_LONG_OPTS +-}; +-static const char * const usage_opts_help[] = { +- "Dump debug information while decoding the file", +- "Scan for an embedded fdt in file", +- USAGE_COMMON_OPTS_HELP +-}; + + int main(int argc, char *argv[]) + { +- int opt; +- const char *file; + char *buf; +- bool debug = false; +- bool scan = false; +- off_t len; +- +- while ((opt = util_getopt_long()) != EOF) { +- switch (opt) { +- case_USAGE_COMMON_FLAGS + +- case 'd': +- debug = true; +- break; +- case 's': +- scan = true; +- break; +- } +- } +- if (optind != argc - 1) +- usage("missing input filename"); +- file = argv[optind]; +- +- buf = utilfdt_read_len(file, &len); +- if (!buf) +- die("could not read: %s\n", file); +- +- /* try and locate an embedded fdt in a bigger blob */ +- if (scan) { +- unsigned char smagic[4]; +- char *p = buf; +- char *endp = buf + len; +- +- fdt_set_magic(smagic, FDT_MAGIC); +- +- /* poor man's memmem */ +- while (true) { +- p = memchr(p, smagic[0], endp - p - 4); +- if (!p) +- break; +- if (fdt_magic(p) == FDT_MAGIC) { +- /* try and validate the main struct */ +- off_t this_len = endp - p; +- fdt32_t max_version = 17; +- if (fdt_version(p) <= max_version && +- fdt_last_comp_version(p) < max_version && +- fdt_totalsize(p) < this_len && +- fdt_off_dt_struct(p) < this_len && +- fdt_off_dt_strings(p) < this_len) +- break; +- if (debug) +- printf("%s: skipping fdt magic at offset %#zx\n", +- file, p - buf); +- } +- ++p; +- } +- if (!p) +- die("%s: could not locate fdt magic\n", file); +- printf("%s: found fdt at offset %#zx\n", file, p - buf); +- buf = p; ++ if (argc < 2) { ++ fprintf(stderr, "supply input filename\n"); ++ return 5; + } + +- dump_blob(buf, debug); ++ buf = utilfdt_read(argv[1]); ++ if (buf) ++ dump_blob(buf); ++ else ++ return 10; + + return 0; + } +diff --git a/scripts/dtc/fdtget.c b/scripts/dtc/fdtget.c +index 437741922..c2fbab2a5 100644 +--- a/scripts/dtc/fdtget.c ++++ b/scripts/dtc/fdtget.c +@@ -277,33 +277,33 @@ static int do_fdtget(struct display_info *disp, const char *filename, + return 0; + } + +-/* Usage related data. */ +-static const char usage_synopsis[] = +- "read values from device tree\n" ++static const char *usage_msg = ++ "fdtget - read values from device tree\n" ++ "\n" ++ "Each value is printed on a new line.\n\n" ++ "Usage:\n" + " fdtget
[ ]...\n" + " fdtget -p
[ ]...\n" +- "\n" +- "Each value is printed on a new line.\n" ++ "Options:\n" ++ "\t-t \tType of data\n" ++ "\t-p\t\tList properties for each node\n" ++ "\t-l\t\tList subnodes for each node\n" ++ "\t-d\t\tDefault value to display when the property is " ++ "missing\n" ++ "\t-h\t\tPrint this help\n\n" + USAGE_TYPE_MSG; +-static const char usage_short_opts[] = "t:pld:" USAGE_COMMON_SHORT_OPTS; +-static struct option const usage_long_opts[] = { +- {"type", a_argument, NULL, 't'}, +- {"properties", no_argument, NULL, 'p'}, +- {"list", no_argument, NULL, 'l'}, +- {"default", a_argument, NULL, 'd'}, +- USAGE_COMMON_LONG_OPTS, +-}; +-static const char * const usage_opts_help[] = { +- "Type of data", +- "List properties for each node", +- "List subnodes for each node", +- "Default value to display when the property is missing", +- USAGE_COMMON_OPTS_HELP +-}; ++ ++static void usage(const char *msg) ++{ ++ if (msg) ++ fprintf(stderr, "Error: %s\n\n", msg); ++ ++ fprintf(stderr, "%s", usage_msg); ++ exit(2); ++} + + int main(int argc, char *argv[]) + { +- int opt; + char *filename = NULL; + struct display_info disp; + int args_per_step = 2; +@@ -312,14 +312,20 @@ int main(int argc, char *argv[]) + memset(&disp, '\0', sizeof(disp)); + disp.size = -1; + disp.mode = MODE_SHOW_VALUE; +- while ((opt = util_getopt_long()) != EOF) { +- switch (opt) { +- case_USAGE_COMMON_FLAGS ++ for (;;) { ++ int c = getopt(argc, argv, "d:hlpt:"); ++ if (c == -1) ++ break; ++ ++ switch (c) { ++ case 'h': ++ case '?': ++ usage(NULL); + + case 't': + if (utilfdt_decode_type(optarg, &disp.type, + &disp.size)) +- usage("invalid type string"); ++ usage("Invalid type string"); + break; + + case 'p': +@@ -341,7 +347,7 @@ int main(int argc, char *argv[]) + if (optind < argc) + filename = argv[optind++]; + if (!filename) +- usage("missing filename"); ++ usage("Missing filename"); + + argv += optind; + argc -= optind; +@@ -352,7 +358,7 @@ int main(int argc, char *argv[]) + + /* Check for node, property arguments */ + if (args_per_step == 2 && (argc % 2)) +- usage("must have an even number of arguments"); ++ usage("Must have an even number of arguments"); + + if (do_fdtget(&disp, filename, argv, argc, args_per_step)) + return 1; +diff --git a/scripts/dtc/fdtput.c b/scripts/dtc/fdtput.c +index 2a8d67447..f2197f519 100644 +--- a/scripts/dtc/fdtput.c ++++ b/scripts/dtc/fdtput.c +@@ -96,7 +96,12 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count, + /* enlarge our value buffer by a suitable margin if needed */ + if (upto + len > value_size) { + value_size = (upto + len) + 500; +- value = xrealloc(value, value_size); ++ value = realloc(value, value_size); ++ if (!value) { ++ fprintf(stderr, "Out of mmory: cannot alloc " ++ "%d bytes\n", value_size); ++ return -1; ++ } + } + + ptr = value + upto; +@@ -126,59 +131,19 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count, + return 0; + } + +-#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1)) +- +-static char *_realloc_fdt(char *fdt, int delta) +-{ +- int new_sz = fdt_totalsize(fdt) + delta; +- fdt = xrealloc(fdt, new_sz); +- fdt_open_into(fdt, fdt, new_sz); +- return fdt; +-} +- +-static char *realloc_node(char *fdt, const char *name) +-{ +- int delta; +- /* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */ +- delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1) +- + FDT_TAGSIZE; +- return _realloc_fdt(fdt, delta); +-} +- +-static char *realloc_property(char *fdt, int nodeoffset, +- const char *name, int newlen) +-{ +- int delta = 0; +- int oldlen = 0; +- +- if (!fdt_get_property(fdt, nodeoffset, name, &oldlen)) +- /* strings + property header */ +- delta = sizeof(struct fdt_property) + strlen(name) + 1; +- +- if (newlen > oldlen) +- /* actual value in off_struct */ +- delta += ALIGN(newlen) - ALIGN(oldlen); +- +- return _realloc_fdt(fdt, delta); +-} +- +-static int store_key_value(char **blob, const char *node_name, ++static int store_key_value(void *blob, const char *node_name, + const char *property, const char *buf, int len) + { + int node; + int err; + +- node = fdt_path_offset(*blob, node_name); ++ node = fdt_path_offset(blob, node_name); + if (node < 0) { + report_error(node_name, -1, node); + return -1; + } + +- err = fdt_setprop(*blob, node, property, buf, len); +- if (err == -FDT_ERR_NOSPACE) { +- *blob = realloc_property(*blob, node, property, len); +- err = fdt_setprop(*blob, node, property, buf, len); +- } ++ err = fdt_setprop(blob, node, property, buf, len); + if (err) { + report_error(property, -1, err); + return -1; +@@ -196,7 +161,7 @@ static int store_key_value(char **blob, const char *node_name, + * @param in_path Path to process + * @return 0 if ok, -1 on error + */ +-static int create_paths(char **blob, const char *in_path) ++static int create_paths(void *blob, const char *in_path) + { + const char *path = in_path; + const char *sep; +@@ -212,11 +177,10 @@ static int create_paths(char **blob, const char *in_path) + if (!sep) + sep = path + strlen(path); + +- node = fdt_subnode_offset_namelen(*blob, offset, path, ++ node = fdt_subnode_offset_namelen(blob, offset, path, + sep - path); + if (node == -FDT_ERR_NOTFOUND) { +- *blob = realloc_node(*blob, path); +- node = fdt_add_subnode_namelen(*blob, offset, path, ++ node = fdt_add_subnode_namelen(blob, offset, path, + sep - path); + } + if (node < 0) { +@@ -239,7 +203,7 @@ static int create_paths(char **blob, const char *in_path) + * @param node_name Name of node to create + * @return new node offset if found, or -1 on failure + */ +-static int create_node(char **blob, const char *node_name) ++static int create_node(void *blob, const char *node_name) + { + int node = 0; + char *p; +@@ -251,17 +215,15 @@ static int create_node(char **blob, const char *node_name) + } + *p = '\0'; + +- *blob = realloc_node(*blob, p + 1); +- + if (p > node_name) { +- node = fdt_path_offset(*blob, node_name); ++ node = fdt_path_offset(blob, node_name); + if (node < 0) { + report_error(node_name, -1, node); + return -1; + } + } + +- node = fdt_add_subnode(*blob, node, p + 1); ++ node = fdt_add_subnode(blob, node, p + 1); + if (node < 0) { + report_error(p + 1, -1, node); + return -1; +@@ -288,64 +250,66 @@ static int do_fdtput(struct display_info *disp, const char *filename, + * store them into the property. + */ + assert(arg_count >= 2); +- if (disp->auto_path && create_paths(&blob, *arg)) ++ if (disp->auto_path && create_paths(blob, *arg)) + return -1; + if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) || +- store_key_value(&blob, *arg, arg[1], value, len)) ++ store_key_value(blob, *arg, arg[1], value, len)) + ret = -1; + break; + case OPER_CREATE_NODE: + for (; ret >= 0 && arg_count--; arg++) { + if (disp->auto_path) +- ret = create_paths(&blob, *arg); ++ ret = create_paths(blob, *arg); + else +- ret = create_node(&blob, *arg); ++ ret = create_node(blob, *arg); + } + break; + } +- if (ret >= 0) { +- fdt_pack(blob); ++ if (ret >= 0) + ret = utilfdt_write(filename, blob); +- } + + free(blob); + return ret; + } + +-/* Usage related data. */ +-static const char usage_synopsis[] = +- "write a property value to a device tree\n" +- " fdtput
[...]\n" +- " fdtput -c
[...]\n" ++static const char *usage_msg = ++ "fdtput - write a property value to a device tree\n" + "\n" + "The command line arguments are joined together into a single value.\n" ++ "\n" ++ "Usage:\n" ++ " fdtput
[...]\n" ++ " fdtput -c
[...]\n" ++ "Options:\n" ++ "\t-c\t\tCreate nodes if they don't already exist\n" ++ "\t-p\t\tAutomatically create nodes as needed for the node path\n" ++ "\t-t \tType of data\n" ++ "\t-v\t\tVerbose: display each value decoded from command line\n" ++ "\t-h\t\tPrint this help\n\n" + USAGE_TYPE_MSG; +-static const char usage_short_opts[] = "cpt:v" USAGE_COMMON_SHORT_OPTS; +-static struct option const usage_long_opts[] = { +- {"create", no_argument, NULL, 'c'}, +- {"auto-path", no_argument, NULL, 'p'}, +- {"type", a_argument, NULL, 't'}, +- {"verbose", no_argument, NULL, 'v'}, +- USAGE_COMMON_LONG_OPTS, +-}; +-static const char * const usage_opts_help[] = { +- "Create nodes if they don't already exist", +- "Automatically create nodes as needed for the node path", +- "Type of data", +- "Display each value decoded from command line", +- USAGE_COMMON_OPTS_HELP +-}; ++ ++static void usage(const char *msg) ++{ ++ if (msg) ++ fprintf(stderr, "Error: %s\n\n", msg); ++ ++ fprintf(stderr, "%s", usage_msg); ++ exit(2); ++} + + int main(int argc, char *argv[]) + { +- int opt; + struct display_info disp; + char *filename = NULL; + + memset(&disp, '\0', sizeof(disp)); + disp.size = -1; + disp.oper = OPER_WRITE_PROP; +- while ((opt = util_getopt_long()) != EOF) { ++ for (;;) { ++ int c = getopt(argc, argv, "chpt:v"); ++ if (c == -1) ++ break; ++ + /* + * TODO: add options to: + * - delete property +@@ -353,13 +317,15 @@ int main(int argc, char *argv[]) + * - rename node + * - pack fdt before writing + * - set amount of free space when writing ++ * - expand fdt if value doesn't fit + */ +- switch (opt) { +- case_USAGE_COMMON_FLAGS +- ++ switch (c) { + case 'c': + disp.oper = OPER_CREATE_NODE; + break; ++ case 'h': ++ case '?': ++ usage(NULL); + case 'p': + disp.auto_path = 1; + break; +@@ -378,16 +344,16 @@ int main(int argc, char *argv[]) + if (optind < argc) + filename = argv[optind++]; + if (!filename) +- usage("missing filename"); ++ usage("Missing filename"); + + argv += optind; + argc -= optind; + + if (disp.oper == OPER_WRITE_PROP) { + if (argc < 1) +- usage("missing node"); ++ usage("Missing node"); + if (argc < 2) +- usage("missing property"); ++ usage("Missing property"); + } + + if (do_fdtput(&disp, filename, argv, argc)) +diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c +index bd99fa2d3..8d268fb78 100644 +--- a/scripts/dtc/flattree.c ++++ b/scripts/dtc/flattree.c +@@ -49,7 +49,7 @@ static struct version_info { + + struct emitter { + void (*cell)(void *, cell_t); +- void (*string)(void *, char *, int); ++ void (*string)(void *, const char *, int); + void (*align)(void *, int); + void (*data)(void *, struct data); + void (*beginnode)(void *, struct label *labels); +@@ -64,7 +64,7 @@ static void bin_emit_cell(void *e, cell_t val) + *dtbuf = data_append_cell(*dtbuf, val); + } + +-static void bin_emit_string(void *e, char *str, int len) ++static void bin_emit_string(void *e, const char *str, int len) + { + struct data *dtbuf = e; + +@@ -144,22 +144,14 @@ static void asm_emit_cell(void *e, cell_t val) + (val >> 8) & 0xff, val & 0xff); + } + +-static void asm_emit_string(void *e, char *str, int len) ++static void asm_emit_string(void *e, const char *str, int len) + { + FILE *f = e; +- char c = 0; + +- if (len != 0) { +- /* XXX: ewww */ +- c = str[len]; +- str[len] = '\0'; +- } +- +- fprintf(f, "\t.string\t\"%s\"\n", str); +- +- if (len != 0) { +- str[len] = c; +- } ++ if (len != 0) ++ fprintf(f, "\t.string\t\"%.*s\"\n", len, str); ++ else ++ fprintf(f, "\t.string\t\"%s\"\n", str); + } + + static void asm_emit_align(void *e, int a) +@@ -179,7 +171,7 @@ static void asm_emit_data(void *e, struct data d) + emit_offset_label(f, m->ref, m->offset); + + while ((d.len - off) >= sizeof(uint32_t)) { +- asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off)))); ++ asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off)))); + off += sizeof(uint32_t); + } + +@@ -318,17 +310,16 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist, + { + struct reserve_info *re; + struct data d = empty_data; +- static struct fdt_reserve_entry null_re = {0,0}; + int j; + + for (re = reservelist; re; re = re->next) { +- d = data_append_re(d, &re->re); ++ d = data_append_re(d, re->address, re->size); + } + /* + * Add additional reserved slots if the user asked for them. + */ + for (j = 0; j < reservenum; j++) { +- d = data_append_re(d, &null_re); ++ d = data_append_re(d, 0, 0); + } + + return d; +@@ -366,7 +357,7 @@ static void make_fdt_header(struct fdt_header *fdt, + fdt->size_dt_struct = cpu_to_fdt32(dtsize); + } + +-void dt_to_blob(FILE *f, struct boot_info *bi, int version) ++void dt_to_blob(FILE *f, struct dt_info *dti, int version) + { + struct version_info *vi = NULL; + int i; +@@ -384,29 +375,36 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version) + if (!vi) + die("Unknown device tree blob version %d\n", version); + +- flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi); ++ flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi); + bin_emit_cell(&dtbuf, FDT_END); + +- reservebuf = flatten_reserve_list(bi->reservelist, vi); ++ reservebuf = flatten_reserve_list(dti->reservelist, vi); + + /* Make header */ + make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len, +- bi->boot_cpuid_phys); ++ dti->boot_cpuid_phys); + + /* + * If the user asked for more space than is used, adjust the totalsize. + */ + if (minsize > 0) { + padlen = minsize - fdt32_to_cpu(fdt.totalsize); +- if ((padlen < 0) && (quiet < 1)) +- fprintf(stderr, +- "Warning: blob size %d >= minimum size %d\n", +- fdt32_to_cpu(fdt.totalsize), minsize); ++ if (padlen < 0) { ++ padlen = 0; ++ if (quiet < 1) ++ fprintf(stderr, ++ "Warning: blob size %d >= minimum size %d\n", ++ fdt32_to_cpu(fdt.totalsize), minsize); ++ } + } + + if (padsize > 0) + padlen = padsize; + ++ if (alignsize > 0) ++ padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize) ++ - fdt32_to_cpu(fdt.totalsize); ++ + if (padlen > 0) { + int tsize = fdt32_to_cpu(fdt.totalsize); + tsize += padlen; +@@ -460,7 +458,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) + } + } + +-void dt_to_asm(FILE *f, struct boot_info *bi, int version) ++void dt_to_asm(FILE *f, struct dt_info *dti, int version) + { + struct version_info *vi = NULL; + int i; +@@ -500,7 +498,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) + + if (vi->flags & FTF_BOOTCPUID) { + fprintf(f, "\t/* boot_cpuid_phys */\n"); +- asm_emit_cell(f, bi->boot_cpuid_phys); ++ asm_emit_cell(f, dti->boot_cpuid_phys); + } + + if (vi->flags & FTF_STRTABSIZE) { +@@ -530,18 +528,18 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) + * Use .long on high and low halfs of u64s to avoid .quad + * as it appears .quad isn't available in some assemblers. + */ +- for (re = bi->reservelist; re; re = re->next) { ++ for (re = dti->reservelist; re; re = re->next) { + struct label *l; + + for_each_label(re->labels, l) { + fprintf(f, "\t.globl\t%s\n", l->label); + fprintf(f, "%s:\n", l->label); + } +- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32)); ++ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->address >> 32)); + ASM_EMIT_BELONG(f, "0x%08x", +- (unsigned int)(re->re.address & 0xffffffff)); +- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32)); +- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff)); ++ (unsigned int)(re->address & 0xffffffff)); ++ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size >> 32)); ++ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size & 0xffffffff)); + } + for (i = 0; i < reservenum; i++) { + fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); +@@ -550,7 +548,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) + fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); + + emit_label(f, symprefix, "struct_start"); +- flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi); ++ flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi); + + fprintf(f, "\t/* FDT_END */\n"); + asm_emit_cell(f, FDT_END); +@@ -572,6 +570,8 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) + if (padsize > 0) { + fprintf(f, "\t.space\t%d, 0\n", padsize); + } ++ if (alignsize > 0) ++ asm_emit_align(f, alignsize); + emit_label(f, symprefix, "blob_abs_end"); + + data_free(strbuf); +@@ -600,7 +600,7 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len) + + static uint32_t flat_read_word(struct inbuf *inb) + { +- uint32_t val; ++ fdt32_t val; + + assert(((inb->ptr - inb->base) % sizeof(val)) == 0); + +@@ -709,13 +709,15 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) + * First pass, count entries. + */ + while (1) { ++ uint64_t address, size; ++ + flat_read_chunk(inb, &re, sizeof(re)); +- re.address = fdt64_to_cpu(re.address); +- re.size = fdt64_to_cpu(re.size); +- if (re.size == 0) ++ address = fdt64_to_cpu(re.address); ++ size = fdt64_to_cpu(re.size); ++ if (size == 0) + break; + +- new = build_reserve_entry(re.address, re.size); ++ new = build_reserve_entry(address, size); + reservelist = add_reserve_entry(reservelist, new); + } + +@@ -729,7 +731,7 @@ static char *nodename_from_path(const char *ppath, const char *cpath) + + plen = strlen(ppath); + +- if (!strneq(ppath, cpath, plen)) ++ if (!strstarts(cpath, ppath)) + die("Path \"%s\" is not valid as a child of \"%s\"\n", + cpath, ppath); + +@@ -797,13 +799,18 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, + } + } while (val != FDT_END_NODE); + ++ if (node->name != flatname) { ++ free(flatname); ++ } ++ + return node; + } + + +-struct boot_info *dt_from_blob(const char *fname) ++struct dt_info *dt_from_blob(const char *fname) + { + FILE *f; ++ fdt32_t magic_buf, totalsize_buf; + uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys; + uint32_t off_dt, off_str, off_mem_rsvmap; + int rc; +@@ -820,7 +827,7 @@ struct boot_info *dt_from_blob(const char *fname) + + f = srcfile_relative_open(fname, NULL); + +- rc = fread(&magic, sizeof(magic), 1, f); ++ rc = fread(&magic_buf, sizeof(magic_buf), 1, f); + if (ferror(f)) + die("Error reading DT blob magic number: %s\n", + strerror(errno)); +@@ -831,11 +838,11 @@ struct boot_info *dt_from_blob(const char *fname) + die("Mysterious short read reading magic number\n"); + } + +- magic = fdt32_to_cpu(magic); ++ magic = fdt32_to_cpu(magic_buf); + if (magic != FDT_MAGIC) + die("Blob has incorrect magic number\n"); + +- rc = fread(&totalsize, sizeof(totalsize), 1, f); ++ rc = fread(&totalsize_buf, sizeof(totalsize_buf), 1, f); + if (ferror(f)) + die("Error reading DT blob size: %s\n", strerror(errno)); + if (rc < 1) { +@@ -845,7 +852,7 @@ struct boot_info *dt_from_blob(const char *fname) + die("Mysterious short read reading blob size\n"); + } + +- totalsize = fdt32_to_cpu(totalsize); ++ totalsize = fdt32_to_cpu(totalsize_buf); + if (totalsize < FDT_V1_SIZE) + die("DT blob size (%d) is too small\n", totalsize); + +@@ -889,7 +896,7 @@ struct boot_info *dt_from_blob(const char *fname) + + if (version >= 3) { + uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings); +- if (off_str+size_str > totalsize) ++ if ((off_str+size_str < off_str) || (off_str+size_str > totalsize)) + die("String table extends past total size\n"); + inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str); + } else { +@@ -898,7 +905,7 @@ struct boot_info *dt_from_blob(const char *fname) + + if (version >= 17) { + size_dt = fdt32_to_cpu(fdt->size_dt_struct); +- if (off_dt+size_dt > totalsize) ++ if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize)) + die("Structure block extends past total size\n"); + } + +@@ -929,5 +936,5 @@ struct boot_info *dt_from_blob(const char *fname) + + fclose(f); + +- return build_boot_info(reservelist, tree, boot_cpuid_phys); ++ return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys); + } +diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c +index 6d1beec95..ae7d06c3c 100644 +--- a/scripts/dtc/fstree.c ++++ b/scripts/dtc/fstree.c +@@ -79,13 +79,12 @@ static struct node *read_fstree(const char *dirname) + return tree; + } + +-struct boot_info *dt_from_fs(const char *dirname) ++struct dt_info *dt_from_fs(const char *dirname) + { + struct node *tree; + + tree = read_fstree(dirname); + tree = name_node(tree, ""); + +- return build_boot_info(NULL, tree, guess_boot_cpuid(tree)); ++ return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree)); + } +- +diff --git a/scripts/dtc/libfdt.h b/scripts/dtc/libfdt.h +index 32d52276d..1e27780e1 100644 +--- a/scripts/dtc/libfdt.h ++++ b/scripts/dtc/libfdt.h +@@ -1,5 +1,5 @@ +-#ifndef _LIBFDT_H +-#define _LIBFDT_H ++#ifndef LIBFDT_H ++#define LIBFDT_H + /* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. +@@ -51,17 +51,17 @@ + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +-#include +-#include ++#include "libfdt_env.h" ++#include "fdt.h" + +-#define FDT_FIRST_SUPPORTED_VERSION 0x10 ++#define FDT_FIRST_SUPPORTED_VERSION 0x02 + #define FDT_LAST_SUPPORTED_VERSION 0x11 + + /* Error codes: informative error codes */ + #define FDT_ERR_NOTFOUND 1 + /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ + #define FDT_ERR_EXISTS 2 +- /* FDT_ERR_EXISTS: Attemped to create a node or property which ++ /* FDT_ERR_EXISTS: Attempted to create a node or property which + * already exists */ + #define FDT_ERR_NOSPACE 3 + /* FDT_ERR_NOSPACE: Operation needed to expand the device +@@ -79,8 +79,10 @@ + * (e.g. missing a leading / for a function which requires an + * absolute path) */ + #define FDT_ERR_BADPHANDLE 6 +- /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle +- * value. phandle values of 0 and -1 are not permitted. */ ++ /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. ++ * This can be caused either by an invalid phandle property ++ * length, or the phandle value was either 0 or -1, which are ++ * not permitted. */ + #define FDT_ERR_BADSTATE 7 + /* FDT_ERR_BADSTATE: Function was passed an incomplete device + * tree created by the sequential-write functions, which is +@@ -121,13 +123,29 @@ + /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells + * or similar property with a bad format or value */ + +-#define FDT_ERR_MAX 14 ++#define FDT_ERR_BADVALUE 15 ++ /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected ++ * value. For example: a property expected to contain a string list ++ * is not NUL-terminated within the length of its value. */ ++ ++#define FDT_ERR_BADOVERLAY 16 ++ /* FDT_ERR_BADOVERLAY: The device tree overlay, while ++ * correctly structured, cannot be applied due to some ++ * unexpected or missing value, property or node. */ ++ ++#define FDT_ERR_NOPHANDLES 17 ++ /* FDT_ERR_NOPHANDLES: The device tree doesn't have any ++ * phandle available anymore without causing an overflow */ ++ ++#define FDT_ERR_MAX 17 + + /**********************************************************************/ + /* Low-level functions (you probably don't need these) */ + /**********************************************************************/ + ++#ifndef SWIG /* This function is not useful in Python */ + const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); ++#endif + static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) + { + return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); +@@ -163,40 +181,67 @@ int fdt_first_subnode(const void *fdt, int offset); + */ + int fdt_next_subnode(const void *fdt, int offset); + ++/** ++ * fdt_for_each_subnode - iterate over all subnodes of a parent ++ * ++ * @node: child node (int, lvalue) ++ * @fdt: FDT blob (const void *) ++ * @parent: parent node (int) ++ * ++ * This is actually a wrapper around a for loop and would be used like so: ++ * ++ * fdt_for_each_subnode(node, fdt, parent) { ++ * Use node ++ * ... ++ * } ++ * ++ * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { ++ * Error handling ++ * } ++ * ++ * 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 ++ * literal. ++ * ++ */ ++#define fdt_for_each_subnode(node, fdt, parent) \ ++ for (node = fdt_first_subnode(fdt, parent); \ ++ node >= 0; \ ++ node = fdt_next_subnode(fdt, node)) ++ + /**********************************************************************/ + /* General functions */ + /**********************************************************************/ +- + #define fdt_get_header(fdt, field) \ + (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) +-#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) ++#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) + #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) + #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) + #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) + #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) + #define fdt_version(fdt) (fdt_get_header(fdt, version)) +-#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +-#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +-#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) ++#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) ++#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) ++#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) + #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + +-#define __fdt_set_hdr(name) \ ++#define fdt_set_hdr_(name) \ + static inline void fdt_set_##name(void *fdt, uint32_t val) \ + { \ +- struct fdt_header *fdth = (struct fdt_header*)fdt; \ ++ struct fdt_header *fdth = (struct fdt_header *)fdt; \ + fdth->name = cpu_to_fdt32(val); \ + } +-__fdt_set_hdr(magic); +-__fdt_set_hdr(totalsize); +-__fdt_set_hdr(off_dt_struct); +-__fdt_set_hdr(off_dt_strings); +-__fdt_set_hdr(off_mem_rsvmap); +-__fdt_set_hdr(version); +-__fdt_set_hdr(last_comp_version); +-__fdt_set_hdr(boot_cpuid_phys); +-__fdt_set_hdr(size_dt_strings); +-__fdt_set_hdr(size_dt_struct); +-#undef __fdt_set_hdr ++fdt_set_hdr_(magic); ++fdt_set_hdr_(totalsize); ++fdt_set_hdr_(off_dt_struct); ++fdt_set_hdr_(off_dt_strings); ++fdt_set_hdr_(off_mem_rsvmap); ++fdt_set_hdr_(version); ++fdt_set_hdr_(last_comp_version); ++fdt_set_hdr_(boot_cpuid_phys); ++fdt_set_hdr_(size_dt_strings); ++fdt_set_hdr_(size_dt_struct); ++#undef fdt_set_hdr_ + + /** + * fdt_check_header - sanity check a device tree or possible device tree +@@ -253,6 +298,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize); + */ + const char *fdt_string(const void *fdt, int stroffset); + ++/** ++ * fdt_get_max_phandle - retrieves the highest phandle in a tree ++ * @fdt: pointer to the device tree blob ++ * ++ * fdt_get_max_phandle retrieves the highest phandle in the given ++ * device tree. This will ignore badly formatted phandles, or phandles ++ * with a value of 0 or -1. ++ * ++ * returns: ++ * the highest phandle on success ++ * 0, if no phandle was found in the device tree ++ * -1, if an error occurred ++ */ ++uint32_t fdt_get_max_phandle(const void *fdt); ++ + /** + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries + * @fdt: pointer to the device tree blob +@@ -295,8 +355,10 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + */ ++#ifndef SWIG /* Not available in Python */ + int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + const char *name, int namelen); ++#endif + /** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob +@@ -313,8 +375,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + * returns: + * structure block offset of the requested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist +- * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag +- * -FDT_ERR_BADMAGIC, ++ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE ++ * tag ++ * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, +@@ -322,6 +385,19 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + */ + int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + ++/** ++ * fdt_path_offset_namelen - find a tree node by its full path ++ * @fdt: pointer to the device tree blob ++ * @path: full path of the node to locate ++ * @namelen: number of characters of path to consider ++ * ++ * Identical to fdt_path_offset(), but only consider the first namelen ++ * characters of path as the path name. ++ */ ++#ifndef SWIG /* Not available in Python */ ++int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); ++#endif ++ + /** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob +@@ -335,7 +411,8 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + * address). + * + * returns: +- * structure block offset of the node with the requested path (>=0), on success ++ * structure block offset of the node with the requested path (>=0), on ++ * success + * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + * -FDT_ERR_NOTFOUND, if the requested node does not exist + * -FDT_ERR_BADMAGIC, +@@ -359,10 +436,12 @@ int fdt_path_offset(const void *fdt, const char *path); + * + * returns: + * pointer to the node's name, on success +- * If lenp is non-NULL, *lenp contains the length of that name (>=0) ++ * If lenp is non-NULL, *lenp contains the length of that name ++ * (>=0) + * NULL, on error + * if lenp is non-NULL *lenp contains an error code (<0): +- * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE ++ * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings +@@ -410,6 +489,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); + */ + int fdt_next_property_offset(const void *fdt, int offset); + ++/** ++ * fdt_for_each_property_offset - iterate over all properties of a node ++ * ++ * @property_offset: property offset (int, lvalue) ++ * @fdt: FDT blob (const void *) ++ * @node: node offset (int) ++ * ++ * This is actually a wrapper around a for loop and would be used like so: ++ * ++ * fdt_for_each_property_offset(property, fdt, node) { ++ * Use property ++ * ... ++ * } ++ * ++ * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { ++ * Error handling ++ * } ++ * ++ * Note that this is implemented as a macro and property is used as ++ * iterator in the loop. The node variable can be constant or even a ++ * literal. ++ */ ++#define fdt_for_each_property_offset(property, fdt, node) \ ++ for (property = fdt_first_property_offset(fdt, node); \ ++ property >= 0; \ ++ property = fdt_next_property_offset(fdt, property)) ++ + /** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob +@@ -421,6 +527,9 @@ int fdt_next_property_offset(const void *fdt, int offset); + * offset. If lenp is non-NULL, the length of the property value is + * also returned, in the integer pointed to by lenp. + * ++ * Note that this code only works on device tree versions >= 16. fdt_getprop() ++ * works on all versions. ++ * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property +@@ -446,13 +555,15 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * +- * Identical to fdt_get_property_namelen(), but only examine the first +- * namelen characters of name for matching the property name. ++ * Identical to fdt_get_property(), but only examine the first namelen ++ * characters of name for matching the property name. + */ ++#ifndef SWIG /* Not available in Python */ + const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); ++#endif + + /** + * fdt_get_property - find a given property in a given node +@@ -474,7 +585,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property +- * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE ++ * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -522,8 +634,10 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ ++#ifndef SWIG /* This function is not useful in Python */ + const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp); ++#endif + + /** + * fdt_getprop_namelen - get property value based on substring +@@ -536,8 +650,17 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + */ ++#ifndef SWIG /* Not available in Python */ + const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); ++static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, ++ const char *name, int namelen, ++ int *lenp) ++{ ++ return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, ++ namelen, lenp); ++} ++#endif + + /** + * fdt_getprop - retrieve the value of a given property +@@ -559,7 +682,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property +- * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE ++ * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -597,11 +721,13 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); + * Identical to fdt_get_alias(), but only examine the first namelen + * characters of name for matching the alias name. + */ ++#ifndef SWIG /* Not available in Python */ + const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen); ++#endif + + /** +- * fdt_get_alias - retreive the path referenced by a given alias ++ * fdt_get_alias - retrieve the path referenced by a given alias + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * +@@ -631,7 +757,7 @@ const char *fdt_get_alias(const void *fdt, const char *name); + * 0, on success + * buf contains the absolute path of the node at + * nodeoffset, as a NUL-terminated string. +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + * characters and will not fit in the given buffer. + * -FDT_ERR_BADMAGIC, +@@ -661,11 +787,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + * structure from the start to nodeoffset. + * + * returns: +- + * structure block offset of the node at node offset's ancestor + * of depth supernodedepth (>=0), on success +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag +-* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of ++ * nodeoffset + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -687,7 +813,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + * + * returns: + * depth of the node at nodeoffset (>=0), on success +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -710,7 +836,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset); + * returns: + * structure block offset of the parent of the node at nodeoffset + * (>=0), on success +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -750,7 +876,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset); + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -797,7 +923,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); + * 1, if the node has a 'compatible' property, but it does not list + * the given string + * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property +- * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -834,7 +960,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -857,6 +983,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + */ + int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + ++/** ++ * fdt_stringlist_count - count the number of strings in a string list ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of a tree node ++ * @property: name of the property containing the string list ++ * @return: ++ * the number of strings in the given property ++ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated ++ * -FDT_ERR_NOTFOUND if the property does not exist ++ */ ++int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); ++ ++/** ++ * fdt_stringlist_search - find a string in a string list and return its index ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of a tree node ++ * @property: name of the property containing the string list ++ * @string: string to look up in the string list ++ * ++ * Note that it is possible for this function to succeed on property values ++ * that are not NUL-terminated. That's because the function will stop after ++ * finding the first occurrence of @string. This can for example happen with ++ * small-valued cell properties, such as #address-cells, when searching for ++ * the empty string. ++ * ++ * @return: ++ * the index of the string in the list of strings ++ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated ++ * -FDT_ERR_NOTFOUND if the property does not exist or does not contain ++ * the given string ++ */ ++int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, ++ const char *string); ++ ++/** ++ * fdt_stringlist_get() - obtain the string at a given index in a string list ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of a tree node ++ * @property: name of the property containing the string list ++ * @index: index of the string to return ++ * @lenp: return location for the string length or an error code on failure ++ * ++ * Note that this will successfully extract strings from properties with ++ * non-NUL-terminated values. For example on small-valued cell properties ++ * this function will return the empty string. ++ * ++ * 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. ++ * ++ * @return: ++ * 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 ++ * location pointed to by the lenp parameter, if non-NULL. On failure one of ++ * the following negative error codes will be returned in the lenp parameter ++ * (if non-NULL): ++ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated ++ * -FDT_ERR_NOTFOUND if the property does not exist ++ */ ++const char *fdt_stringlist_get(const void *fdt, int nodeoffset, ++ const char *property, int index, ++ int *lenp); ++ + /**********************************************************************/ + /* Read-only functions (addressing related) */ + /**********************************************************************/ +@@ -882,7 +1070,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property +- * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property ++ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid ++ * #address-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -902,7 +1091,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset); + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property +- * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property ++ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid ++ * #size-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -916,6 +1106,29 @@ int fdt_size_cells(const void *fdt, int nodeoffset); + /* Write-in-place functions */ + /**********************************************************************/ + ++/** ++ * fdt_setprop_inplace_namelen_partial - change a property's value, ++ * but not its size ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of the node whose property to change ++ * @name: name of the property to change ++ * @namelen: number of characters of name to consider ++ * @idx: index of the property to change in the array ++ * @val: pointer to data to replace the property value with ++ * @len: length of the property value ++ * ++ * Identical to fdt_setprop_inplace(), but modifies the given property ++ * 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 ++ * an array and you have a string that doesn't end with \0. ++ */ ++#ifndef SWIG /* Not available in Python */ ++int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, ++ const char *name, int namelen, ++ uint32_t idx, const void *val, ++ int len); ++#endif ++ + /** + * fdt_setprop_inplace - change a property's value, but not its size + * @fdt: pointer to the device tree blob +@@ -944,8 +1157,10 @@ int fdt_size_cells(const void *fdt, int nodeoffset); + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ ++#ifndef SWIG /* Not available in Python */ + int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len); ++#endif + + /** + * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property +@@ -1102,6 +1317,22 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) + { + return fdt_property_u32(fdt, name, val); + } ++ ++/** ++ * fdt_property_placeholder - add a new property and return a ptr to its value ++ * ++ * @fdt: pointer to the device tree blob ++ * @name: name of property to add ++ * @len: length of property value in bytes ++ * @valp: returns a pointer to where where the value should be placed ++ * ++ * returns: ++ * 0, on success ++ * -FDT_ERR_BADMAGIC, ++ * -FDT_ERR_NOSPACE, standard meanings ++ */ ++int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp); ++ + #define fdt_property_string(fdt, name, str) \ + fdt_property(fdt, name, str, strlen(str)+1) + int fdt_end_node(void *fdt); +@@ -1220,6 +1451,37 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name); + int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + ++/** ++ * fdt_setprop_placeholder - allocate space for 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 ++ * @len: length of the property value ++ * @prop_data: return pointer to property data ++ * ++ * fdt_setprop_placeholer() allocates the named property in the given node. ++ * If the property exists it is resized. In either case a pointer to the ++ * property data is returned. ++ * ++ * This function may insert or delete data from the blob, and will ++ * therefore change the offsets of some existing nodes. ++ * ++ * returns: ++ * 0, on success ++ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to ++ * contain the new property value ++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADLAYOUT, ++ * -FDT_ERR_BADMAGIC, ++ * -FDT_ERR_BADVERSION, ++ * -FDT_ERR_BADSTATE, ++ * -FDT_ERR_BADSTRUCTURE, ++ * -FDT_ERR_BADLAYOUT, ++ * -FDT_ERR_TRUNCATED, standard meanings ++ */ ++int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, ++ int len, void **prop_data); ++ + /** + * fdt_setprop_u32 - set a property to a 32-bit integer + * @fdt: pointer to the device tree blob +@@ -1332,6 +1594,36 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, + #define fdt_setprop_string(fdt, nodeoffset, name, str) \ + fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + ++ ++/** ++ * fdt_setprop_empty - set a property to an empty value ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of the node whose property to change ++ * @name: name of the property to change ++ * ++ * fdt_setprop_empty() sets the value of the named property in the ++ * given node to an empty (zero length) value, or creates a new empty ++ * property if it does not already exist. ++ * ++ * This function may insert or delete data from the blob, and will ++ * therefore change the offsets of some existing nodes. ++ * ++ * returns: ++ * 0, on success ++ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to ++ * contain the new property value ++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADLAYOUT, ++ * -FDT_ERR_BADMAGIC, ++ * -FDT_ERR_BADVERSION, ++ * -FDT_ERR_BADSTATE, ++ * -FDT_ERR_BADSTRUCTURE, ++ * -FDT_ERR_BADLAYOUT, ++ * -FDT_ERR_TRUNCATED, standard meanings ++ */ ++#define fdt_setprop_empty(fdt, nodeoffset, name) \ ++ fdt_setprop((fdt), (nodeoffset), (name), NULL, 0) ++ + /** + * fdt_appendprop - append to or create a property + * @fdt: pointer to the device tree blob +@@ -1509,8 +1801,10 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name); + * creating subnodes based on a portion of a larger string, such as a + * full path. + */ ++#ifndef SWIG /* Not available in Python */ + int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen); ++#endif + + /** + * fdt_add_subnode - creates a new node +@@ -1526,9 +1820,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, + * change the offsets of some existing nodes. + + * returns: +- * structure block offset of the created nodeequested subnode (>=0), on success ++ * structure block offset of the created nodeequested subnode (>=0), on ++ * success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist +- * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE ++ * tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the +@@ -1566,10 +1862,41 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); + */ + int fdt_del_node(void *fdt, int nodeoffset); + ++/** ++ * fdt_overlay_apply - Applies a DT overlay on a base DT ++ * @fdt: pointer to the base device tree blob ++ * @fdto: pointer to the device tree overlay blob ++ * ++ * fdt_overlay_apply() will apply the given device tree overlay on the ++ * given base device tree. ++ * ++ * Expect the base device tree to be modified, even if the function ++ * returns an error. ++ * ++ * returns: ++ * 0, on success ++ * -FDT_ERR_NOSPACE, there's not enough space in the base device tree ++ * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or ++ * properties in the base DT ++ * -FDT_ERR_BADPHANDLE, ++ * -FDT_ERR_BADOVERLAY, ++ * -FDT_ERR_NOPHANDLES, ++ * -FDT_ERR_INTERNAL, ++ * -FDT_ERR_BADLAYOUT, ++ * -FDT_ERR_BADMAGIC, ++ * -FDT_ERR_BADOFFSET, ++ * -FDT_ERR_BADPATH, ++ * -FDT_ERR_BADVERSION, ++ * -FDT_ERR_BADSTRUCTURE, ++ * -FDT_ERR_BADSTATE, ++ * -FDT_ERR_TRUNCATED, standard meanings ++ */ ++int fdt_overlay_apply(void *fdt, void *fdto); ++ + /**********************************************************************/ + /* Debugging / informational functions */ + /**********************************************************************/ + + const char *fdt_strerror(int errval); + +-#endif /* _LIBFDT_H */ ++#endif /* LIBFDT_H */ +diff --git a/scripts/dtc/libfdt_env.h b/scripts/dtc/libfdt_env.h +index 9dea97dff..bd2474628 100644 +--- a/scripts/dtc/libfdt_env.h ++++ b/scripts/dtc/libfdt_env.h +@@ -1,5 +1,5 @@ +-#ifndef _LIBFDT_ENV_H +-#define _LIBFDT_ENV_H ++#ifndef LIBFDT_ENV_H ++#define LIBFDT_ENV_H + /* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. +@@ -54,19 +54,20 @@ + + #include + #include ++#include + #include + + #ifdef __CHECKER__ +-#define __force __attribute__((force)) +-#define __bitwise __attribute__((bitwise)) ++#define FDT_FORCE __attribute__((force)) ++#define FDT_BITWISE __attribute__((bitwise)) + #else +-#define __force +-#define __bitwise ++#define FDT_FORCE ++#define FDT_BITWISE + #endif + +-typedef uint16_t __bitwise fdt16_t; +-typedef uint32_t __bitwise fdt32_t; +-typedef uint64_t __bitwise fdt64_t; ++typedef uint16_t FDT_BITWISE fdt16_t; ++typedef uint32_t FDT_BITWISE fdt32_t; ++typedef uint64_t FDT_BITWISE fdt64_t; + + #define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) + #define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) +@@ -79,33 +80,60 @@ typedef uint64_t __bitwise fdt64_t; + + static inline uint16_t fdt16_to_cpu(fdt16_t x) + { +- return (__force uint16_t)CPU_TO_FDT16(x); ++ return (FDT_FORCE uint16_t)CPU_TO_FDT16(x); + } + static inline fdt16_t cpu_to_fdt16(uint16_t x) + { +- return (__force fdt16_t)CPU_TO_FDT16(x); ++ return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x); + } + + static inline uint32_t fdt32_to_cpu(fdt32_t x) + { +- return (__force uint32_t)CPU_TO_FDT32(x); ++ return (FDT_FORCE uint32_t)CPU_TO_FDT32(x); + } + static inline fdt32_t cpu_to_fdt32(uint32_t x) + { +- return (__force fdt32_t)CPU_TO_FDT32(x); ++ return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x); + } + + static inline uint64_t fdt64_to_cpu(fdt64_t x) + { +- return (__force uint64_t)CPU_TO_FDT64(x); ++ return (FDT_FORCE uint64_t)CPU_TO_FDT64(x); + } + static inline fdt64_t cpu_to_fdt64(uint64_t x) + { +- return (__force fdt64_t)CPU_TO_FDT64(x); ++ return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x); + } + #undef CPU_TO_FDT64 + #undef CPU_TO_FDT32 + #undef CPU_TO_FDT16 + #undef EXTRACT_BYTE + +-#endif /* _LIBFDT_ENV_H */ ++#ifdef __APPLE__ ++#include ++ ++/* 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 */ +diff --git a/scripts/dtc/libfdt_internal.h b/scripts/dtc/libfdt_internal.h +index 02cfa6fb6..7681e1922 100644 +--- a/scripts/dtc/libfdt_internal.h ++++ b/scripts/dtc/libfdt_internal.h +@@ -1,5 +1,5 @@ +-#ifndef _LIBFDT_INTERNAL_H +-#define _LIBFDT_INTERNAL_H ++#ifndef LIBFDT_INTERNAL_H ++#define LIBFDT_INTERNAL_H + /* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. +@@ -57,27 +57,27 @@ + + #define FDT_CHECK_HEADER(fdt) \ + { \ +- int __err; \ +- if ((__err = fdt_check_header(fdt)) != 0) \ +- return __err; \ ++ int err_; \ ++ if ((err_ = fdt_check_header(fdt)) != 0) \ ++ return err_; \ + } + +-int _fdt_check_node_offset(const void *fdt, int offset); +-int _fdt_check_prop_offset(const void *fdt, int offset); +-const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); +-int _fdt_node_end_offset(void *fdt, int nodeoffset); ++int fdt_check_node_offset_(const void *fdt, int offset); ++int fdt_check_prop_offset_(const void *fdt, int offset); ++const char *fdt_find_string_(const char *strtab, int tabsize, const char *s); ++int fdt_node_end_offset_(void *fdt, int nodeoffset); + +-static inline const void *_fdt_offset_ptr(const void *fdt, int offset) ++static inline const void *fdt_offset_ptr_(const void *fdt, int offset) + { + return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; + } + +-static inline void *_fdt_offset_ptr_w(void *fdt, int offset) ++static inline void *fdt_offset_ptr_w_(void *fdt, int offset) + { +- return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); ++ return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset); + } + +-static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) ++static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n) + { + const struct fdt_reserve_entry *rsv_table = + (const struct fdt_reserve_entry *) +@@ -85,11 +85,11 @@ static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int + + return rsv_table + n; + } +-static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) ++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); + } + + #define FDT_SW_MAGIC (~FDT_MAGIC) + +-#endif /* _LIBFDT_INTERNAL_H */ ++#endif /* LIBFDT_INTERNAL_H */ +diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c +index e229b8443..57b7db2ed 100644 +--- a/scripts/dtc/livetree.c ++++ b/scripts/dtc/livetree.c +@@ -204,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) + } + } + +- /* if no collision occured, add child to the old node. */ ++ /* if no collision occurred, add child to the old node. */ + if (new_child) + add_child(old_node, new_child); + } +@@ -216,6 +216,29 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) + return old_node; + } + ++struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref) ++{ ++ static unsigned int next_orphan_fragment = 0; ++ struct node *node; ++ struct property *p; ++ struct data d = empty_data; ++ char *name; ++ ++ d = data_add_marker(d, REF_PHANDLE, ref); ++ d = data_append_integer(d, 0xffffffff, 32); ++ ++ p = build_property("target", d); ++ ++ xasprintf(&name, "fragment@%u", ++ next_orphan_fragment++); ++ name_node(new_node, "__overlay__"); ++ node = build_node(p, new_node); ++ name_node(node, name); ++ ++ add_child(dt, node); ++ return dt; ++} ++ + struct node *chain_node(struct node *first, struct node *list) + { + assert(first->next_sibling == NULL); +@@ -242,7 +265,7 @@ void delete_property_by_name(struct node *node, char *name) + struct property *prop = node->proplist; + + while (prop) { +- if (!strcmp(prop->name, name)) { ++ if (streq(prop->name, name)) { + delete_property(prop); + return; + } +@@ -275,7 +298,7 @@ void delete_node_by_name(struct node *parent, char *name) + struct node *node = parent->children; + + while (node) { +- if (!strcmp(node->name, name)) { ++ if (streq(node->name, name)) { + delete_node(node); + return; + } +@@ -296,14 +319,31 @@ void delete_node(struct node *node) + delete_labels(&node->labels); + } + ++void append_to_property(struct node *node, ++ char *name, const void *data, int len) ++{ ++ struct data d; ++ struct property *p; ++ ++ p = get_property(node, name); ++ if (p) { ++ d = data_append_data(p->val, data, len); ++ p->val = d; ++ } else { ++ d = data_append_data(empty_data, data, len); ++ p = build_property(name, d); ++ add_property(node, p); ++ } ++} ++ + struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) + { + struct reserve_info *new = xmalloc(sizeof(*new)); + + memset(new, 0, sizeof(*new)); + +- new->re.address = address; +- new->re.size = size; ++ new->address = address; ++ new->size = size; + + return new; + } +@@ -335,17 +375,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, + return list; + } + +-struct boot_info *build_boot_info(struct reserve_info *reservelist, +- struct node *tree, uint32_t boot_cpuid_phys) ++struct dt_info *build_dt_info(unsigned int dtsflags, ++ struct reserve_info *reservelist, ++ struct node *tree, uint32_t boot_cpuid_phys) + { +- struct boot_info *bi; ++ struct dt_info *dti; + +- bi = xmalloc(sizeof(*bi)); +- bi->reservelist = reservelist; +- bi->dt = tree; +- bi->boot_cpuid_phys = boot_cpuid_phys; ++ dti = xmalloc(sizeof(*dti)); ++ dti->dtsflags = dtsflags; ++ dti->reservelist = reservelist; ++ dti->dt = tree; ++ dti->boot_cpuid_phys = boot_cpuid_phys; + +- return bi; ++ return dti; + } + + /* +@@ -374,7 +416,13 @@ struct property *get_property(struct node *node, const char *propname) + cell_t propval_cell(struct property *prop) + { + assert(prop->val.len == sizeof(cell_t)); +- return fdt32_to_cpu(*((cell_t *)prop->val.val)); ++ return fdt32_to_cpu(*((fdt32_t *)prop->val.val)); ++} ++ ++cell_t propval_cell_n(struct property *prop, int n) ++{ ++ assert(prop->val.len / sizeof(cell_t) >= n); ++ return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n)); + } + + struct property *get_property_by_label(struct node *tree, const char *label, +@@ -459,7 +507,8 @@ struct node *get_node_by_path(struct node *tree, const char *path) + p = strchr(path, '/'); + + for_each_child(tree, child) { +- if (p && strneq(path, child->name, p-path)) ++ if (p && (strlen(child->name) == p-path) && ++ strprefixeq(path, p - path, child->name)) + return get_node_by_path(child, p+1); + else if (!p && streq(path, child->name)) + return child; +@@ -492,7 +541,10 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) + { + struct node *child, *node; + +- assert((phandle != 0) && (phandle != -1)); ++ if ((phandle == 0) || (phandle == -1)) { ++ assert(generate_fixups); ++ return NULL; ++ } + + if (tree->phandle == phandle) { + if (tree->deleted) +@@ -580,24 +632,24 @@ static int cmp_reserve_info(const void *ax, const void *bx) + a = *((const struct reserve_info * const *)ax); + b = *((const struct reserve_info * const *)bx); + +- if (a->re.address < b->re.address) ++ if (a->address < b->address) + return -1; +- else if (a->re.address > b->re.address) ++ else if (a->address > b->address) + return 1; +- else if (a->re.size < b->re.size) ++ else if (a->size < b->size) + return -1; +- else if (a->re.size > b->re.size) ++ else if (a->size > b->size) + return 1; + else + return 0; + } + +-static void sort_reserve_entries(struct boot_info *bi) ++static void sort_reserve_entries(struct dt_info *dti) + { + struct reserve_info *ri, **tbl; + int n = 0, i = 0; + +- for (ri = bi->reservelist; ++ for (ri = dti->reservelist; + ri; + ri = ri->next) + n++; +@@ -607,14 +659,14 @@ static void sort_reserve_entries(struct boot_info *bi) + + tbl = xmalloc(n * sizeof(*tbl)); + +- for (ri = bi->reservelist; ++ for (ri = dti->reservelist; + ri; + ri = ri->next) + tbl[i++] = ri; + + qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); + +- bi->reservelist = tbl[0]; ++ dti->reservelist = tbl[0]; + for (i = 0; i < (n-1); i++) + tbl[i]->next = tbl[i+1]; + tbl[n-1]->next = NULL; +@@ -704,8 +756,258 @@ static void sort_node(struct node *node) + sort_node(c); + } + +-void sort_tree(struct boot_info *bi) ++void sort_tree(struct dt_info *dti) ++{ ++ sort_reserve_entries(dti); ++ sort_node(dti->dt); ++} ++ ++/* utility helper to avoid code duplication */ ++static struct node *build_and_name_child_node(struct node *parent, char *name) ++{ ++ struct node *node; ++ ++ node = build_node(NULL, NULL); ++ name_node(node, xstrdup(name)); ++ add_child(parent, node); ++ ++ return node; ++} ++ ++static struct node *build_root_node(struct node *dt, char *name) ++{ ++ struct node *an; ++ ++ an = get_subnode(dt, name); ++ if (!an) ++ an = build_and_name_child_node(dt, name); ++ ++ if (!an) ++ die("Could not build root node /%s\n", name); ++ ++ return an; ++} ++ ++static bool any_label_tree(struct dt_info *dti, struct node *node) ++{ ++ struct node *c; ++ ++ if (node->labels) ++ return true; ++ ++ for_each_child(node, c) ++ if (any_label_tree(dti, c)) ++ return true; ++ ++ return false; ++} ++ ++static void generate_label_tree_internal(struct dt_info *dti, ++ struct node *an, struct node *node, ++ bool allocph) + { +- sort_reserve_entries(bi); +- sort_node(bi->dt); ++ struct node *dt = dti->dt; ++ struct node *c; ++ struct property *p; ++ struct label *l; ++ ++ /* if there are labels */ ++ if (node->labels) { ++ ++ /* now add the label in the node */ ++ for_each_label(node->labels, l) { ++ ++ /* check whether the label already exists */ ++ p = get_property(an, l->label); ++ if (p) { ++ fprintf(stderr, "WARNING: label %s already" ++ " exists in /%s", l->label, ++ an->name); ++ continue; ++ } ++ ++ /* insert it */ ++ p = build_property(l->label, ++ data_copy_mem(node->fullpath, ++ strlen(node->fullpath) + 1)); ++ add_property(an, p); ++ } ++ ++ /* force allocation of a phandle for this node */ ++ if (allocph) ++ (void)get_node_phandle(dt, node); ++ } ++ ++ for_each_child(node, c) ++ generate_label_tree_internal(dti, an, c, allocph); ++} ++ ++static bool any_fixup_tree(struct dt_info *dti, struct node *node) ++{ ++ struct node *c; ++ struct property *prop; ++ struct marker *m; ++ ++ for_each_property(node, prop) { ++ m = prop->val.markers; ++ for_each_marker_of_type(m, REF_PHANDLE) { ++ if (!get_node_by_ref(dti->dt, m->ref)) ++ return true; ++ } ++ } ++ ++ for_each_child(node, c) { ++ if (any_fixup_tree(dti, c)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void add_fixup_entry(struct dt_info *dti, struct node *fn, ++ struct node *node, struct property *prop, ++ struct marker *m) ++{ ++ char *entry; ++ ++ /* m->ref can only be a REF_PHANDLE, but check anyway */ ++ assert(m->type == REF_PHANDLE); ++ ++ /* there shouldn't be any ':' in the arguments */ ++ if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) ++ die("arguments should not contain ':'\n"); ++ ++ xasprintf(&entry, "%s:%s:%u", ++ node->fullpath, prop->name, m->offset); ++ append_to_property(fn, m->ref, entry, strlen(entry) + 1); ++ ++ free(entry); ++} ++ ++static void generate_fixups_tree_internal(struct dt_info *dti, ++ struct node *fn, ++ struct node *node) ++{ ++ struct node *dt = dti->dt; ++ struct node *c; ++ struct property *prop; ++ struct marker *m; ++ struct node *refnode; ++ ++ for_each_property(node, prop) { ++ m = prop->val.markers; ++ for_each_marker_of_type(m, REF_PHANDLE) { ++ refnode = get_node_by_ref(dt, m->ref); ++ if (!refnode) ++ add_fixup_entry(dti, fn, node, prop, m); ++ } ++ } ++ ++ for_each_child(node, c) ++ generate_fixups_tree_internal(dti, fn, c); ++} ++ ++static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) ++{ ++ struct node *c; ++ struct property *prop; ++ struct marker *m; ++ ++ for_each_property(node, prop) { ++ m = prop->val.markers; ++ for_each_marker_of_type(m, REF_PHANDLE) { ++ if (get_node_by_ref(dti->dt, m->ref)) ++ return true; ++ } ++ } ++ ++ for_each_child(node, c) { ++ if (any_local_fixup_tree(dti, c)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void add_local_fixup_entry(struct dt_info *dti, ++ struct node *lfn, struct node *node, ++ struct property *prop, struct marker *m, ++ struct node *refnode) ++{ ++ struct node *wn, *nwn; /* local fixup node, walk node, new */ ++ fdt32_t value_32; ++ char **compp; ++ int i, depth; ++ ++ /* walk back retreiving depth */ ++ depth = 0; ++ for (wn = node; wn; wn = wn->parent) ++ depth++; ++ ++ /* allocate name array */ ++ compp = xmalloc(sizeof(*compp) * depth); ++ ++ /* store names in the array */ ++ for (wn = node, i = depth - 1; wn; wn = wn->parent, i--) ++ compp[i] = wn->name; ++ ++ /* walk the path components creating nodes if they don't exist */ ++ for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { ++ /* if no node exists, create it */ ++ nwn = get_subnode(wn, compp[i]); ++ if (!nwn) ++ nwn = build_and_name_child_node(wn, compp[i]); ++ } ++ ++ free(compp); ++ ++ value_32 = cpu_to_fdt32(m->offset); ++ append_to_property(wn, prop->name, &value_32, sizeof(value_32)); ++} ++ ++static void generate_local_fixups_tree_internal(struct dt_info *dti, ++ struct node *lfn, ++ struct node *node) ++{ ++ struct node *dt = dti->dt; ++ struct node *c; ++ struct property *prop; ++ struct marker *m; ++ struct node *refnode; ++ ++ for_each_property(node, prop) { ++ m = prop->val.markers; ++ for_each_marker_of_type(m, REF_PHANDLE) { ++ refnode = get_node_by_ref(dt, m->ref); ++ if (refnode) ++ add_local_fixup_entry(dti, lfn, node, prop, m, refnode); ++ } ++ } ++ ++ for_each_child(node, c) ++ generate_local_fixups_tree_internal(dti, lfn, c); ++} ++ ++void generate_label_tree(struct dt_info *dti, char *name, bool allocph) ++{ ++ if (!any_label_tree(dti, dti->dt)) ++ return; ++ generate_label_tree_internal(dti, build_root_node(dti->dt, name), ++ dti->dt, allocph); ++} ++ ++void generate_fixups_tree(struct dt_info *dti, char *name) ++{ ++ if (!any_fixup_tree(dti, dti->dt)) ++ return; ++ generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), ++ dti->dt); ++} ++ ++void generate_local_fixups_tree(struct dt_info *dti, char *name) ++{ ++ if (!any_local_fixup_tree(dti, dti->dt)) ++ return; ++ generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), ++ dti->dt); + } +diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c +index f534c22a8..cb6ed0e3e 100644 +--- a/scripts/dtc/srcpos.c ++++ b/scripts/dtc/srcpos.c +@@ -209,8 +209,6 @@ struct srcpos srcpos_empty = { + .file = NULL, + }; + +-#define TAB_SIZE 8 +- + void srcpos_update(struct srcpos *pos, const char *text, int len) + { + int i; +@@ -224,9 +222,6 @@ void srcpos_update(struct srcpos *pos, const char *text, int len) + if (text[i] == '\n') { + current_srcfile->lineno++; + current_srcfile->colno = 1; +- } else if (text[i] == '\t') { +- current_srcfile->colno = +- ALIGN(current_srcfile->colno, TAB_SIZE); + } else { + current_srcfile->colno++; + } +@@ -246,46 +241,27 @@ srcpos_copy(struct srcpos *pos) + return pos_new; + } + +- +- +-void +-srcpos_dump(struct srcpos *pos) +-{ +- printf("file : \"%s\"\n", +- pos->file ? (char *) pos->file : ""); +- printf("first_line : %d\n", pos->first_line); +- printf("first_column: %d\n", pos->first_column); +- printf("last_line : %d\n", pos->last_line); +- printf("last_column : %d\n", pos->last_column); +- printf("file : %s\n", pos->file->name); +-} +- +- + char * + srcpos_string(struct srcpos *pos) + { + const char *fname = ""; + char *pos_str; +- int rc; + +- if (pos) ++ if (pos->file && pos->file->name) + fname = pos->file->name; + + + if (pos->first_line != pos->last_line) +- rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname, +- pos->first_line, pos->first_column, +- pos->last_line, pos->last_column); ++ xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname, ++ pos->first_line, pos->first_column, ++ pos->last_line, pos->last_column); + else if (pos->first_column != pos->last_column) +- rc = asprintf(&pos_str, "%s:%d.%d-%d", fname, +- pos->first_line, pos->first_column, +- pos->last_column); ++ xasprintf(&pos_str, "%s:%d.%d-%d", fname, ++ pos->first_line, pos->first_column, ++ pos->last_column); + else +- rc = asprintf(&pos_str, "%s:%d.%d", fname, +- pos->first_line, pos->first_column); +- +- if (rc == -1) +- die("Couldn't allocate in srcpos string"); ++ xasprintf(&pos_str, "%s:%d.%d", fname, ++ pos->first_line, pos->first_column); + + return pos_str; + } +diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h +index f81827bd6..9ded12a38 100644 +--- a/scripts/dtc/srcpos.h ++++ b/scripts/dtc/srcpos.h +@@ -17,11 +17,12 @@ + * USA + */ + +-#ifndef _SRCPOS_H_ +-#define _SRCPOS_H_ ++#ifndef SRCPOS_H ++#define SRCPOS_H + + #include + #include ++#include "util.h" + + struct srcfile_state { + FILE *f; +@@ -105,15 +106,12 @@ extern struct srcpos srcpos_empty; + extern void srcpos_update(struct srcpos *pos, const char *text, int len); + extern struct srcpos *srcpos_copy(struct srcpos *pos); + extern char *srcpos_string(struct srcpos *pos); +-extern void srcpos_dump(struct srcpos *pos); + +-extern void srcpos_verror(struct srcpos *pos, const char *prefix, +- const char *fmt, va_list va) +- __attribute__((format(printf, 3, 0))); +-extern void srcpos_error(struct srcpos *pos, const char *prefix, +- const char *fmt, ...) +- __attribute__((format(printf, 3, 4))); ++extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix, ++ const char *fmt, va_list va); ++extern void PRINTF(3, 4) srcpos_error(struct srcpos *pos, const char *prefix, ++ const char *fmt, ...); + + extern void srcpos_set_line(char *f, int l); + +-#endif /* _SRCPOS_H_ */ ++#endif /* SRCPOS_H */ +diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c +index a55d1d128..2461a3d06 100644 +--- a/scripts/dtc/treesource.c ++++ b/scripts/dtc/treesource.c +@@ -25,12 +25,12 @@ extern FILE *yyin; + extern int yyparse(void); + extern YYLTYPE yylloc; + +-struct boot_info *the_boot_info; ++struct dt_info *parser_output; + bool treesource_error; + +-struct boot_info *dt_from_source(const char *fname) ++struct dt_info *dt_from_source(const char *fname) + { +- the_boot_info = NULL; ++ parser_output = NULL; + treesource_error = false; + + srcfile_push(fname); +@@ -43,7 +43,7 @@ struct boot_info *dt_from_source(const char *fname) + if (treesource_error) + die("Syntax error parsing input tree\n"); + +- return the_boot_info; ++ return parser_output; + } + + static void write_prefix(FILE *f, int level) +@@ -137,7 +137,7 @@ static void write_propval_string(FILE *f, struct data val) + static void write_propval_cells(FILE *f, struct data val) + { + void *propend = val.val + val.len; +- cell_t *cp = (cell_t *)val.val; ++ fdt32_t *cp = (fdt32_t *)val.val; + struct marker *m = val.markers; + + fprintf(f, "<"); +@@ -263,22 +263,22 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) + } + + +-void dt_to_source(FILE *f, struct boot_info *bi) ++void dt_to_source(FILE *f, struct dt_info *dti) + { + struct reserve_info *re; + + fprintf(f, "/dts-v1/;\n\n"); + +- for (re = bi->reservelist; re; re = re->next) { ++ for (re = dti->reservelist; re; re = re->next) { + struct label *l; + + for_each_label(re->labels, l) + fprintf(f, "%s: ", l->label); + fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", +- (unsigned long long)re->re.address, +- (unsigned long long)re->re.size); ++ (unsigned long long)re->address, ++ (unsigned long long)re->size); + } + +- write_tree_source_node(f, bi->dt, 0); ++ write_tree_source_node(f, dti->dt, 0); + } + +diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh +index 075d1d7af..1a009fd19 100755 +--- a/scripts/dtc/update-dtc-source.sh ++++ b/scripts/dtc/update-dtc-source.sh +@@ -1,9 +1,10 @@ + #!/bin/sh ++# SPDX-License-Identifier: GPL-2.0 + # Simple script to update the version of DTC carried by the Linux kernel + # + # This script assumes that the dtc and the linux git trees are in the + # same directory. After building dtc in the dtc directory, it copies the +-# source files and generated source files into the scripts/dtc directory ++# source files and generated source file(s) into the scripts/dtc directory + # in the kernel and creates a git commit updating them to the new + # version. + # +@@ -32,16 +33,24 @@ DTC_LINUX_PATH=`pwd`/scripts/dtc + + DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \ + srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \ +- dtc-lexer.l dtc-parser.y fdtdump.c fdtput.c fdtget.c" +-DTC_LIB="fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c fdt_ro.c fdt_rw.c \ +- fdt_strerror.c fdt_sw.c fdt_wip.c libfdt.h libfdt_env.h \ +- libfdt_internal.h" +-DTC_GENERATED="dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h" ++ dtc-lexer.l dtc-parser.y" ++LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \ ++ fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \ ++ fdt_wip.c libfdt.h libfdt_env.h libfdt_internal.h" ++ ++get_last_dtc_version() { ++ git log --oneline scripts/dtc/ | grep 'upstream' | head -1 | sed -e 's/^.* \(.*\)/\1/' ++} ++ ++last_dtc_ver=$(get_last_dtc_version) + + # Build DTC + cd $DTC_UPSTREAM_PATH + make clean + make check ++dtc_version=$(git describe HEAD) ++dtc_log=$(git log --oneline ${last_dtc_ver}..) ++ + + # Copy the files into the Linux tree + cd $DTC_LINUX_PATH +@@ -49,13 +58,22 @@ for f in $DTC_SOURCE; do + cp ${DTC_UPSTREAM_PATH}/${f} ${f} + git add ${f} + done +-for f in $DTC_LIB; do +- cp ${DTC_UPSTREAM_PATH}/libfdt/${f} ${f} +- git add ${f} +-done +-for f in $DTC_GENERATED; do +- cp ${DTC_UPSTREAM_PATH}/$f ${f}_shipped +- git add ${f}_shipped ++for f in $LIBFDT_SOURCE; do ++ cp ${DTC_UPSTREAM_PATH}/libfdt/${f} libfdt/${f} ++ git add libfdt/${f} + done + +-git commit -e -v -m "scripts/dtc: Update to upstream version [CHANGEME]" ++sed -i -- 's/#include /#include "libfdt_env.h"/g' ./libfdt/libfdt.h ++sed -i -- 's/#include /#include "fdt.h"/g' ./libfdt/libfdt.h ++git add ./libfdt/libfdt.h ++ ++commit_msg=$(cat << EOF ++scripts/dtc: Update to upstream version ${dtc_version} ++ ++This adds the following commits from upstream: ++ ++${dtc_log} ++EOF ++) ++ ++git commit -e -v -s -m "${commit_msg}" +diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c +index 9d65226df..9953c32a0 100644 +--- a/scripts/dtc/util.c ++++ b/scripts/dtc/util.c +@@ -46,6 +46,36 @@ char *xstrdup(const char *s) + return d; + } + ++/* based in part from (3) vsnprintf */ ++int xasprintf(char **strp, const char *fmt, ...) ++{ ++ int n, size = 128; /* start with 128 bytes */ ++ char *p; ++ va_list ap; ++ ++ /* initial pointer is NULL making the fist realloc to be malloc */ ++ p = NULL; ++ while (1) { ++ p = xrealloc(p, size); ++ ++ /* Try to print in the allocated space. */ ++ va_start(ap, fmt); ++ n = vsnprintf(p, size, fmt, ap); ++ va_end(ap); ++ ++ /* If that worked, return the string. */ ++ if (n > -1 && n < size) ++ break; ++ /* Else try again with more space. */ ++ if (n > -1) /* glibc 2.1 */ ++ size = n + 1; /* precisely what is needed */ ++ else /* glibc 2.0 */ ++ size *= 2; /* twice the old size */ ++ } ++ *strp = p; ++ return strlen(p); ++} ++ + char *join_path(const char *path, const char *name) + { + int lenp = strlen(path); +@@ -152,7 +182,6 @@ char get_escape_char(const char *s, int *i) + int j = *i + 1; + char val; + +- assert(c); + switch (c) { + case 'a': + val = '\a'; +@@ -349,7 +378,6 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) + void utilfdt_print_data(const char *data, int len) + { + int i; +- const char *p = data; + const char *s; + + /* no data, don't print */ +@@ -368,7 +396,7 @@ void utilfdt_print_data(const char *data, int len) + } while (s < data + len); + + } else if ((len % 4) == 0) { +- const uint32_t *cell = (const uint32_t *)data; ++ const fdt32_t *cell = (const fdt32_t *)data; + + printf(" = <"); + for (i = 0, len /= 4; i < len; i++) +@@ -376,6 +404,7 @@ void utilfdt_print_data(const char *data, int len) + i < (len - 1) ? " " : ""); + printf(">"); + } else { ++ const unsigned char *p = (const unsigned char *)data; + printf(" = ["); + for (i = 0; i < len; i++) + printf("%02x%s", *p++, i < len - 1 ? " " : ""); +@@ -383,15 +412,16 @@ void utilfdt_print_data(const char *data, int len) + } + } + +-void util_version(void) ++void NORETURN util_version(void) + { + printf("Version: %s\n", DTC_VERSION); + exit(0); + } + +-void util_usage(const char *errmsg, const char *synopsis, +- const char *short_opts, struct option const long_opts[], +- const char * const opts_help[]) ++void NORETURN util_usage(const char *errmsg, const char *synopsis, ++ const char *short_opts, ++ struct option const long_opts[], ++ const char * const opts_help[]) + { + FILE *fp = errmsg ? stderr : stdout; + const char a_arg[] = ""; +diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h +index ccfdf4b12..66fba8ea7 100644 +--- a/scripts/dtc/util.h ++++ b/scripts/dtc/util.h +@@ -1,5 +1,5 @@ +-#ifndef _UTIL_H +-#define _UTIL_H ++#ifndef UTIL_H ++#define UTIL_H + + #include + #include +@@ -25,15 +25,27 @@ + * USA + */ + ++#ifdef __GNUC__ ++#define PRINTF(i, j) __attribute__((format (printf, i, j))) ++#define NORETURN __attribute__((noreturn)) ++#else ++#define PRINTF(i, j) ++#define NORETURN ++#endif ++ + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +-static inline void __attribute__((noreturn)) die(const char *str, ...) ++#define stringify(s) stringify_(s) ++#define stringify_(s) #s ++ ++static inline void NORETURN PRINTF(1, 2) die(const char *str, ...) + { + va_list ap; + + va_start(ap, str); + fprintf(stderr, "FATAL ERROR: "); + vfprintf(stderr, str, ap); ++ va_end(ap); + exit(1); + } + +@@ -52,12 +64,14 @@ static inline void *xrealloc(void *p, size_t len) + void *new = realloc(p, len); + + if (!new) +- die("realloc() failed (len=%d)\n", len); ++ die("realloc() failed (len=%zd)\n", len); + + return new; + } + + extern char *xstrdup(const char *s); ++ ++extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...); + extern char *join_path(const char *path, const char *name); + + /** +@@ -186,7 +200,7 @@ void utilfdt_print_data(const char *data, int len); + /** + * Show source version and exit + */ +-void util_version(void) __attribute__((noreturn)); ++void NORETURN util_version(void); + + /** + * Show usage and exit +@@ -200,9 +214,10 @@ void util_version(void) __attribute__((noreturn)); + * @param long_opts The structure of long options + * @param opts_help An array of help strings (should align with long_opts) + */ +-void util_usage(const char *errmsg, const char *synopsis, +- const char *short_opts, struct option const long_opts[], +- const char * const opts_help[]) __attribute__((noreturn)); ++void NORETURN util_usage(const char *errmsg, const char *synopsis, ++ const char *short_opts, ++ struct option const long_opts[], ++ const char * const opts_help[]); + + /** + * Show usage and exit +@@ -248,4 +263,4 @@ void util_usage(const char *errmsg, const char *synopsis, + case 'V': util_version(); \ + case '?': usage("unknown option"); + +-#endif /* _UTIL_H */ ++#endif /* UTIL_H */ +diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h +index 607afac1c..89d4e0ad1 100644 +--- a/scripts/dtc/version_gen.h ++++ b/scripts/dtc/version_gen.h +@@ -1 +1 @@ +-#define DTC_VERSION "DTC 1.4.1" ++#define DTC_VERSION "DTC 1.4.6" +-- +2.17.0 +