diff options
42 files changed, 4057 insertions, 712 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt new file mode 100644 index 00000000000..72a06c0ab1d --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt @@ -0,0 +1,95 @@ +Specifying interrupt information for devices +============================================ + +1) Interrupt client nodes +------------------------- + +Nodes that describe devices which generate interrupts must contain an +"interrupts" property. This property must contain a list of interrupt +specifiers, one per output interrupt. The format of the interrupt specifier is +determined by the interrupt controller to which the interrupts are routed; see +section 2 below for details. + +The "interrupt-parent" property is used to specify the controller to which +interrupts are routed and contains a single phandle referring to the interrupt +controller node. This property is inherited, so it may be specified in an +interrupt client node or in any of its parent nodes. + +2) Interrupt controller nodes +----------------------------- + +A device is marked as an interrupt controller with the "interrupt-controller" +property. This is a empty, boolean property. An additional "#interrupt-cells" +property defines the number of cells needed to specify a single interrupt. + +It is the responsibility of the interrupt controller's binding to define the +length and format of the interrupt specifier. The following two variants are +commonly used: + + a) one cell + ----------- + The #interrupt-cells property is set to 1 and the single cell defines the + index of the interrupt within the controller. + + Example: + + vic: intc@10140000 { + compatible = "arm,versatile-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10140000 0x1000>; + }; + + sic: intc@10003000 { + compatible = "arm,versatile-sic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10003000 0x1000>; + interrupt-parent = <&vic>; + interrupts = <31>; /* Cascaded to vic */ + }; + + b) two cells + ------------ + The #interrupt-cells property is set to 2 and the first cell defines the + index of the interrupt within the controller, while the second cell is used + to specify any of the following flags: + - bits[3:0] trigger type and level flags + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + + Example: + + i2c@7000c000 { + gpioext: gpio-adnp@41 { + compatible = "ad,gpio-adnp"; + reg = <0x41>; + + interrupt-parent = <&gpio>; + interrupts = <160 1>; + + gpio-controller; + #gpio-cells = <1>; + + interrupt-controller; + #interrupt-cells = <2>; + + nr-gpios = <64>; + }; + + sx8634@2b { + compatible = "smtc,sx8634"; + reg = <0x2b>; + + interrupt-parent = <&gpioext>; + interrupts = <3 0x8>; + + #address-cells = <1>; + #size-cells = <0>; + + threshold = <0x40>; + sensitivity = <7>; + }; + }; diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt index b16f4a57d11..11963e4d6bc 100644 --- a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt @@ -11,7 +11,7 @@ Example: pwm: pwm@80064000 { compatible = "fsl,imx28-pwm", "fsl,imx23-pwm"; - reg = <0x80064000 2000>; + reg = <0x80064000 0x2000>; #pwm-cells = <2>; fsl,pwm-number = <8>; }; diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt new file mode 100644 index 00000000000..c58573b5b1a --- /dev/null +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt @@ -0,0 +1,35 @@ +* Freescale i.MX UART controller + +Required properties: +- compatible : should be "fsl,imx21-uart" +- reg : Address and length of the register set for the device +- interrupts : Should contain UART interrupt number + +Optional properties: +- fsl,uart-has-rtscts: indicate that RTS/CTS signals are used + +Note: Each uart controller should have an alias correctly numbered +in "aliases" node. + +Example: + +- From imx51.dtsi: +aliases { + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; +}; + +uart1: serial@73fbc000 { + compatible = "fsl,imx51-uart", "fsl,imx21-uart"; + reg = <0x73fbc000 0x4000>; + interrupts = <31>; + status = "disabled"; +} + +- From imx51-babbage.dts: +uart1: serial@73fbc000 { + fsl,uart-has-rtscts; + status = "okay"; +}; + diff --git a/MAINTAINERS b/MAINTAINERS index 28167d0f8b4..d919e3d4a0d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5067,6 +5067,7 @@ S: Maintained F: Documentation/devicetree F: drivers/of F: include/linux/of*.h +F: scripts/dtc K: of_get_property K: of_match_table diff --git a/drivers/of/address.c b/drivers/of/address.c index 7e262a6124c..72e496f1e9b 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -9,8 +9,8 @@ /* Max address size we deal with */ #define OF_MAX_ADDR_CELLS 4 -#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ - (ns) > 0) +#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) +#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0) static struct of_bus *of_match_bus(struct device_node *np); static int __of_address_to_resource(struct device_node *dev, @@ -69,6 +69,14 @@ static u64 of_bus_default_map(u32 *addr, const __be32 *range, (unsigned long long)cp, (unsigned long long)s, (unsigned long long)da); + /* + * If the number of address cells is larger than 2 we assume the + * mapping doesn't specify a physical address. Rather, the address + * specifies an identifier that must match exactly. + */ + if (na > 2 && memcmp(range, addr, na * 4) != 0) + return OF_BAD_ADDR; + if (da < cp || da >= (cp + s)) return OF_BAD_ADDR; return da - cp; @@ -182,7 +190,7 @@ const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, } bus->count_cells(dev, &na, &ns); of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) + if (!OF_CHECK_ADDR_COUNT(na)) return NULL; /* Get "reg" or "assigned-addresses" property */ @@ -490,6 +498,25 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) } EXPORT_SYMBOL(of_translate_dma_address); +bool of_can_translate_address(struct device_node *dev) +{ + struct device_node *parent; + struct of_bus *bus; + int na, ns; + + parent = of_get_parent(dev); + if (parent == NULL) + return false; + + bus = of_match_bus(parent); + bus->count_cells(dev, &na, &ns); + + of_node_put(parent); + + return OF_CHECK_COUNTS(na, ns); +} +EXPORT_SYMBOL(of_can_translate_address); + const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) { @@ -506,7 +533,7 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, bus = of_match_bus(parent); bus->count_cells(dev, &na, &ns); of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) + if (!OF_CHECK_ADDR_COUNT(na)) return NULL; /* Get "reg" or "assigned-addresses" property */ diff --git a/drivers/of/base.c b/drivers/of/base.c index d4a1c9a043e..af3b22ac762 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -391,6 +391,29 @@ struct device_node *of_get_next_available_child(const struct device_node *node, EXPORT_SYMBOL(of_get_next_available_child); /** + * of_get_child_by_name - Find the child node by name for a given parent + * @node: parent node + * @name: child name to look for. + * + * This function looks for child node for given matching name + * + * Returns a node pointer if found, with refcount incremented, use + * of_node_put() on it when done. + * Returns NULL if node is not found. + */ +struct device_node *of_get_child_by_name(const struct device_node *node, + const char *name) +{ + struct device_node *child; + + for_each_child_of_node(node, child) + if (child->name && (of_node_cmp(child->name, name) == 0)) + break; + return child; +} +EXPORT_SYMBOL(of_get_child_by_name); + +/** * of_find_node_by_path - Find a node matching a full OF path * @path: The full path to match * diff --git a/drivers/of/irq.c b/drivers/of/irq.c index ff8ab7b2737..a23ec777999 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -392,6 +392,7 @@ int of_irq_to_resource_table(struct device_node *dev, struct resource *res, return i; } +EXPORT_SYMBOL_GPL(of_irq_to_resource_table); struct intc_desc { struct list_head list; diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index 1e173f35767..3550f3bf4f9 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -61,6 +61,9 @@ void of_i2c_register_devices(struct i2c_adapter *adap) info.of_node = of_node_get(node); info.archdata = &dev_ad; + if (of_get_property(node, "wakeup-source", NULL)) + info.flags |= I2C_CLIENT_WAKE; + request_module("%s%s", I2C_MODULE_PREFIX, info.type); result = i2c_new_device(adap, &info); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index e44f8c2d239..9bdeaf30b17 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -78,6 +78,7 @@ void of_device_make_bus_id(struct device *dev) struct device_node *node = dev->of_node; const u32 *reg; u64 addr; + const __be32 *addrp; int magic; #ifdef CONFIG_PPC_DCR @@ -105,7 +106,15 @@ void of_device_make_bus_id(struct device *dev) */ reg = of_get_property(node, "reg", NULL); if (reg) { - addr = of_translate_address(node, reg); + if (of_can_translate_address(node)) { + addr = of_translate_address(node, reg); + } else { + addrp = of_get_address(node, 0, NULL, NULL); + if (addrp) + addr = of_read_number(addrp, 1); + else + addr = OF_BAD_ADDR; + } if (addr != OF_BAD_ADDR) { dev_set_name(dev, "%llx.%s", (unsigned long long)addr, node->name); @@ -140,8 +149,9 @@ struct platform_device *of_device_alloc(struct device_node *np, return NULL; /* count the io and irq resources */ - while (of_address_to_resource(np, num_reg, &temp_res) == 0) - num_reg++; + if (of_can_translate_address(np)) + while (of_address_to_resource(np, num_reg, &temp_res) == 0) + num_reg++; num_irq = of_irq_count(np); /* Populate the resource table */ diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 1860c3aca7e..1a81c90a4a7 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -835,9 +835,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( return ERR_PTR(-EINVAL); } - for_each_child_of_node(slave_np, data_np) - if (!strcmp(data_np->name, "controller-data")) - break; + data_np = of_get_child_by_name(slave_np, "controller-data"); if (!data_np) { dev_err(&spi->dev, "child node 'controller-data' not found\n"); return ERR_PTR(-EINVAL); @@ -847,6 +845,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( if (!cs) { dev_err(&spi->dev, "could not allocate memory for controller" " data\n"); + of_node_put(data_np); return ERR_PTR(-ENOMEM); } @@ -855,11 +854,13 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( dev_err(&spi->dev, "chip select gpio is not specified or " "invalid\n"); kfree(cs); + of_node_put(data_np); return ERR_PTR(-EINVAL); } of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay); cs->fb_delay = fb_delay; + of_node_put(data_np); return cs; } diff --git a/include/linux/of.h b/include/linux/of.h index 1b1163225f3..f594c528842 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -193,6 +193,8 @@ extern struct device_node *of_get_next_child(const struct device_node *node, extern struct device_node *of_get_next_available_child( const struct device_node *node, struct device_node *prev); +extern struct device_node *of_get_child_by_name(const struct device_node *node, + const char *name); #define for_each_child_of_node(parent, child) \ for (child = of_get_next_child(parent, NULL); child != NULL; \ child = of_get_next_child(parent, child)) diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 01b925ad8d7..c3cdc1025c3 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -6,6 +6,7 @@ #ifdef CONFIG_OF_ADDRESS extern u64 of_translate_address(struct device_node *np, const __be32 *addr); +extern bool of_can_translate_address(struct device_node *dev); extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); extern struct device_node *of_find_matching_node_by_address( diff --git a/scripts/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc index 6ddf9ecac66..bece49b3553 100644 --- a/scripts/dtc/Makefile.dtc +++ b/scripts/dtc/Makefile.dtc @@ -3,7 +3,16 @@ # This is not a complete Makefile of itself. Instead, it is designed to # be easily embeddable into other systems of Makefiles. # -DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \ - checks.c +DTC_SRCS = \ + checks.c \ + data.c \ + dtc.c \ + flattree.c \ + fstree.c \ + livetree.c \ + srcpos.c \ + treesource.c \ + util.c + DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index a662a004479..ee96a2519ef 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -31,12 +31,6 @@ #define TRACE(c, fmt, ...) do { } while (0) #endif -enum checklevel { - IGNORE = 0, - WARN = 1, - ERROR = 2, -}; - enum checkstatus { UNCHECKED = 0, PREREQ, @@ -57,14 +51,14 @@ struct check { node_check_fn node_fn; prop_check_fn prop_fn; void *data; - enum checklevel level; + bool warn, error; enum checkstatus status; int inprogress; int num_prereqs; struct check **prereq; }; -#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \ +#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ static struct check nm = { \ .name = #nm, \ @@ -72,20 +66,37 @@ struct check { .node_fn = (nfn), \ .prop_fn = (pfn), \ .data = (d), \ - .level = (lvl), \ + .warn = (w), \ + .error = (e), \ .status = UNCHECKED, \ .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ .prereq = nm##_prereqs, \ }; - -#define TREE_CHECK(nm, d, lvl, ...) \ - CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__) -#define NODE_CHECK(nm, d, lvl, ...) \ - CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__) -#define PROP_CHECK(nm, d, lvl, ...) \ - CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__) -#define BATCH_CHECK(nm, lvl, ...) \ - CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__) +#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))); @@ -95,13 +106,13 @@ static inline void check_msg(struct check *c, const char *fmt, ...) va_list ap; va_start(ap, fmt); - if ((c->level < WARN) || (c->level <= quiet)) - return; /* Suppress message */ - - fprintf(stderr, "%s (%s): ", - (c->level == ERROR) ? "ERROR" : "Warning", c->name); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); + if ((c->warn && (quiet < 1)) + || (c->error && (quiet < 2))) { + fprintf(stderr, "%s (%s): ", + (c->error) ? "ERROR" : "Warning", c->name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } } #define FAIL(c, ...) \ @@ -167,7 +178,7 @@ static int run_check(struct check *c, struct node *dt) out: c->inprogress = 0; - if ((c->status != PASSED) && (c->level == ERROR)) + if ((c->status != PASSED) && (c->error)) error = 1; return error; } @@ -176,6 +187,13 @@ out: * Utility check functions */ +/* A check which always fails, for testing purposes only */ +static inline void check_always_fail(struct check *c, struct node *dt) +{ + FAIL(c, "always_fail check"); +} +TREE_CHECK(always_fail, NULL); + static void check_is_string(struct check *c, struct node *root, struct node *node) { @@ -190,8 +208,10 @@ static void check_is_string(struct check *c, struct node *root, FAIL(c, "\"%s\" property in %s is not a string", propname, node->fullpath); } -#define CHECK_IS_STRING(nm, propname, lvl) \ - CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl)) +#define WARNING_IF_NOT_STRING(nm, propname) \ + WARNING(nm, NULL, check_is_string, NULL, (propname)) +#define ERROR_IF_NOT_STRING(nm, propname) \ + ERROR(nm, NULL, check_is_string, NULL, (propname)) static void check_is_cell(struct check *c, struct node *root, struct node *node) @@ -207,8 +227,10 @@ static void check_is_cell(struct check *c, struct node *root, FAIL(c, "\"%s\" property in %s is not a single cell", propname, node->fullpath); } -#define CHECK_IS_CELL(nm, propname, lvl) \ - CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl)) +#define WARNING_IF_NOT_CELL(nm, propname) \ + WARNING(nm, NULL, check_is_cell, NULL, (propname)) +#define ERROR_IF_NOT_CELL(nm, propname) \ + ERROR(nm, NULL, check_is_cell, NULL, (propname)) /* * Structural check functions @@ -227,20 +249,24 @@ static void check_duplicate_node_names(struct check *c, struct node *dt, FAIL(c, "Duplicate node name %s", child->fullpath); } -NODE_CHECK(duplicate_node_names, NULL, ERROR); +NODE_ERROR(duplicate_node_names, NULL); static void check_duplicate_property_names(struct check *c, struct node *dt, struct node *node) { struct property *prop, *prop2; - for_each_property(node, prop) - for (prop2 = prop->next; prop2; prop2 = prop2->next) + for_each_property(node, prop) { + for (prop2 = prop->next; prop2; prop2 = prop2->next) { + if (prop2->deleted) + continue; if (streq(prop->name, prop2->name)) FAIL(c, "Duplicate property name %s in %s", prop->name, node->fullpath); + } + } } -NODE_CHECK(duplicate_property_names, NULL, ERROR); +NODE_ERROR(duplicate_property_names, NULL); #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -256,7 +282,7 @@ static void check_node_name_chars(struct check *c, struct node *dt, FAIL(c, "Bad character '%c' in node %s", node->name[n], node->fullpath); } -NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR); +NODE_ERROR(node_name_chars, PROPNODECHARS "@"); static void check_node_name_format(struct check *c, struct node *dt, struct node *node) @@ -265,7 +291,7 @@ static void check_node_name_format(struct check *c, struct node *dt, FAIL(c, "Node %s has multiple '@' characters in name", node->fullpath); } -NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars); +NODE_ERROR(node_name_format, NULL, &node_name_chars); static void check_property_name_chars(struct check *c, struct node *dt, struct node *node, struct property *prop) @@ -276,7 +302,7 @@ static void check_property_name_chars(struct check *c, struct node *dt, FAIL(c, "Bad character '%c' in property name \"%s\", node %s", prop->name[n], prop->name, node->fullpath); } -PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR); +PROP_ERROR(property_name_chars, PROPNODECHARS); #define DESCLABEL_FMT "%s%s%s%s%s" #define DESCLABEL_ARGS(node,prop,mark) \ @@ -331,8 +357,8 @@ static void check_duplicate_label_prop(struct check *c, struct node *dt, for_each_marker_of_type(m, LABEL) check_duplicate_label(c, dt, m->ref, node, prop, m); } -CHECK(duplicate_label, NULL, check_duplicate_label_node, - check_duplicate_label_prop, NULL, ERROR); +ERROR(duplicate_label, NULL, check_duplicate_label_node, + check_duplicate_label_prop, NULL); static void check_explicit_phandles(struct check *c, struct node *root, struct node *node, struct property *prop) @@ -391,7 +417,7 @@ static void check_explicit_phandles(struct check *c, struct node *root, node->phandle = phandle; } -PROP_CHECK(explicit_phandles, NULL, ERROR); +PROP_ERROR(explicit_phandles, NULL); static void check_name_properties(struct check *c, struct node *root, struct node *node) @@ -420,8 +446,8 @@ static void check_name_properties(struct check *c, struct node *root, free(prop); } } -CHECK_IS_STRING(name_is_string, "name", ERROR); -NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); +ERROR_IF_NOT_STRING(name_is_string, "name"); +NODE_ERROR(name_properties, NULL, &name_is_string); /* * Reference fixup functions @@ -448,7 +474,7 @@ static void fixup_phandle_references(struct check *c, struct node *dt, *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } } -CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR, +ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, &duplicate_node_names, &explicit_phandles); static void fixup_path_references(struct check *c, struct node *dt, @@ -473,19 +499,19 @@ static void fixup_path_references(struct check *c, struct node *dt, strlen(path) + 1); } } -CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR, +ERROR(path_references, NULL, NULL, fixup_path_references, NULL, &duplicate_node_names); /* * Semantic checks */ -CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN); -CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN); -CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN); +WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); +WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); +WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); -CHECK_IS_STRING(device_type_is_string, "device_type", WARN); -CHECK_IS_STRING(model_is_string, "model", WARN); -CHECK_IS_STRING(status_is_string, "status", WARN); +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"); static void fixup_addr_size_cells(struct check *c, struct node *dt, struct node *node) @@ -503,8 +529,8 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt, if (prop) node->size_cells = propval_cell(prop); } -CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN, - &address_cells_is_cell, &size_cells_is_cell); +WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, + &address_cells_is_cell, &size_cells_is_cell); #define node_addr_cells(n) \ (((n)->addr_cells == -1) ? 2 : (n)->addr_cells) @@ -538,7 +564,7 @@ static void check_reg_format(struct check *c, struct node *dt, "(#address-cells == %d, #size-cells == %d)", node->fullpath, prop->val.len, addr_cells, size_cells); } -NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells); +NODE_WARNING(reg_format, NULL, &addr_size_cells); static void check_ranges_format(struct check *c, struct node *dt, struct node *node) @@ -579,7 +605,7 @@ static void check_ranges_format(struct check *c, struct node *dt, p_addr_cells, c_addr_cells, c_size_cells); } } -NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells); +NODE_WARNING(ranges_format, NULL, &addr_size_cells); /* * Style checks @@ -606,7 +632,7 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt, FAIL(c, "Relying on default #size-cells value for %s", node->fullpath); } -NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells); +NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); static void check_obsolete_chosen_interrupt_controller(struct check *c, struct node *dt) @@ -623,7 +649,7 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, FAIL(c, "/chosen has obsolete \"interrupt-controller\" " "property"); } -TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN); +TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, @@ -642,8 +668,71 @@ static struct check *check_table[] = { &avoid_default_addr_size, &obsolete_chosen_interrupt_controller, + + &always_fail, }; +static void enable_warning_error(struct check *c, bool warn, bool error) +{ + int i; + + /* Raising level, also raise it for prereqs */ + if ((warn && !c->warn) || (error && !c->error)) + for (i = 0; i < c->num_prereqs; i++) + enable_warning_error(c->prereq[i], warn, error); + + c->warn = c->warn || warn; + c->error = c->error || error; +} + +static void disable_warning_error(struct check *c, bool warn, bool error) +{ + int i; + + /* Lowering level, also lower it for things this is the prereq + * for */ + if ((warn && c->warn) || (error && c->error)) { + for (i = 0; i < ARRAY_SIZE(check_table); i++) { + struct check *cc = check_table[i]; + int j; + + for (j = 0; j < cc->num_prereqs; j++) + if (cc->prereq[j] == c) + disable_warning_error(cc, warn, error); + } + } + + c->warn = c->warn && !warn; + c->error = c->error && !error; +} + +void parse_checks_option(bool warn, bool error, const char *optarg) +{ + int i; + const char *name = optarg; + bool enable = true; + + if ((strncmp(optarg, "no-", 3) == 0) + || (strncmp(optarg, "no_", 3) == 0)) { + name = optarg + 3; + enable = false; + } + + for (i = 0; i < ARRAY_SIZE(check_table); i++) { + struct check *c = check_table[i]; + + if (streq(c->name, name)) { + if (enable) + enable_warning_error(c, warn, error); + else + disable_warning_error(c, warn, error); + return; + } + } + + die("Unrecognized check name \"%s\"\n", name); +} + void process_checks(int force, struct boot_info *bi) { struct node *dt = bi->dt; @@ -653,7 +742,7 @@ void process_checks(int force, struct boot_info *bi) for (i = 0; i < ARRAY_SIZE(check_table); i++) { struct check *c = check_table[i]; - if (c->level != IGNORE) + if (c->warn || c->error) error = error || run_check(c, dt); } diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index fe555e819bf..4a40c5b9247 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -68,40 +68,6 @@ struct data data_copy_mem(const char *mem, int len) return d; } -static char get_oct_char(const char *s, int *i) -{ - char x[4]; - char *endx; - long val; - - x[3] = '\0'; - strncpy(x, s + *i, 3); - - val = strtol(x, &endx, 8); - - assert(endx > x); - - (*i) += endx - x; - return val; -} - -static char get_hex_char(const char *s, int *i) -{ - char x[3]; - char *endx; - long val; - - x[2] = '\0'; - strncpy(x, s + *i, 2); - - val = strtol(x, &endx, 16); - if (!(endx > x)) - die("\\x used with no following hex digits\n"); - - (*i) += endx - x; - return val; -} - struct data data_copy_escape_string(const char *s, int len) { int i = 0; @@ -114,53 +80,10 @@ struct data data_copy_escape_string(const char *s, int len) while (i < len) { char c = s[i++]; - if (c != '\\') { - q[d.len++] = c; - continue; - } - - c = s[i++]; - assert(c); - switch (c) { - case 'a': - q[d.len++] = '\a'; - break; - case 'b': - q[d.len++] = '\b'; - break; - case 't': - q[d.len++] = '\t'; - break; - case 'n': - q[d.len++] = '\n'; - break; - case 'v': - q[d.len++] = '\v'; - break; - case 'f': - q[d.len++] = '\f'; - break; - case 'r': - q[d.len++] = '\r'; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - i--; /* need to re-read the first digit as - * part of the octal value */ - q[d.len++] = get_oct_char(s, &i); - break; - case 'x': - q[d.len++] = get_hex_char(s, &i); - break; - default: - q[d.len++] = c; - } + if (c == '\\') + c = get_escape_char(s, &i); + + q[d.len++] = c; } q[d.len++] = '\0'; @@ -245,11 +168,33 @@ struct data data_merge(struct data d1, struct data d2) return d; } -struct data data_append_cell(struct data d, cell_t word) +struct data data_append_integer(struct data d, uint64_t value, int bits) { - cell_t beword = cpu_to_fdt32(word); - - return data_append_data(d, &beword, sizeof(beword)); + uint8_t value_8; + uint16_t value_16; + uint32_t value_32; + uint64_t value_64; + + switch (bits) { + case 8: + value_8 = value; + return data_append_data(d, &value_8, 1); + + case 16: + value_16 = cpu_to_fdt16(value); + return data_append_data(d, &value_16, 2); + + case 32: + value_32 = cpu_to_fdt32(value); + return data_append_data(d, &value_32, 4); + + case 64: + value_64 = cpu_to_fdt64(value); + return data_append_data(d, &value_64, 8); + + default: + die("Invalid literal size (%d)\n", bits); + } } struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) @@ -262,11 +207,14 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) return data_append_data(d, &bere, sizeof(bere)); } -struct data data_append_addr(struct data d, uint64_t addr) +struct data data_append_cell(struct data d, cell_t word) { - uint64_t beaddr = cpu_to_fdt64(addr); + return data_append_integer(d, word, sizeof(word) * 8); +} - return data_append_data(d, &beaddr, sizeof(beaddr)); +struct data data_append_addr(struct data d, uint64_t addr) +{ + return data_append_integer(d, addr, sizeof(addr) * 8); } struct data data_append_byte(struct data d, uint8_t byte) diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index e866ea5166a..254d5af8895 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -29,6 +29,7 @@ PROPNODECHAR [a-zA-Z0-9,._+*#?@-] PATHCHAR ({PROPNODECHAR}|[/]) LABEL [a-zA-Z_][a-zA-Z0-9_]* STRING \"([^\\"]|\\.)*\" +CHAR_LITERAL '([^']|\\')*' WS [[:space:]] COMMENT "/*"([^*]|\*+[^*/])*\*+"/" LINECOMMENT "//".*\n @@ -70,6 +71,27 @@ static int pop_input_file(void); push_input_file(name); } +<*>^"#"(line)?{WS}+[0-9]+{WS}+{STRING}({WS}+[0-9]+)? { + char *line, *tmp, *fn; + /* skip text before line # */ + line = yytext; + while (!isdigit(*line)) + line++; + /* skip digits in line # */ + tmp = line; + while (!isspace(*tmp)) + tmp++; + /* "NULL"-terminate line # */ + *tmp = '\0'; + /* start of filename */ + fn = strchr(tmp + 1, '"') + 1; + /* strip trailing " from filename */ + tmp = strchr(fn, '"'); + *tmp = 0; + /* -1 since #line is the number of the next line */ + srcpos_set_line(xstrdup(fn), atoi(line) - 1); + } + <*><<EOF>> { if (!pop_input_file()) { yyterminate(); @@ -96,6 +118,26 @@ static int pop_input_file(void); return DT_MEMRESERVE; } +<*>"/bits/" { + DPRINT("Keyword: /bits/\n"); + BEGIN_DEFAULT(); + return DT_BITS; + } + +<*>"/delete-property/" { + DPRINT("Keyword: /delete-property/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_DEL_PROP; + } + +<*>"/delete-node/" { + DPRINT("Keyword: /delete-node/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_DEL_NODE; + } + <*>{LABEL}: { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -103,12 +145,19 @@ static int pop_input_file(void); return DT_LABEL; } -<V1>[0-9]+|0[xX][0-9a-fA-F]+ { +<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? { yylval.literal = xstrdup(yytext); DPRINT("Literal: '%s'\n", yylval.literal); return DT_LITERAL; } +<*>{CHAR_LITERAL} { + yytext[yyleng-1] = '\0'; + yylval.literal = xstrdup(yytext+1); + DPRINT("Character literal: %s\n", yylval.literal); + return DT_CHAR_LITERAL; + } + <*>\&{LABEL} { /* label reference */ DPRINT("Ref: %s\n", yytext+1); yylval.labelref = xstrdup(yytext+1); @@ -134,9 +183,10 @@ static int pop_input_file(void); return ']'; } -<PROPNODENAME>{PROPNODECHAR}+ { +<PROPNODENAME>\\?{PROPNODECHAR}+ { DPRINT("PropNodeName: %s\n", yytext); - yylval.propnodename = xstrdup(yytext); + yylval.propnodename = xstrdup((yytext[0] == '\\') ? + yytext + 1 : yytext); BEGIN_DEFAULT(); return DT_PROPNODENAME; } @@ -150,6 +200,15 @@ static int pop_input_file(void); <*>{COMMENT}+ /* eat C-style comments */ <*>{LINECOMMENT}+ /* eat C++-style comments */ +<*>"<<" { return DT_LSHIFT; }; +<*>">>" { return DT_RSHIFT; }; +<*>"<=" { return DT_LE; }; +<*>">=" { return DT_GE; }; +<*>"==" { return DT_EQ; }; +<*>"!=" { return DT_NE; }; +<*>"&&" { return DT_AND; }; +<*>"||" { return DT_OR; }; + <*>. { DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index 8bbe1281705..a6c5fcdfc03 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -1,5 +1,6 @@ +#line 2 "dtc-lexer.lex.c" -#line 3 "scripts/dtc/dtc-lexer.lex.c_shipped" +#line 4 "dtc-lexer.lex.c" #define YY_INT_ALIGNED short int @@ -53,7 +54,6 @@ typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN @@ -84,6 +84,8 @@ typedef unsigned int flex_uint32_t; #define UINT32_MAX (4294967295U) #endif +#endif /* ! C99 */ + #endif /* ! FLEXINT_H */ #ifdef __cplusplus @@ -140,7 +142,15 @@ typedef unsigned int flex_uint32_t; /* Size of default input buffer. */ #ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else #define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. @@ -362,8 +372,8 @@ static void yy_fatal_error (yyconst char msg[] ); *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 17 -#define YY_END_OF_BUFFER 18 +#define YY_NUM_RULES 30 +#define YY_END_OF_BUFFER 31 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -371,19 +381,25 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[94] = +static yyconst flex_int16_t yy_accept[161] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 18, 16, 13, 13, 16, 16, 16, 16, 16, 16, - 16, 10, 11, 11, 6, 6, 13, 0, 2, 0, - 7, 0, 0, 0, 0, 0, 0, 0, 5, 0, - 9, 9, 11, 11, 6, 0, 7, 0, 0, 0, - 0, 15, 0, 0, 0, 0, 6, 0, 14, 0, - 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 12, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 4, 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, 19, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 16, 13, 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 } ; static yyconst flex_int32_t yy_ec[256] = @@ -391,17 +407,17 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 1, 4, 5, 1, 1, 6, 1, 1, - 1, 7, 5, 5, 8, 5, 9, 10, 11, 12, - 12, 12, 12, 12, 12, 12, 12, 13, 1, 1, - 1, 1, 5, 5, 14, 14, 14, 14, 14, 14, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 16, 15, 15, - 1, 17, 18, 1, 15, 1, 14, 19, 20, 21, - - 22, 14, 15, 15, 23, 15, 15, 24, 25, 26, - 15, 15, 15, 27, 28, 29, 30, 31, 15, 16, - 15, 15, 32, 1, 33, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 1, 7, 8, 1, + 1, 9, 10, 10, 11, 10, 12, 13, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 1, 17, + 18, 19, 10, 10, 20, 20, 20, 20, 20, 20, + 21, 21, 21, 21, 21, 22, 21, 21, 21, 21, + 21, 21, 21, 21, 23, 21, 21, 24, 21, 21, + 1, 25, 26, 1, 21, 1, 20, 27, 28, 29, + + 30, 20, 21, 21, 31, 21, 21, 32, 33, 34, + 35, 36, 21, 37, 38, 39, 40, 41, 21, 24, + 42, 21, 43, 44, 45, 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, @@ -418,112 +434,163 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[34] = +static yyconst flex_int32_t yy_meta[46] = { 0, - 1, 1, 1, 1, 2, 1, 2, 2, 3, 4, - 4, 4, 5, 6, 7, 7, 1, 1, 6, 6, - 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 8, 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, 1 } ; -static yyconst flex_int16_t yy_base[106] = +static yyconst flex_int16_t yy_base[175] = { 0, - 0, 0, 237, 236, 25, 0, 47, 0, 30, 71, - 244, 247, 82, 84, 84, 211, 95, 229, 218, 0, - 111, 247, 0, 84, 83, 95, 106, 86, 247, 237, - 0, 230, 231, 234, 207, 209, 212, 220, 247, 206, - 247, 218, 0, 106, 116, 0, 0, 0, 223, 89, - 226, 219, 199, 206, 200, 204, 0, 190, 213, 212, - 202, 91, 178, 161, 247, 172, 144, 150, 140, 130, - 140, 124, 128, 120, 138, 137, 123, 122, 247, 247, - 134, 114, 132, 86, 135, 125, 90, 136, 247, 97, - 29, 247, 247, 153, 156, 161, 165, 170, 176, 180, - - 187, 195, 200, 205, 212 + 0, 388, 381, 40, 41, 386, 71, 385, 34, 44, + 390, 395, 60, 62, 371, 112, 111, 111, 111, 104, + 370, 106, 371, 342, 124, 119, 0, 144, 395, 0, + 123, 0, 159, 153, 165, 167, 395, 130, 395, 382, + 395, 0, 372, 122, 395, 157, 374, 379, 350, 21, + 346, 349, 395, 395, 395, 395, 395, 362, 395, 395, + 181, 346, 342, 395, 359, 0, 191, 343, 190, 351, + 350, 0, 0, 0, 173, 362, 177, 367, 357, 329, + 335, 328, 337, 331, 206, 329, 334, 327, 395, 338, + 170, 314, 346, 345, 318, 325, 343, 158, 316, 212, + + 322, 319, 320, 395, 340, 336, 308, 305, 314, 304, + 295, 138, 208, 220, 395, 292, 305, 265, 264, 254, + 201, 222, 285, 275, 273, 270, 236, 235, 225, 115, + 395, 395, 252, 216, 216, 217, 214, 230, 209, 220, + 213, 239, 211, 217, 216, 209, 229, 395, 240, 225, + 206, 169, 395, 395, 116, 106, 99, 54, 395, 395, + 254, 260, 268, 272, 276, 282, 289, 293, 301, 309, + 313, 319, 327, 335 } ; -static yyconst flex_int16_t yy_def[106] = +static yyconst flex_int16_t yy_def[175] = { 0, - 93, 1, 1, 1, 1, 5, 93, 7, 1, 1, - 93, 93, 93, 93, 94, 95, 93, 96, 17, 97, - 96, 93, 98, 99, 93, 93, 93, 94, 93, 94, - 100, 93, 101, 102, 93, 93, 93, 96, 93, 93, - 93, 96, 98, 99, 93, 103, 100, 104, 101, 101, - 102, 93, 93, 93, 93, 93, 103, 104, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 105, 93, 105, 93, 105, - 93, 93, 0, 93, 93, 93, 93, 93, 93, 93, - - 93, 93, 93, 93, 93 + 160, 1, 1, 1, 1, 5, 160, 7, 1, 1, + 160, 160, 160, 160, 160, 161, 162, 163, 160, 160, + 160, 160, 164, 160, 160, 160, 165, 164, 160, 166, + 167, 166, 166, 160, 160, 160, 160, 161, 160, 161, + 160, 168, 160, 163, 160, 163, 169, 170, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 164, 160, 160, + 160, 160, 160, 160, 164, 166, 167, 166, 160, 160, + 160, 171, 168, 172, 163, 169, 169, 170, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 166, 160, 160, + 171, 172, 160, 160, 160, 160, 160, 160, 160, 160, + + 160, 160, 166, 160, 160, 160, 160, 160, 160, 160, + 160, 173, 160, 166, 160, 160, 160, 160, 160, 160, + 173, 160, 173, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 174, 160, 160, 160, 174, 160, 174, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 0, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160 } ; -static yyconst flex_int16_t yy_nxt[281] = +static yyconst flex_int16_t yy_nxt[441] = { 0, - 12, 13, 14, 15, 12, 16, 12, 12, 17, 12, - 12, 12, 12, 18, 18, 18, 12, 12, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 12, 12, 19, 20, 20, 20, 92, 21, 25, - 26, 26, 22, 21, 21, 21, 21, 12, 13, 14, - 15, 23, 16, 23, 23, 19, 23, 23, 23, 12, - 24, 24, 24, 12, 12, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 12, 12, - 25, 26, 26, 27, 27, 27, 27, 29, 43, 29, - 43, 43, 45, 45, 45, 50, 39, 59, 46, 93, - - 30, 33, 30, 34, 45, 45, 45, 27, 27, 68, - 43, 91, 43, 43, 69, 35, 87, 36, 39, 37, - 42, 42, 42, 39, 42, 45, 45, 45, 89, 42, - 42, 42, 42, 85, 85, 86, 85, 85, 86, 89, - 84, 90, 83, 82, 81, 80, 79, 78, 77, 76, - 75, 74, 90, 28, 28, 28, 28, 28, 28, 28, - 28, 31, 31, 31, 38, 38, 38, 38, 41, 73, - 41, 43, 72, 43, 71, 43, 43, 44, 33, 44, - 44, 44, 44, 47, 69, 47, 47, 49, 49, 49, - 49, 49, 49, 49, 49, 51, 51, 51, 51, 51, - - 51, 51, 51, 57, 70, 57, 58, 58, 58, 67, - 58, 58, 88, 88, 88, 88, 88, 88, 88, 88, - 34, 66, 65, 64, 63, 62, 61, 60, 52, 50, - 39, 56, 39, 55, 54, 53, 52, 50, 48, 93, - 40, 39, 32, 93, 19, 19, 11, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93 + 12, 13, 14, 15, 16, 12, 17, 18, 12, 12, + 12, 19, 12, 12, 12, 12, 20, 21, 22, 23, + 23, 23, 23, 23, 12, 12, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 12, 24, 12, 25, 34, 35, 35, 25, + 81, 26, 26, 27, 27, 27, 34, 35, 35, 82, + 28, 36, 36, 36, 36, 159, 29, 28, 28, 28, + 28, 12, 13, 14, 15, 16, 30, 17, 18, 30, + 30, 30, 26, 30, 30, 30, 12, 20, 21, 22, + 31, 31, 31, 31, 31, 32, 12, 31, 31, 31, + + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 12, 24, 12, 39, 41, 45, 47, + 53, 54, 48, 56, 57, 61, 61, 47, 66, 45, + 48, 66, 66, 66, 39, 46, 40, 49, 59, 50, + 158, 51, 122, 52, 157, 49, 46, 50, 136, 63, + 137, 52, 156, 43, 40, 62, 65, 65, 65, 59, + 61, 61, 123, 65, 75, 69, 69, 69, 36, 36, + 65, 65, 65, 65, 70, 71, 72, 69, 69, 69, + 45, 46, 61, 61, 109, 77, 70, 71, 93, 110, + 68, 70, 71, 85, 85, 85, 66, 46, 155, 66, + + 66, 66, 69, 69, 69, 122, 59, 100, 100, 61, + 61, 70, 71, 100, 100, 148, 112, 154, 85, 85, + 85, 61, 61, 129, 129, 123, 129, 129, 135, 135, + 135, 142, 142, 148, 143, 149, 153, 135, 135, 135, + 142, 142, 160, 143, 152, 151, 150, 146, 145, 144, + 141, 140, 139, 149, 38, 38, 38, 38, 38, 38, + 38, 38, 42, 138, 134, 133, 42, 42, 44, 44, + 44, 44, 44, 44, 44, 44, 58, 58, 58, 58, + 64, 132, 64, 66, 131, 130, 66, 160, 66, 66, + 67, 128, 127, 67, 67, 67, 67, 73, 126, 73, + + 73, 76, 76, 76, 76, 76, 76, 76, 76, 78, + 78, 78, 78, 78, 78, 78, 78, 91, 125, 91, + 92, 124, 92, 92, 120, 92, 92, 121, 121, 121, + 121, 121, 121, 121, 121, 147, 147, 147, 147, 147, + 147, 147, 147, 119, 118, 117, 116, 115, 47, 114, + 110, 113, 111, 108, 107, 106, 48, 105, 104, 89, + 103, 102, 101, 99, 98, 97, 96, 95, 94, 79, + 77, 90, 89, 88, 59, 87, 86, 59, 84, 83, + 80, 79, 77, 74, 160, 60, 59, 55, 37, 160, + 33, 25, 26, 25, 11, 160, 160, 160, 160, 160, + + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160 } ; -static yyconst flex_int16_t yy_chk[281] = +static yyconst flex_int16_t yy_chk[441] = { 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, 5, 5, 5, 5, 91, 5, 9, - 9, 9, 5, 5, 5, 5, 5, 7, 7, 7, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 9, 9, 9, 10, + 50, 4, 5, 5, 5, 5, 10, 10, 10, 50, + 5, 13, 13, 14, 14, 158, 5, 5, 5, 5, + 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 10, 10, 10, 13, 13, 14, 14, 15, 24, 28, - 24, 24, 25, 25, 25, 50, 24, 50, 25, 90, - - 15, 17, 28, 17, 26, 26, 26, 27, 27, 62, - 44, 87, 44, 44, 62, 17, 84, 17, 44, 17, - 21, 21, 21, 21, 21, 45, 45, 45, 86, 21, - 21, 21, 21, 83, 83, 83, 85, 85, 85, 88, - 82, 86, 81, 78, 77, 76, 75, 74, 73, 72, - 71, 70, 88, 94, 94, 94, 94, 94, 94, 94, - 94, 95, 95, 95, 96, 96, 96, 96, 97, 69, - 97, 98, 68, 98, 67, 98, 98, 99, 66, 99, - 99, 99, 99, 100, 64, 100, 100, 101, 101, 101, - 101, 101, 101, 101, 101, 102, 102, 102, 102, 102, - - 102, 102, 102, 103, 63, 103, 104, 104, 104, 61, - 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, - 60, 59, 58, 56, 55, 54, 53, 52, 51, 49, - 42, 40, 38, 37, 36, 35, 34, 33, 32, 30, - 19, 18, 16, 11, 4, 3, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93 + 7, 7, 7, 7, 7, 7, 16, 17, 18, 19, + 20, 20, 19, 22, 22, 25, 25, 26, 31, 44, + 26, 31, 31, 31, 38, 18, 16, 19, 31, 19, + 157, 19, 112, 19, 156, 26, 44, 26, 130, 26, + 130, 26, 155, 17, 38, 25, 28, 28, 28, 28, + 33, 33, 112, 28, 46, 34, 34, 34, 36, 36, + 28, 28, 28, 28, 34, 34, 34, 35, 35, 35, + 75, 46, 61, 61, 98, 77, 35, 35, 77, 98, + 33, 91, 91, 61, 61, 61, 67, 75, 152, 67, + + 67, 67, 69, 69, 69, 121, 67, 85, 85, 113, + 113, 69, 69, 100, 100, 143, 100, 151, 85, 85, + 85, 114, 114, 122, 122, 121, 129, 129, 135, 135, + 135, 138, 138, 147, 138, 143, 150, 129, 129, 129, + 142, 142, 149, 142, 146, 145, 144, 141, 140, 139, + 137, 136, 134, 147, 161, 161, 161, 161, 161, 161, + 161, 161, 162, 133, 128, 127, 162, 162, 163, 163, + 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, + 165, 126, 165, 166, 125, 124, 166, 123, 166, 166, + 167, 120, 119, 167, 167, 167, 167, 168, 118, 168, + + 168, 169, 169, 169, 169, 169, 169, 169, 169, 170, + 170, 170, 170, 170, 170, 170, 170, 171, 117, 171, + 172, 116, 172, 172, 111, 172, 172, 173, 173, 173, + 173, 173, 173, 173, 173, 174, 174, 174, 174, 174, + 174, 174, 174, 110, 109, 108, 107, 106, 105, 103, + 102, 101, 99, 97, 96, 95, 94, 93, 92, 90, + 88, 87, 86, 84, 83, 82, 81, 80, 79, 78, + 76, 71, 70, 68, 65, 63, 62, 58, 52, 51, + 49, 48, 47, 43, 40, 24, 23, 21, 15, 11, + 8, 6, 3, 2, 160, 160, 160, 160, 160, 160, + + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160 } ; static yy_state_type yy_last_accepting_state; @@ -540,6 +607,7 @@ int yy_flex_debug = 0; #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; +#line 1 "dtc-lexer.l" /* * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * @@ -561,6 +629,10 @@ char *yytext; */ #define YY_NO_INPUT 1 + + + +#line 38 "dtc-lexer.l" #include "dtc.h" #include "srcpos.h" #include "dtc-parser.tab.h" @@ -588,6 +660,7 @@ static int dts_version = 1; static void push_input_file(const char *filename); static int pop_input_file(void); +#line 664 "dtc-lexer.lex.c" #define INITIAL 0 #define INCLUDE 1 @@ -670,7 +743,12 @@ static int input (void ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else #define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ @@ -689,7 +767,7 @@ static int input (void ); if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ - unsigned n; \ + size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -761,6 +839,9 @@ extern int yylex (void); #endif #define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION /** The main scanner function which does all the work. @@ -771,6 +852,10 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; +#line 67 "dtc-lexer.l" + +#line 858 "dtc-lexer.lex.c" + if ( !(yy_init) ) { (yy_init) = 1; @@ -810,6 +895,7 @@ YY_DECL yy_bp = yy_cp; yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); yy_match: do { @@ -822,13 +908,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 >= 94 ) + if ( yy_current_state >= 161 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_current_state != 93 ); + while ( yy_current_state != 160 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); @@ -851,26 +937,54 @@ do_action: /* This label is used only to access EOF actions. */ case 1: /* rule 1 can match eol */ YY_RULE_SETUP +#line 68 "dtc-lexer.l" { char *name = strchr(yytext, '\"') + 1; yytext[yyleng-1] = '\0'; push_input_file(name); } YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 74 "dtc-lexer.l" +{ + char *line, *tmp, *fn; + /* skip text before line # */ + line = yytext; + while (!isdigit(*line)) + line++; + /* skip digits in line # */ + tmp = line; + while (!isspace(*tmp)) + tmp++; + /* "NULL"-terminate line # */ + *tmp = '\0'; + /* start of filename */ + fn = strchr(tmp + 1, '"') + 1; + /* strip trailing " from filename */ + tmp = strchr(fn, '"'); + *tmp = 0; + /* -1 since #line is the number of the next line */ + srcpos_set_line(xstrdup(fn), atoi(line) - 1); + } + YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(INCLUDE): case YY_STATE_EOF(BYTESTRING): case YY_STATE_EOF(PROPNODENAME): case YY_STATE_EOF(V1): +#line 95 "dtc-lexer.l" { if (!pop_input_file()) { yyterminate(); } } YY_BREAK -case 2: -/* rule 2 can match eol */ +case 3: +/* rule 3 can match eol */ YY_RULE_SETUP +#line 101 "dtc-lexer.l" { DPRINT("String: %s\n", yytext); yylval.data = data_copy_escape_string(yytext+1, @@ -878,8 +992,9 @@ YY_RULE_SETUP return DT_STRING; } YY_BREAK -case 3: +case 4: YY_RULE_SETUP +#line 108 "dtc-lexer.l" { DPRINT("Keyword: /dts-v1/\n"); dts_version = 1; @@ -887,16 +1002,47 @@ YY_RULE_SETUP return DT_V1; } YY_BREAK -case 4: +case 5: YY_RULE_SETUP +#line 115 "dtc-lexer.l" { DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); return DT_MEMRESERVE; } YY_BREAK -case 5: +case 6: +YY_RULE_SETUP +#line 121 "dtc-lexer.l" +{ + DPRINT("Keyword: /bits/\n"); + BEGIN_DEFAULT(); + return DT_BITS; + } + YY_BREAK +case 7: YY_RULE_SETUP +#line 127 "dtc-lexer.l" +{ + DPRINT("Keyword: /delete-property/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_DEL_PROP; + } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 134 "dtc-lexer.l" +{ + DPRINT("Keyword: /delete-node/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_DEL_NODE; + } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 141 "dtc-lexer.l" { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -904,24 +1050,38 @@ YY_RULE_SETUP return DT_LABEL; } YY_BREAK -case 6: +case 10: YY_RULE_SETUP +#line 148 "dtc-lexer.l" { yylval.literal = xstrdup(yytext); DPRINT("Literal: '%s'\n", yylval.literal); return DT_LITERAL; } YY_BREAK -case 7: +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +#line 154 "dtc-lexer.l" +{ + yytext[yyleng-1] = '\0'; + yylval.literal = xstrdup(yytext+1); + DPRINT("Character literal: %s\n", yylval.literal); + return DT_CHAR_LITERAL; + } + YY_BREAK +case 12: YY_RULE_SETUP +#line 161 "dtc-lexer.l" { /* label reference */ DPRINT("Ref: %s\n", yytext+1); yylval.labelref = xstrdup(yytext+1); return DT_REF; } YY_BREAK -case 8: +case 13: YY_RULE_SETUP +#line 167 "dtc-lexer.l" { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); @@ -929,55 +1089,104 @@ YY_RULE_SETUP return DT_REF; } YY_BREAK -case 9: +case 14: YY_RULE_SETUP +#line 174 "dtc-lexer.l" { yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); return DT_BYTE; } YY_BREAK -case 10: +case 15: YY_RULE_SETUP +#line 180 "dtc-lexer.l" { DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); return ']'; } YY_BREAK -case 11: +case 16: YY_RULE_SETUP +#line 186 "dtc-lexer.l" { DPRINT("PropNodeName: %s\n", yytext); - yylval.propnodename = xstrdup(yytext); + yylval.propnodename = xstrdup((yytext[0] == '\\') ? + yytext + 1 : yytext); BEGIN_DEFAULT(); return DT_PROPNODENAME; } YY_BREAK -case 12: +case 17: YY_RULE_SETUP +#line 194 "dtc-lexer.l" { DPRINT("Binary Include\n"); return DT_INCBIN; } YY_BREAK -case 13: -/* rule 13 can match eol */ +case 18: +/* rule 18 can match eol */ YY_RULE_SETUP +#line 199 "dtc-lexer.l" /* eat whitespace */ YY_BREAK -case 14: -/* rule 14 can match eol */ +case 19: +/* rule 19 can match eol */ YY_RULE_SETUP +#line 200 "dtc-lexer.l" /* eat C-style comments */ YY_BREAK -case 15: -/* rule 15 can match eol */ +case 20: +/* rule 20 can match eol */ YY_RULE_SETUP +#line 201 "dtc-lexer.l" /* eat C++-style comments */ YY_BREAK -case 16: +case 21: YY_RULE_SETUP +#line 203 "dtc-lexer.l" +{ return DT_LSHIFT; }; + YY_BREAK +case 22: +YY_RULE_SETUP +#line 204 "dtc-lexer.l" +{ return DT_RSHIFT; }; + YY_BREAK +case 23: +YY_RULE_SETUP +#line 205 "dtc-lexer.l" +{ return DT_LE; }; + YY_BREAK +case 24: +YY_RULE_SETUP +#line 206 "dtc-lexer.l" +{ return DT_GE; }; + YY_BREAK +case 25: +YY_RULE_SETUP +#line 207 "dtc-lexer.l" +{ return DT_EQ; }; + YY_BREAK +case 26: +YY_RULE_SETUP +#line 208 "dtc-lexer.l" +{ return DT_NE; }; + YY_BREAK +case 27: +YY_RULE_SETUP +#line 209 "dtc-lexer.l" +{ return DT_AND; }; + YY_BREAK +case 28: +YY_RULE_SETUP +#line 210 "dtc-lexer.l" +{ return DT_OR; }; + YY_BREAK +case 29: +YY_RULE_SETUP +#line 212 "dtc-lexer.l" { DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); @@ -993,10 +1202,12 @@ YY_RULE_SETUP return yytext[0]; } YY_BREAK -case 17: +case 30: YY_RULE_SETUP +#line 227 "dtc-lexer.l" ECHO; YY_BREAK +#line 1211 "dtc-lexer.lex.c" case YY_END_OF_BUFFER: { @@ -1275,6 +1486,7 @@ static int yy_get_next_buffer (void) register 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 ) { @@ -1287,7 +1499,7 @@ 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 >= 94 ) + if ( yy_current_state >= 161 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1315,11 +1527,11 @@ 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 >= 94 ) + if ( yy_current_state >= 161 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 93); + yy_is_jam = (yy_current_state == 160); return yy_is_jam ? 0 : yy_current_state; } @@ -1394,6 +1606,8 @@ static int yy_get_next_buffer (void) *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + return c; } #endif /* ifndef YY_NO_INPUT */ @@ -1712,8 +1926,8 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ @@ -1952,6 +2166,10 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" +#line 227 "dtc-lexer.l" + + + static void push_input_file(const char *filename) { assert(filename); @@ -1963,6 +2181,7 @@ static void push_input_file(const char *filename) yypush_buffer_state(yy_create_buffer(yyin,YY_BUF_SIZE)); } + static int pop_input_file(void) { if (srcfile_pop() == 0) diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped index b05921e1e84..4af55900a15 100644 --- a/scripts/dtc/dtc-parser.tab.c_shipped +++ b/scripts/dtc/dtc-parser.tab.c_shipped @@ -1,9 +1,10 @@ -/* A Bison parser, made by GNU Bison 2.4.3. */ + +/* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton implementation for Bison's Yacc-like parsers in C - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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 @@ -45,7 +46,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.4.3" +#define YYBISON_VERSION "2.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -66,6 +67,8 @@ /* Copy the first part of user declarations. */ +/* Line 189 of yacc.c */ +#line 21 "dtc-parser.y" #include <stdio.h> @@ -82,12 +85,15 @@ extern struct boot_info *the_boot_info; extern int treesource_error; static unsigned long long eval_literal(const char *s, int base, int bits); +static unsigned char eval_char_literal(const char *s); +/* Line 189 of yacc.c */ +#line 93 "dtc-parser.tab.c" /* Enabling traces. */ #ifndef YYDEBUG -# define YYDEBUG 1 +# define YYDEBUG 0 #endif /* Enabling verbose error messages. */ @@ -112,14 +118,26 @@ static unsigned long long eval_literal(const char *s, int base, int bits); enum yytokentype { DT_V1 = 258, DT_MEMRESERVE = 259, - DT_PROPNODENAME = 260, - DT_LITERAL = 261, - DT_BASE = 262, - DT_BYTE = 263, - DT_STRING = 264, - DT_LABEL = 265, - DT_REF = 266, - DT_INCBIN = 267 + 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_BASE = 274, + DT_BYTE = 275, + DT_STRING = 276, + DT_LABEL = 277, + DT_REF = 278, + DT_INCBIN = 279 }; #endif @@ -129,6 +147,8 @@ static unsigned long long eval_literal(const char *s, int base, int bits); typedef union YYSTYPE { +/* Line 214 of yacc.c */ +#line 40 "dtc-parser.y" char *propnodename; char *literal; @@ -137,16 +157,22 @@ typedef union YYSTYPE uint8_t byte; struct data data; - uint64_t addr; - cell_t cell; + struct { + struct data data; + int bits; + } array; + struct property *prop; struct property *proplist; struct node *node; struct node *nodelist; struct reserve_info *re; + uint64_t integer; +/* Line 214 of yacc.c */ +#line 176 "dtc-parser.tab.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ @@ -157,6 +183,8 @@ typedef union YYSTYPE /* Copy the second part of user declarations. */ +/* Line 264 of yacc.c */ +#line 188 "dtc-parser.tab.c" #ifdef short # undef short @@ -206,7 +234,7 @@ typedef short int yytype_int16; #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS +# if YYENABLE_NLS # if ENABLE_NLS # include <libintl.h> /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) @@ -371,20 +399,20 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 4 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 56 +#define YYLAST 133 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 25 +#define YYNTOKENS 48 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 16 +#define YYNNTS 28 /* YYNRULES -- Number of rules. */ -#define YYNRULES 39 +#define YYNRULES 79 /* YYNRULES -- Number of states. */ -#define YYNSTATES 67 +#define YYNSTATES 141 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 267 +#define YYMAXUTOK 279 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -395,16 +423,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, 2, 2, 2, 2, 2, 2, 2, - 22, 24, 2, 2, 23, 2, 2, 14, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, - 18, 17, 19, 2, 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, 20, 2, 21, 2, 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, 15, 2, 16, 2, 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, @@ -418,45 +446,68 @@ static const yytype_uint8 yytranslate[] = 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, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12 + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ -static const yytype_uint8 yyprhs[] = +static const yytype_uint16 yyprhs[] = { - 0, 0, 3, 8, 9, 12, 17, 20, 22, 25, - 29, 33, 39, 40, 43, 48, 51, 54, 57, 62, - 67, 70, 80, 86, 89, 90, 93, 96, 97, 100, - 103, 106, 108, 109, 112, 115, 116, 119, 122, 125 + 0, 0, 3, 8, 9, 12, 17, 20, 23, 27, + 31, 36, 42, 43, 46, 51, 54, 58, 61, 64, + 68, 73, 76, 86, 92, 95, 96, 99, 102, 106, + 108, 111, 114, 117, 119, 121, 125, 127, 129, 135, + 137, 141, 143, 147, 149, 153, 155, 159, 161, 165, + 167, 171, 175, 177, 181, 185, 189, 193, 197, 201, + 203, 207, 211, 213, 217, 221, 225, 227, 229, 232, + 235, 238, 239, 242, 245, 246, 249, 252, 255, 259 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 26, 0, -1, 3, 13, 27, 30, -1, -1, 28, - 27, -1, 4, 29, 29, 13, -1, 10, 28, -1, - 6, -1, 14, 31, -1, 30, 14, 31, -1, 30, - 11, 31, -1, 15, 32, 39, 16, 13, -1, -1, - 32, 33, -1, 5, 17, 34, 13, -1, 5, 13, - -1, 10, 33, -1, 35, 9, -1, 35, 18, 36, - 19, -1, 35, 20, 38, 21, -1, 35, 11, -1, - 35, 12, 22, 9, 23, 29, 23, 29, 24, -1, - 35, 12, 22, 9, 24, -1, 34, 10, -1, -1, - 34, 23, -1, 35, 10, -1, -1, 36, 37, -1, - 36, 11, -1, 36, 10, -1, 6, -1, -1, 38, - 8, -1, 38, 10, -1, -1, 40, 39, -1, 40, - 33, -1, 5, 31, -1, 10, 40, -1 + 49, 0, -1, 3, 25, 50, 52, -1, -1, 51, + 50, -1, 4, 59, 59, 25, -1, 22, 51, -1, + 26, 53, -1, 52, 26, 53, -1, 52, 23, 53, + -1, 52, 15, 23, 25, -1, 27, 54, 74, 28, + 25, -1, -1, 54, 55, -1, 16, 29, 56, 25, + -1, 16, 25, -1, 14, 16, 25, -1, 22, 55, + -1, 57, 21, -1, 57, 58, 30, -1, 57, 31, + 73, 32, -1, 57, 23, -1, 57, 24, 33, 21, + 34, 59, 34, 59, 35, -1, 57, 24, 33, 21, + 35, -1, 56, 22, -1, -1, 56, 34, -1, 57, + 22, -1, 13, 17, 36, -1, 36, -1, 58, 59, + -1, 58, 23, -1, 58, 22, -1, 17, -1, 18, + -1, 33, 60, 35, -1, 61, -1, 62, -1, 62, + 37, 60, 38, 61, -1, 63, -1, 62, 12, 63, + -1, 64, -1, 63, 11, 64, -1, 65, -1, 64, + 39, 65, -1, 66, -1, 65, 40, 66, -1, 67, + -1, 66, 41, 67, -1, 68, -1, 67, 9, 68, + -1, 67, 10, 68, -1, 69, -1, 68, 36, 69, + -1, 68, 30, 69, -1, 68, 7, 69, -1, 68, + 8, 69, -1, 69, 5, 70, -1, 69, 6, 70, + -1, 70, -1, 70, 42, 71, -1, 70, 43, 71, + -1, 71, -1, 71, 44, 72, -1, 71, 26, 72, + -1, 71, 45, 72, -1, 72, -1, 59, -1, 43, + 72, -1, 46, 72, -1, 47, 72, -1, -1, 73, + 20, -1, 73, 22, -1, -1, 75, 74, -1, 75, + 55, -1, 16, 53, -1, 15, 16, 25, -1, 22, + 75, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 86, 86, 95, 98, 105, 109, 117, 124, 128, - 132, 145, 153, 156, 163, 167, 171, 179, 183, 187, - 191, 195, 212, 222, 230, 233, 237, 245, 248, 252, - 257, 264, 272, 275, 279, 287, 290, 294, 302, 306 + 0, 109, 109, 118, 121, 128, 132, 140, 144, 148, + 158, 172, 180, 183, 190, 194, 198, 202, 210, 214, + 218, 222, 226, 243, 253, 261, 264, 268, 275, 290, + 295, 315, 329, 336, 340, 344, 351, 355, 356, 360, + 361, 365, 366, 370, 371, 375, 376, 380, 381, 385, + 386, 387, 391, 392, 393, 394, 395, 399, 400, 401, + 405, 406, 407, 411, 412, 413, 414, 418, 419, 420, + 421, 426, 429, 433, 441, 444, 448, 456, 460, 464 }; #endif @@ -465,13 +516,19 @@ 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_PROPNODENAME", "DT_LITERAL", "DT_BASE", "DT_BYTE", "DT_STRING", - "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", - "'<'", "'>'", "'['", "']'", "'('", "','", "')'", "$accept", "sourcefile", - "memreserves", "memreserve", "addr", "devicetree", "nodedef", "proplist", - "propdef", "propdata", "propdataprefix", "celllist", "cellval", - "bytestring", "subnodes", "subnode", 0 + "$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_BASE", "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", 0 }; #endif @@ -481,27 +538,37 @@ static const char *const yytname[] = static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 59, 47, 123, 125, 61, 60, 62, - 91, 93, 40, 44, 41 + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 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 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 25, 26, 27, 27, 28, 28, 29, 30, 30, - 30, 31, 32, 32, 33, 33, 33, 34, 34, 34, - 34, 34, 34, 34, 35, 35, 35, 36, 36, 36, - 36, 37, 38, 38, 38, 39, 39, 39, 40, 40 + 0, 48, 49, 50, 50, 51, 51, 52, 52, 52, + 52, 53, 54, 54, 55, 55, 55, 55, 56, 56, + 56, 56, 56, 56, 56, 57, 57, 57, 58, 58, + 58, 58, 58, 59, 59, 59, 60, 61, 61, 62, + 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, + 67, 67, 68, 68, 68, 68, 68, 69, 69, 69, + 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, + 72, 73, 73, 73, 74, 74, 74, 75, 75, 75 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 4, 0, 2, 4, 2, 1, 2, 3, - 3, 5, 0, 2, 4, 2, 2, 2, 4, 4, - 2, 9, 5, 2, 0, 2, 2, 0, 2, 2, - 2, 1, 0, 2, 2, 0, 2, 2, 2, 2 + 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 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -509,41 +576,59 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 0, 0, 0, 3, 1, 0, 0, 0, 3, 7, - 0, 6, 0, 2, 4, 0, 12, 8, 0, 0, - 5, 35, 10, 9, 0, 0, 13, 0, 35, 15, - 24, 38, 16, 39, 0, 37, 36, 0, 0, 11, - 23, 14, 25, 17, 26, 20, 0, 27, 32, 0, - 0, 0, 0, 31, 30, 29, 18, 28, 33, 34, - 19, 0, 22, 0, 0, 0, 21 + 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, 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 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 2, 7, 8, 10, 13, 17, 21, 26, 37, - 38, 50, 57, 51, 27, 28 + -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 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -12 +#define YYPACT_NINF -78 static const yytype_int8 yypact[] = { - 10, -11, 18, -1, -12, 22, -1, 15, -1, -12, - 22, -12, 20, 1, -12, 17, -12, -12, 20, 20, - -12, 6, -12, -12, 21, 6, -12, 23, 6, -12, - -12, -12, -12, -12, 28, -12, -12, -6, 13, -12, - -12, -12, -12, -12, -12, -12, 24, -12, -12, 33, - -5, 0, -4, -12, -12, -12, -12, -12, -12, -12, - -12, 22, -12, 25, 22, 19, -12 + 22, 11, 51, 10, -78, 23, 10, 2, 10, -78, + -78, -9, 23, -78, 30, 38, -78, -9, -9, -9, + -78, 35, -78, -6, 52, 29, 48, 49, 33, 3, + 71, 36, 0, -78, 64, -78, -78, 68, 30, 30, + -78, -78, -78, -78, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -78, 44, 67, -78, -78, 52, 55, + 29, 48, 49, 33, 3, 3, 71, 71, 71, 71, + 36, 36, 0, 0, -78, -78, -78, 78, 79, 42, + 44, -78, 69, 44, -78, -9, 73, 74, -78, -78, + -78, -78, -78, 75, -78, -78, -78, -78, -78, -7, + -1, -78, -78, -78, -78, 84, -78, -78, -78, 63, + -78, -78, 32, 66, 82, -3, -78, -78, -78, -78, + -78, 46, -78, -78, -78, 23, -78, 70, 23, 72, + -78 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -12, -12, 36, 39, -10, -12, 8, -12, 12, -12, - -12, -12, -12, -12, 27, 31 + -78, -78, 97, 100, -78, -37, -78, -77, -78, -78, + -78, -5, 65, 13, -78, 76, 77, 62, 80, 83, + 34, 20, 26, 28, -14, -78, 18, 24 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -553,35 +638,59 @@ static const yytype_int8 yypgoto[] = #define YYTABLE_NINF -1 static const yytype_uint8 yytable[] = { - 15, 53, 3, 5, 40, 54, 55, 41, 58, 6, - 59, 24, 18, 1, 56, 19, 25, 42, 4, 61, - 62, 60, 43, 44, 45, 46, 22, 23, 9, 12, - 20, 47, 31, 48, 29, 16, 16, 32, 30, 34, - 35, 39, 52, 66, 14, 11, 49, 0, 64, 0, - 0, 63, 0, 0, 65, 36, 33 + 12, 66, 67, 40, 41, 42, 44, 34, 9, 10, + 52, 53, 115, 101, 5, 112, 104, 132, 113, 133, + 116, 117, 118, 119, 11, 1, 60, 114, 14, 134, + 120, 45, 6, 54, 17, 121, 3, 18, 19, 55, + 9, 10, 50, 51, 61, 62, 84, 85, 86, 9, + 10, 4, 100, 37, 126, 127, 11, 35, 87, 88, + 89, 38, 128, 46, 39, 11, 90, 98, 47, 35, + 43, 99, 76, 77, 78, 79, 56, 57, 58, 59, + 135, 136, 80, 81, 74, 75, 82, 83, 48, 63, + 49, 65, 94, 95, 96, 97, 124, 103, 107, 108, + 111, 123, 130, 131, 138, 16, 13, 140, 106, 71, + 69, 105, 0, 0, 102, 0, 0, 129, 0, 0, + 68, 0, 0, 70, 0, 0, 0, 0, 72, 0, + 137, 0, 73, 139 }; -static const yytype_int8 yycheck[] = +static const yytype_int16 yycheck[] = { - 10, 6, 13, 4, 10, 10, 11, 13, 8, 10, - 10, 5, 11, 3, 19, 14, 10, 23, 0, 23, - 24, 21, 9, 10, 11, 12, 18, 19, 6, 14, - 13, 18, 24, 20, 13, 15, 15, 25, 17, 16, - 28, 13, 9, 24, 8, 6, 22, -1, 23, -1, - -1, 61, -1, -1, 64, 28, 25 + 5, 38, 39, 17, 18, 19, 12, 12, 17, 18, + 7, 8, 13, 90, 4, 22, 93, 20, 25, 22, + 21, 22, 23, 24, 33, 3, 26, 34, 26, 32, + 31, 37, 22, 30, 43, 36, 25, 46, 47, 36, + 17, 18, 9, 10, 44, 45, 60, 61, 62, 17, + 18, 0, 89, 15, 22, 23, 33, 27, 14, 15, + 16, 23, 30, 11, 26, 33, 22, 25, 39, 27, + 35, 29, 52, 53, 54, 55, 5, 6, 42, 43, + 34, 35, 56, 57, 50, 51, 58, 59, 40, 25, + 41, 23, 25, 38, 16, 16, 33, 28, 25, 25, + 25, 17, 36, 21, 34, 8, 6, 35, 95, 47, + 45, 93, -1, -1, 90, -1, -1, 122, -1, -1, + 44, -1, -1, 46, -1, -1, -1, -1, 48, -1, + 135, -1, 49, 138 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 3, 26, 13, 0, 4, 10, 27, 28, 6, - 29, 28, 14, 30, 27, 29, 15, 31, 11, 14, - 13, 32, 31, 31, 5, 10, 33, 39, 40, 13, - 17, 31, 33, 40, 16, 33, 39, 34, 35, 13, - 10, 13, 23, 9, 10, 11, 12, 18, 20, 22, - 36, 38, 9, 6, 10, 11, 19, 37, 8, 10, - 21, 23, 24, 29, 23, 29, 24 + 0, 3, 49, 25, 0, 4, 22, 50, 51, 17, + 18, 33, 59, 51, 26, 52, 50, 43, 46, 47, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 59, 27, 53, 15, 23, 26, + 72, 72, 72, 35, 12, 37, 11, 39, 40, 41, + 9, 10, 7, 8, 30, 36, 5, 6, 42, 43, + 26, 44, 45, 25, 54, 23, 53, 53, 63, 60, + 64, 65, 66, 67, 68, 68, 69, 69, 69, 69, + 70, 70, 71, 71, 72, 72, 72, 14, 15, 16, + 22, 55, 74, 75, 25, 38, 16, 16, 25, 29, + 53, 55, 75, 28, 55, 74, 61, 25, 25, 56, + 57, 25, 22, 25, 34, 13, 21, 22, 23, 24, + 31, 36, 58, 17, 33, 73, 22, 23, 30, 59, + 36, 21, 20, 22, 32, 34, 35, 59, 34, 59, + 35 }; #define yyerrok (yyerrstatus = 0) @@ -596,18 +705,9 @@ static const yytype_uint8 yystos[] = /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ + Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif #define YYRECOVERING() (!!yyerrstatus) @@ -664,7 +764,7 @@ while (YYID (0)) we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# if YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ @@ -1403,6 +1503,8 @@ yyreduce: { case 2: +/* Line 1455 of yacc.c */ +#line 110 "dtc-parser.y" { the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node), guess_boot_cpuid((yyvsp[(4) - (4)].node))); @@ -1411,6 +1513,8 @@ yyreduce: case 3: +/* Line 1455 of yacc.c */ +#line 118 "dtc-parser.y" { (yyval.re) = NULL; ;} @@ -1418,6 +1522,8 @@ yyreduce: case 4: +/* Line 1455 of yacc.c */ +#line 122 "dtc-parser.y" { (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re)); ;} @@ -1425,13 +1531,17 @@ yyreduce: case 5: +/* Line 1455 of yacc.c */ +#line 129 "dtc-parser.y" { - (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].addr), (yyvsp[(3) - (4)].addr)); + (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].integer)); ;} break; case 6: +/* Line 1455 of yacc.c */ +#line 133 "dtc-parser.y" { add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref)); (yyval.re) = (yyvsp[(2) - (2)].re); @@ -1440,40 +1550,57 @@ yyreduce: case 7: +/* Line 1455 of yacc.c */ +#line 141 "dtc-parser.y" { - (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64); + (yyval.node) = name_node((yyvsp[(2) - (2)].node), ""); ;} break; case 8: +/* Line 1455 of yacc.c */ +#line 145 "dtc-parser.y" { - (yyval.node) = name_node((yyvsp[(2) - (2)].node), ""); + (yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; case 9: +/* Line 1455 of yacc.c */ +#line 149 "dtc-parser.y" { - (yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref)); + + if (target) + merge_nodes(target, (yyvsp[(3) - (3)].node)); + else + print_error("label or path, '%s', not found", (yyvsp[(2) - (3)].labelref)); + (yyval.node) = (yyvsp[(1) - (3)].node); ;} break; case 10: +/* Line 1455 of yacc.c */ +#line 159 "dtc-parser.y" { - struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref)); + struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref)); - if (target) - merge_nodes(target, (yyvsp[(3) - (3)].node)); + if (!target) + print_error("label or path, '%s', not found", (yyvsp[(3) - (4)].labelref)); else - print_error("label or path, '%s', not found", (yyvsp[(2) - (3)].labelref)); - (yyval.node) = (yyvsp[(1) - (3)].node); + delete_node(target); + + (yyval.node) = (yyvsp[(1) - (4)].node); ;} break; case 11: +/* Line 1455 of yacc.c */ +#line 173 "dtc-parser.y" { (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist)); ;} @@ -1481,6 +1608,8 @@ yyreduce: case 12: +/* Line 1455 of yacc.c */ +#line 180 "dtc-parser.y" { (yyval.proplist) = NULL; ;} @@ -1488,6 +1617,8 @@ yyreduce: case 13: +/* Line 1455 of yacc.c */ +#line 184 "dtc-parser.y" { (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist)); ;} @@ -1495,6 +1626,8 @@ yyreduce: case 14: +/* Line 1455 of yacc.c */ +#line 191 "dtc-parser.y" { (yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data)); ;} @@ -1502,6 +1635,8 @@ yyreduce: case 15: +/* Line 1455 of yacc.c */ +#line 195 "dtc-parser.y" { (yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data); ;} @@ -1509,62 +1644,85 @@ yyreduce: case 16: +/* Line 1455 of yacc.c */ +#line 199 "dtc-parser.y" { - add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref)); - (yyval.prop) = (yyvsp[(2) - (2)].prop); + (yyval.prop) = build_property_delete((yyvsp[(2) - (3)].propnodename)); ;} break; case 17: +/* Line 1455 of yacc.c */ +#line 203 "dtc-parser.y" { - (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data)); + add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref)); + (yyval.prop) = (yyvsp[(2) - (2)].prop); ;} break; case 18: +/* Line 1455 of yacc.c */ +#line 211 "dtc-parser.y" { - (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); + (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data)); ;} break; case 19: +/* Line 1455 of yacc.c */ +#line 215 "dtc-parser.y" { - (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); + (yyval.data) = data_merge((yyvsp[(1) - (3)].data), (yyvsp[(2) - (3)].array).data); ;} break; case 20: +/* Line 1455 of yacc.c */ +#line 219 "dtc-parser.y" { - (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref)); + (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); ;} break; case 21: +/* Line 1455 of yacc.c */ +#line 223 "dtc-parser.y" + { + (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref)); + ;} + break; + + case 22: + +/* Line 1455 of yacc.c */ +#line 227 "dtc-parser.y" { FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL); struct data d; - if ((yyvsp[(6) - (9)].addr) != 0) - if (fseek(f, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0) + if ((yyvsp[(6) - (9)].integer) != 0) + if (fseek(f, (yyvsp[(6) - (9)].integer), SEEK_SET) != 0) print_error("Couldn't seek to offset %llu in \"%s\": %s", - (unsigned long long)(yyvsp[(6) - (9)].addr), + (unsigned long long)(yyvsp[(6) - (9)].integer), (yyvsp[(4) - (9)].data).val, strerror(errno)); - d = data_copy_file(f, (yyvsp[(8) - (9)].addr)); + d = data_copy_file(f, (yyvsp[(8) - (9)].integer)); (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d); fclose(f); ;} break; - case 22: + case 23: +/* Line 1455 of yacc.c */ +#line 244 "dtc-parser.y" { FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL); struct data d = empty_data; @@ -1576,122 +1734,383 @@ yyreduce: ;} break; - case 23: - - { - (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); - ;} - break; - case 24: +/* Line 1455 of yacc.c */ +#line 254 "dtc-parser.y" { - (yyval.data) = empty_data; + (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); ;} break; case 25: +/* Line 1455 of yacc.c */ +#line 261 "dtc-parser.y" { - (yyval.data) = (yyvsp[(1) - (2)].data); + (yyval.data) = empty_data; ;} break; case 26: +/* Line 1455 of yacc.c */ +#line 265 "dtc-parser.y" { - (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); + (yyval.data) = (yyvsp[(1) - (2)].data); ;} break; case 27: +/* Line 1455 of yacc.c */ +#line 269 "dtc-parser.y" { - (yyval.data) = empty_data; + (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); ;} break; case 28: +/* Line 1455 of yacc.c */ +#line 276 "dtc-parser.y" { - (yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell)); + (yyval.array).data = empty_data; + (yyval.array).bits = eval_literal((yyvsp[(2) - (3)].literal), 0, 7); + + if (((yyval.array).bits != 8) && + ((yyval.array).bits != 16) && + ((yyval.array).bits != 32) && + ((yyval.array).bits != 64)) + { + print_error("Only 8, 16, 32 and 64-bit elements" + " are currently supported"); + (yyval.array).bits = 32; + } ;} break; case 29: +/* Line 1455 of yacc.c */ +#line 291 "dtc-parser.y" { - (yyval.data) = data_append_cell(data_add_marker((yyvsp[(1) - (2)].data), REF_PHANDLE, - (yyvsp[(2) - (2)].labelref)), -1); + (yyval.array).data = empty_data; + (yyval.array).bits = 32; ;} break; case 30: +/* Line 1455 of yacc.c */ +#line 296 "dtc-parser.y" { - (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); + if ((yyvsp[(1) - (2)].array).bits < 64) { + uint64_t mask = (1ULL << (yyvsp[(1) - (2)].array).bits) - 1; + /* + * Bits above mask must either be all zero + * (positive within range of mask) or all one + * (negative and sign-extended). The second + * condition is true if when we set all bits + * within the mask to one (i.e. | in the + * mask), all bits are one. + */ + if (((yyvsp[(2) - (2)].integer) > mask) && (((yyvsp[(2) - (2)].integer) | mask) != -1ULL)) + print_error( + "integer value out of range " + "%016lx (%d bits)", (yyvsp[(1) - (2)].array).bits); + } + + (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, (yyvsp[(2) - (2)].integer), (yyvsp[(1) - (2)].array).bits); ;} break; case 31: +/* Line 1455 of yacc.c */ +#line 316 "dtc-parser.y" { - (yyval.cell) = eval_literal((yyvsp[(1) - (1)].literal), 0, 32); + uint64_t val = ~0ULL >> (64 - (yyvsp[(1) - (2)].array).bits); + + if ((yyvsp[(1) - (2)].array).bits == 32) + (yyvsp[(1) - (2)].array).data = data_add_marker((yyvsp[(1) - (2)].array).data, + REF_PHANDLE, + (yyvsp[(2) - (2)].labelref)); + else + print_error("References are only allowed in " + "arrays with 32-bit elements."); + + (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, val, (yyvsp[(1) - (2)].array).bits); ;} break; case 32: +/* Line 1455 of yacc.c */ +#line 330 "dtc-parser.y" { - (yyval.data) = empty_data; + (yyval.array).data = data_add_marker((yyvsp[(1) - (2)].array).data, LABEL, (yyvsp[(2) - (2)].labelref)); ;} break; case 33: +/* Line 1455 of yacc.c */ +#line 337 "dtc-parser.y" { - (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte)); + (yyval.integer) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64); ;} break; case 34: +/* Line 1455 of yacc.c */ +#line 341 "dtc-parser.y" { - (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); + (yyval.integer) = eval_char_literal((yyvsp[(1) - (1)].literal)); ;} break; case 35: +/* Line 1455 of yacc.c */ +#line 345 "dtc-parser.y" + { + (yyval.integer) = (yyvsp[(2) - (3)].integer); + ;} + break; + + case 38: + +/* Line 1455 of yacc.c */ +#line 356 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (5)].integer) ? (yyvsp[(3) - (5)].integer) : (yyvsp[(5) - (5)].integer); ;} + break; + + case 40: + +/* Line 1455 of yacc.c */ +#line 361 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) || (yyvsp[(3) - (3)].integer); ;} + break; + + case 42: + +/* Line 1455 of yacc.c */ +#line 366 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) && (yyvsp[(3) - (3)].integer); ;} + break; + + case 44: + +/* Line 1455 of yacc.c */ +#line 371 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) | (yyvsp[(3) - (3)].integer); ;} + break; + + case 46: + +/* Line 1455 of yacc.c */ +#line 376 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) ^ (yyvsp[(3) - (3)].integer); ;} + break; + + case 48: + +/* Line 1455 of yacc.c */ +#line 381 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) & (yyvsp[(3) - (3)].integer); ;} + break; + + case 50: + +/* Line 1455 of yacc.c */ +#line 386 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) == (yyvsp[(3) - (3)].integer); ;} + break; + + case 51: + +/* Line 1455 of yacc.c */ +#line 387 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) != (yyvsp[(3) - (3)].integer); ;} + break; + + case 53: + +/* Line 1455 of yacc.c */ +#line 392 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) < (yyvsp[(3) - (3)].integer); ;} + break; + + case 54: + +/* Line 1455 of yacc.c */ +#line 393 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) > (yyvsp[(3) - (3)].integer); ;} + break; + + case 55: + +/* Line 1455 of yacc.c */ +#line 394 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) <= (yyvsp[(3) - (3)].integer); ;} + break; + + case 56: + +/* Line 1455 of yacc.c */ +#line 395 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) >= (yyvsp[(3) - (3)].integer); ;} + break; + + case 57: + +/* Line 1455 of yacc.c */ +#line 399 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) << (yyvsp[(3) - (3)].integer); ;} + break; + + case 58: + +/* Line 1455 of yacc.c */ +#line 400 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) >> (yyvsp[(3) - (3)].integer); ;} + break; + + case 60: + +/* Line 1455 of yacc.c */ +#line 405 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) + (yyvsp[(3) - (3)].integer); ;} + break; + + case 61: + +/* Line 1455 of yacc.c */ +#line 406 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) - (yyvsp[(3) - (3)].integer); ;} + break; + + case 63: + +/* Line 1455 of yacc.c */ +#line 411 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) * (yyvsp[(3) - (3)].integer); ;} + break; + + case 64: + +/* Line 1455 of yacc.c */ +#line 412 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) / (yyvsp[(3) - (3)].integer); ;} + break; + + case 65: + +/* Line 1455 of yacc.c */ +#line 413 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) % (yyvsp[(3) - (3)].integer); ;} + break; + + case 68: + +/* Line 1455 of yacc.c */ +#line 419 "dtc-parser.y" + { (yyval.integer) = -(yyvsp[(2) - (2)].integer); ;} + break; + + case 69: + +/* Line 1455 of yacc.c */ +#line 420 "dtc-parser.y" + { (yyval.integer) = ~(yyvsp[(2) - (2)].integer); ;} + break; + + case 70: + +/* Line 1455 of yacc.c */ +#line 421 "dtc-parser.y" + { (yyval.integer) = !(yyvsp[(2) - (2)].integer); ;} + break; + + case 71: + +/* Line 1455 of yacc.c */ +#line 426 "dtc-parser.y" + { + (yyval.data) = empty_data; + ;} + break; + + case 72: + +/* Line 1455 of yacc.c */ +#line 430 "dtc-parser.y" + { + (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte)); + ;} + break; + + case 73: + +/* Line 1455 of yacc.c */ +#line 434 "dtc-parser.y" + { + (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); + ;} + break; + + case 74: + +/* Line 1455 of yacc.c */ +#line 441 "dtc-parser.y" { (yyval.nodelist) = NULL; ;} break; - case 36: + case 75: +/* Line 1455 of yacc.c */ +#line 445 "dtc-parser.y" { (yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist)); ;} break; - case 37: + case 76: +/* Line 1455 of yacc.c */ +#line 449 "dtc-parser.y" { print_error("syntax error: properties must precede subnodes"); YYERROR; ;} break; - case 38: + case 77: +/* Line 1455 of yacc.c */ +#line 457 "dtc-parser.y" { (yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename)); ;} break; - case 39: + case 78: + +/* Line 1455 of yacc.c */ +#line 461 "dtc-parser.y" + { + (yyval.node) = name_node(build_node_delete(), (yyvsp[(2) - (3)].propnodename)); + ;} + break; + + case 79: +/* Line 1455 of yacc.c */ +#line 465 "dtc-parser.y" { add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref)); (yyval.node) = (yyvsp[(2) - (2)].node); @@ -1700,6 +2119,8 @@ yyreduce: +/* Line 1455 of yacc.c */ +#line 2124 "dtc-parser.tab.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -1910,6 +2331,8 @@ yyreturn: +/* Line 1675 of yacc.c */ +#line 471 "dtc-parser.y" void print_error(char const *fmt, ...) @@ -1934,9 +2357,12 @@ static unsigned long long eval_literal(const char *s, int base, int bits) errno = 0; val = strtoull(s, &e, base); - if (*e) - print_error("bad characters in literal"); - else if ((errno == ERANGE) + if (*e) { + size_t uls = strspn(e, "UL"); + if (e[uls]) + print_error("bad characters in literal"); + } + if ((errno == ERANGE) || ((bits < 64) && (val >= (1ULL << bits)))) print_error("literal out of range"); else if (errno != 0) @@ -1944,3 +2370,29 @@ static unsigned long long eval_literal(const char *s, int base, int bits) return val; } +static unsigned char eval_char_literal(const char *s) +{ + int i = 1; + char c = s[0]; + + if (c == '\0') + { + print_error("empty character literal"); + return 0; + } + + /* + * If the first character in the character literal is a \ then process + * the remaining characters as an escape encoding. If the first + * character is neither an escape or a terminator it should be the only + * character in the literal and will be returned. + */ + if (c == '\\') + c = get_escape_char(s, &i); + + if (s[i] != '\0') + print_error("malformed character literal"); + + return c; +} + diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped index 4ee682bb7d3..9d2dce41211 100644 --- a/scripts/dtc/dtc-parser.tab.h_shipped +++ b/scripts/dtc/dtc-parser.tab.h_shipped @@ -1,9 +1,10 @@ -/* A Bison parser, made by GNU Bison 2.4.3. */ + +/* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton interface for Bison's Yacc-like parsers in C - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 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 @@ -40,14 +41,26 @@ enum yytokentype { DT_V1 = 258, DT_MEMRESERVE = 259, - DT_PROPNODENAME = 260, - DT_LITERAL = 261, - DT_BASE = 262, - DT_BYTE = 263, - DT_STRING = 264, - DT_LABEL = 265, - DT_REF = 266, - DT_INCBIN = 267 + 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_BASE = 274, + DT_BYTE = 275, + DT_STRING = 276, + DT_LABEL = 277, + DT_REF = 278, + DT_INCBIN = 279 }; #endif @@ -57,6 +70,8 @@ typedef union YYSTYPE { +/* Line 1676 of yacc.c */ +#line 40 "dtc-parser.y" char *propnodename; char *literal; @@ -65,16 +80,22 @@ typedef union YYSTYPE uint8_t byte; struct data data; - uint64_t addr; - cell_t cell; + struct { + struct data data; + int bits; + } array; + struct property *prop; struct property *proplist; struct node *node; struct node *nodelist; struct reserve_info *re; + uint64_t integer; +/* Line 1676 of yacc.c */ +#line 99 "dtc-parser.tab.h" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 5e84a67fc1d..f412460f94d 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -34,6 +34,7 @@ extern struct boot_info *the_boot_info; extern int treesource_error; static unsigned long long eval_literal(const char *s, int base, int bits); +static unsigned char eval_char_literal(const char *s); %} %union { @@ -44,19 +45,28 @@ static unsigned long long eval_literal(const char *s, int base, int bits); uint8_t byte; struct data data; - uint64_t addr; - cell_t cell; + struct { + struct data data; + int bits; + } array; + struct property *prop; struct property *proplist; struct node *node; struct node *nodelist; struct reserve_info *re; + uint64_t integer; } %token DT_V1 %token DT_MEMRESERVE +%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR +%token DT_BITS +%token DT_DEL_PROP +%token DT_DEL_NODE %token <propnodename> DT_PROPNODENAME %token <literal> DT_LITERAL +%token <literal> DT_CHAR_LITERAL %token <cbase> DT_BASE %token <byte> DT_BYTE %token <data> DT_STRING @@ -68,9 +78,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %type <data> propdataprefix %type <re> memreserve %type <re> memreserves -%type <addr> addr -%type <data> celllist -%type <cell> cellval +%type <array> arrayprefix %type <data> bytestring %type <prop> propdef %type <proplist> proplist @@ -80,6 +88,21 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %type <node> subnode %type <nodelist> subnodes +%type <integer> integer_prim +%type <integer> integer_unary +%type <integer> integer_mul +%type <integer> integer_add +%type <integer> integer_shift +%type <integer> integer_rela +%type <integer> integer_eq +%type <integer> integer_bitand +%type <integer> integer_bitxor +%type <integer> integer_bitor +%type <integer> integer_and +%type <integer> integer_or +%type <integer> integer_trinary +%type <integer> integer_expr + %% sourcefile: @@ -102,7 +125,7 @@ memreserves: ; memreserve: - DT_MEMRESERVE addr addr ';' + DT_MEMRESERVE integer_prim integer_prim ';' { $$ = build_reserve_entry($2, $3); } @@ -113,13 +136,6 @@ memreserve: } ; -addr: - DT_LITERAL - { - $$ = eval_literal($1, 0, 64); - } - ; - devicetree: '/' nodedef { @@ -139,6 +155,17 @@ devicetree: print_error("label or path, '%s', not found", $2); $$ = $1; } + | devicetree DT_DEL_NODE DT_REF ';' + { + struct node *target = get_node_by_ref($1, $3); + + if (!target) + print_error("label or path, '%s', not found", $3); + else + delete_node(target); + + $$ = $1; + } ; nodedef: @@ -168,6 +195,10 @@ propdef: { $$ = build_property($1, empty_data); } + | DT_DEL_PROP DT_PROPNODENAME ';' + { + $$ = build_property_delete($2); + } | DT_LABEL propdef { add_label(&$2->labels, $1); @@ -180,9 +211,9 @@ propdata: { $$ = data_merge($1, $2); } - | propdataprefix '<' celllist '>' + | propdataprefix arrayprefix '>' { - $$ = data_merge($1, $3); + $$ = data_merge($1, $2.data); } | propdataprefix '[' bytestring ']' { @@ -192,7 +223,7 @@ propdata: { $$ = data_add_marker($1, REF_PATH, $2); } - | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' + | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')' { FILE *f = srcfile_relative_open($4.val, NULL); struct data d; @@ -240,31 +271,154 @@ propdataprefix: } ; -celllist: - /* empty */ +arrayprefix: + DT_BITS DT_LITERAL '<' + { + $$.data = empty_data; + $$.bits = eval_literal($2, 0, 7); + + if (($$.bits != 8) && + ($$.bits != 16) && + ($$.bits != 32) && + ($$.bits != 64)) + { + print_error("Only 8, 16, 32 and 64-bit elements" + " are currently supported"); + $$.bits = 32; + } + } + | '<' + { + $$.data = empty_data; + $$.bits = 32; + } + | arrayprefix integer_prim + { + if ($1.bits < 64) { + uint64_t mask = (1ULL << $1.bits) - 1; + /* + * Bits above mask must either be all zero + * (positive within range of mask) or all one + * (negative and sign-extended). The second + * condition is true if when we set all bits + * within the mask to one (i.e. | in the + * mask), all bits are one. + */ + if (($2 > mask) && (($2 | mask) != -1ULL)) + print_error( + "integer value out of range " + "%016lx (%d bits)", $1.bits); + } + + $$.data = data_append_integer($1.data, $2, $1.bits); + } + | arrayprefix DT_REF + { + uint64_t val = ~0ULL >> (64 - $1.bits); + + if ($1.bits == 32) + $1.data = data_add_marker($1.data, + REF_PHANDLE, + $2); + else + print_error("References are only allowed in " + "arrays with 32-bit elements."); + + $$.data = data_append_integer($1.data, val, $1.bits); + } + | arrayprefix DT_LABEL { - $$ = empty_data; + $$.data = data_add_marker($1.data, LABEL, $2); } - | celllist cellval + ; + +integer_prim: + DT_LITERAL { - $$ = data_append_cell($1, $2); + $$ = eval_literal($1, 0, 64); } - | celllist DT_REF + | DT_CHAR_LITERAL { - $$ = data_append_cell(data_add_marker($1, REF_PHANDLE, - $2), -1); + $$ = eval_char_literal($1); } - | celllist DT_LABEL + | '(' integer_expr ')' { - $$ = data_add_marker($1, LABEL, $2); + $$ = $2; } ; -cellval: - DT_LITERAL - { - $$ = eval_literal($1, 0, 32); - } +integer_expr: + integer_trinary + ; + +integer_trinary: + integer_or + | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; } + ; + +integer_or: + integer_and + | integer_or DT_OR integer_and { $$ = $1 || $3; } + ; + +integer_and: + integer_bitor + | integer_and DT_AND integer_bitor { $$ = $1 && $3; } + ; + +integer_bitor: + integer_bitxor + | integer_bitor '|' integer_bitxor { $$ = $1 | $3; } + ; + +integer_bitxor: + integer_bitand + | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; } + ; + +integer_bitand: + integer_eq + | integer_bitand '&' integer_eq { $$ = $1 & $3; } + ; + +integer_eq: + integer_rela + | integer_eq DT_EQ integer_rela { $$ = $1 == $3; } + | integer_eq DT_NE integer_rela { $$ = $1 != $3; } + ; + +integer_rela: + integer_shift + | integer_rela '<' integer_shift { $$ = $1 < $3; } + | integer_rela '>' integer_shift { $$ = $1 > $3; } + | integer_rela DT_LE integer_shift { $$ = $1 <= $3; } + | integer_rela DT_GE integer_shift { $$ = $1 >= $3; } + ; + +integer_shift: + integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; } + | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; } + | integer_add + ; + +integer_add: + integer_add '+' integer_mul { $$ = $1 + $3; } + | integer_add '-' integer_mul { $$ = $1 - $3; } + | integer_mul + ; + +integer_mul: + integer_mul '*' integer_unary { $$ = $1 * $3; } + | integer_mul '/' integer_unary { $$ = $1 / $3; } + | integer_mul '%' integer_unary { $$ = $1 % $3; } + | integer_unary + ; + +integer_unary: + integer_prim + | '-' integer_unary { $$ = -$2; } + | '~' integer_unary { $$ = ~$2; } + | '!' integer_unary { $$ = !$2; } ; bytestring: @@ -303,6 +457,10 @@ subnode: { $$ = name_node($2, $1); } + | DT_DEL_NODE DT_PROPNODENAME ';' + { + $$ = name_node(build_node_delete(), $2); + } | DT_LABEL subnode { add_label(&$2->labels, $1); @@ -334,12 +492,41 @@ static unsigned long long eval_literal(const char *s, int base, int bits) errno = 0; val = strtoull(s, &e, base); - if (*e) - print_error("bad characters in literal"); - else if ((errno == ERANGE) + if (*e) { + size_t uls = strspn(e, "UL"); + if (e[uls]) + print_error("bad characters in literal"); + } + if ((errno == ERANGE) || ((bits < 64) && (val >= (1ULL << bits)))) print_error("literal out of range"); else if (errno != 0) print_error("bad literal"); return val; } + +static unsigned char eval_char_literal(const char *s) +{ + int i = 1; + char c = s[0]; + + if (c == '\0') + { + print_error("empty character literal"); + return 0; + } + + /* + * If the first character in the character literal is a \ then process + * the remaining characters as an escape encoding. If the first + * character is neither an escape or a terminator it should be the only + * character in the literal and will be returned. + */ + if (c == '\\') + c = get_escape_char(s, &i); + + if (s[i] != '\0') + print_error("malformed character literal"); + + return c; +} diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index 2ef5e2e3dd3..a375683c153 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -82,6 +82,8 @@ static void __attribute__ ((noreturn)) usage(void) fprintf(stderr, "\t\tSet the physical boot cpu\n"); fprintf(stderr, "\t-f\n"); fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n"); + fprintf(stderr, "\t-i\n"); + fprintf(stderr, "\t\tAdd a path to search for include files\n"); fprintf(stderr, "\t-s\n"); fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n"); fprintf(stderr, "\t-v\n"); @@ -91,6 +93,9 @@ static void __attribute__ ((noreturn)) usage(void) fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n"); fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n"); fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n"); + fprintf(stderr, "\t-W [no-]<checkname>\n"); + fprintf(stderr, "\t-E [no-]<checkname>\n"); + fprintf(stderr, "\t\t\tenable or disable warnings and errors\n"); exit(3); } @@ -113,7 +118,7 @@ int main(int argc, char *argv[]) minsize = 0; padsize = 0; - while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fcqb:vH:s")) + while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:")) != EOF) { switch (opt) { case 'I': @@ -149,6 +154,9 @@ int main(int argc, char *argv[]) case 'b': cmdline_boot_cpuid = strtoll(optarg, NULL, 0); break; + case 'i': + srcfile_add_search_path(optarg); + break; case 'v': printf("Version: %s\n", DTC_VERSION); exit(0); @@ -168,6 +176,14 @@ int main(int argc, char *argv[]) sort = 1; break; + case 'W': + parse_checks_option(true, false, optarg); + break; + + case 'E': + parse_checks_option(false, true, optarg); + break; + case 'h': default: usage(); @@ -188,9 +204,6 @@ int main(int argc, char *argv[]) if (minsize) fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n"); - fprintf(stderr, "DTC: %s->%s on file \"%s\"\n", - inform, outform, arg); - if (depname) { depfile = fopen(depname, "w"); if (!depfile) diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index f37c97eb3df..d501c8605f2 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -25,6 +25,7 @@ #include <string.h> #include <stdlib.h> #include <stdint.h> +#include <stdbool.h> #include <stdarg.h> #include <assert.h> #include <ctype.h> @@ -109,6 +110,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m, const void *p, int len); struct data data_merge(struct data d1, struct data d2); struct data data_append_cell(struct data d, cell_t word); +struct data data_append_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_addr(struct data d, uint64_t addr); struct data data_append_byte(struct data d, uint8_t byte); @@ -126,11 +128,13 @@ int data_is_one_string(struct data d); /* Live trees */ struct label { + int deleted; char *label; struct label *next; }; struct property { + int deleted; char *name; struct data val; @@ -140,6 +144,7 @@ struct property { }; struct node { + int deleted; char *name; struct property *proplist; struct node *children; @@ -156,28 +161,71 @@ struct node { struct label *labels; }; +static inline struct label *for_each_label_next(struct label *l) +{ + do { + l = l->next; + } while (l && l->deleted); + + return l; +} + #define for_each_label(l0, l) \ + for ((l) = (l0); (l); (l) = for_each_label_next(l)) + +#define for_each_label_withdel(l0, l) \ for ((l) = (l0); (l); (l) = (l)->next) +static inline struct property *for_each_property_next(struct property *p) +{ + do { + p = p->next; + } while (p && p->deleted); + + return p; +} + #define for_each_property(n, p) \ + for ((p) = (n)->proplist; (p); (p) = for_each_property_next(p)) + +#define for_each_property_withdel(n, p) \ for ((p) = (n)->proplist; (p); (p) = (p)->next) -#define for_each_child(n, c) \ +static inline struct node *for_each_child_next(struct node *c) +{ + do { + c = c->next_sibling; + } while (c && c->deleted); + + return c; +} + +#define for_each_child(n, c) \ + for ((c) = (n)->children; (c); (c) = for_each_child_next(c)) + +#define for_each_child_withdel(n, c) \ for ((c) = (n)->children; (c); (c) = (c)->next_sibling) void add_label(struct label **labels, char *label); +void delete_labels(struct label **labels); struct property *build_property(char *name, struct data val); +struct property *build_property_delete(char *name); struct property *chain_property(struct property *first, struct property *list); struct property *reverse_properties(struct property *first); struct node *build_node(struct property *proplist, struct node *children); +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); void add_property(struct node *node, struct property *prop); +void delete_property_by_name(struct node *node, char *name); +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); const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); @@ -224,6 +272,7 @@ void sort_tree(struct boot_info *bi); /* Checks */ +void parse_checks_option(bool warn, bool error, const char *optarg); void process_checks(int force, struct boot_info *bi); /* Flattened trees */ diff --git a/scripts/dtc/fdtdump.c b/scripts/dtc/fdtdump.c new file mode 100644 index 00000000000..207a46d6486 --- /dev/null +++ b/scripts/dtc/fdtdump.c @@ -0,0 +1,162 @@ +/* + * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com> + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <fdt.h> +#include <libfdt_env.h> + +#include "util.h" + +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) +#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) +#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) + +static void print_data(const char *data, int len) +{ + 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("]"); + } +} + +static void dump_blob(void *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); + uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings); + struct fdt_reserve_entry *p_rsvmap = + (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap); + const char *p_struct = (const char *)blob + off_dt; + const char *p_strings = (const char *)blob + off_str; + uint32_t version = fdt32_to_cpu(bph->version); + uint32_t totalsize = fdt32_to_cpu(bph->totalsize); + uint32_t tag; + const char *p, *s, *t; + int depth, sz, shift; + int i; + uint64_t addr, size; + + depth = 0; + shift = 4; + + printf("/dts-v1/;\n"); + printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic)); + printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize); + printf("// off_dt_struct:\t0x%x\n", off_dt); + printf("// off_dt_strings:\t0x%x\n", off_str); + printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); + printf("// version:\t\t%d\n", version); + printf("// last_comp_version:\t%d\n", + fdt32_to_cpu(bph->last_comp_version)); + if (version >= 2) + printf("// boot_cpuid_phys:\t0x%x\n", + fdt32_to_cpu(bph->boot_cpuid_phys)); + + if (version >= 3) + printf("// size_dt_strings:\t0x%x\n", + fdt32_to_cpu(bph->size_dt_strings)); + if (version >= 17) + printf("// size_dt_struct:\t0x%x\n", + fdt32_to_cpu(bph->size_dt_struct)); + printf("\n"); + + for (i = 0; ; i++) { + addr = fdt64_to_cpu(p_rsvmap[i].address); + size = fdt64_to_cpu(p_rsvmap[i].size); + if (addr == 0 && size == 0) + break; + + 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) { + + /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + + if (tag == FDT_BEGIN_NODE) { + s = p; + p = PALIGN(p + strlen(s) + 1, 4); + + if (*s == '\0') + s = "/"; + + printf("%*s%s {\n", depth * shift, "", s); + + depth++; + continue; + } + + if (tag == FDT_END_NODE) { + depth--; + + printf("%*s};\n", depth * shift, ""); + continue; + } + + if (tag == FDT_NOP) { + printf("%*s// [NOP]\n", depth * shift, ""); + continue; + } + + if (tag != FDT_PROP) { + fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); + break; + } + sz = fdt32_to_cpu(GET_CELL(p)); + s = p_strings + fdt32_to_cpu(GET_CELL(p)); + if (version < 16 && sz >= 8) + p = PALIGN(p, 8); + t = p; + + p = PALIGN(p + sz, 4); + + printf("%*s%s", depth * shift, "", s); + print_data(t, sz); + printf(";\n"); + } +} + + +int main(int argc, char *argv[]) +{ + char *buf; + + if (argc < 2) { + fprintf(stderr, "supply input filename\n"); + return 5; + } + + 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 new file mode 100644 index 00000000000..c2fbab2a547 --- /dev/null +++ b/scripts/dtc/fdtget.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * + * Portions from U-Boot cmd_fdt.c (C) Copyright 2007 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com + * Based on code written by: + * Pantelis Antoniou <pantelis.antoniou@gmail.com> and + * Matthew McClintock <msm@freescale.com> + * + * 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 the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libfdt.h> + +#include "util.h" + +enum display_mode { + MODE_SHOW_VALUE, /* show values for node properties */ + MODE_LIST_PROPS, /* list the properties for a node */ + MODE_LIST_SUBNODES, /* list the subnodes of a node */ +}; + +/* Holds information which controls our output and options */ +struct display_info { + int type; /* data type (s/i/u/x or 0 for default) */ + int size; /* data size (1/2/4) */ + enum display_mode mode; /* display mode that we are using */ + const char *default_val; /* default value if node/property not found */ +}; + +static void report_error(const char *where, int err) +{ + fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err)); +} + +/** + * Displays data of a given length according to selected options + * + * If a specific data type is provided in disp, then this is used. Otherwise + * we try to guess the data type / size from the contents. + * + * @param disp Display information / options + * @param data Data to display + * @param len Maximum length of buffer + * @return 0 if ok, -1 if data does not match format + */ +static int show_data(struct display_info *disp, const char *data, int len) +{ + int i, size; + const uint8_t *p = (const uint8_t *)data; + const char *s; + int value; + int is_string; + char fmt[3]; + + /* no data, don't print */ + if (len == 0) + return 0; + + is_string = (disp->type) == 's' || + (!disp->type && util_is_printable_string(data, len)); + if (is_string) { + if (data[len - 1] != '\0') { + fprintf(stderr, "Unterminated string\n"); + return -1; + } + for (s = data; s - data < len; s += strlen(s) + 1) { + if (s != data) + printf(" "); + printf("%s", (const char *)s); + } + return 0; + } + size = disp->size; + if (size == -1) { + size = (len % 4) == 0 ? 4 : 1; + } else if (len % size) { + fprintf(stderr, "Property length must be a multiple of " + "selected data size\n"); + return -1; + } + fmt[0] = '%'; + fmt[1] = disp->type ? disp->type : 'd'; + fmt[2] = '\0'; + for (i = 0; i < len; i += size, p += size) { + if (i) + printf(" "); + value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) : + size == 2 ? (*p << 8) | p[1] : *p; + printf(fmt, value); + } + return 0; +} + +/** + * List all properties in a node, one per line. + * + * @param blob FDT blob + * @param node Node to display + * @return 0 if ok, or FDT_ERR... if not. + */ +static int list_properties(const void *blob, int node) +{ + const struct fdt_property *data; + const char *name; + int prop; + + prop = fdt_first_property_offset(blob, node); + do { + /* Stop silently when there are no more properties */ + if (prop < 0) + return prop == -FDT_ERR_NOTFOUND ? 0 : prop; + data = fdt_get_property_by_offset(blob, prop, NULL); + name = fdt_string(blob, fdt32_to_cpu(data->nameoff)); + if (name) + puts(name); + prop = fdt_next_property_offset(blob, prop); + } while (1); +} + +#define MAX_LEVEL 32 /* how deeply nested we will go */ + +/** + * List all subnodes in a node, one per line + * + * @param blob FDT blob + * @param node Node to display + * @return 0 if ok, or FDT_ERR... if not. + */ +static int list_subnodes(const void *blob, int node) +{ + int nextoffset; /* next node offset from libfdt */ + uint32_t tag; /* current tag */ + int level = 0; /* keep track of nesting level */ + const char *pathp; + int depth = 1; /* the assumed depth of this node */ + + while (level >= 0) { + tag = fdt_next_tag(blob, node, &nextoffset); + switch (tag) { + case FDT_BEGIN_NODE: + pathp = fdt_get_name(blob, node, NULL); + if (level <= depth) { + if (pathp == NULL) + pathp = "/* NULL pointer error */"; + if (*pathp == '\0') + pathp = "/"; /* root is nameless */ + if (level == 1) + puts(pathp); + } + level++; + if (level >= MAX_LEVEL) { + printf("Nested too deep, aborting.\n"); + return 1; + } + break; + case FDT_END_NODE: + level--; + if (level == 0) + level = -1; /* exit the loop */ + break; + case FDT_END: + return 1; + case FDT_PROP: + break; + default: + if (level <= depth) + printf("Unknown tag 0x%08X\n", tag); + return 1; + } + node = nextoffset; + } + return 0; +} + +/** + * Show the data for a given node (and perhaps property) according to the + * display option provided. + * + * @param blob FDT blob + * @param disp Display information / options + * @param node Node to display + * @param property Name of property to display, or NULL if none + * @return 0 if ok, -ve on error + */ +static int show_data_for_item(const void *blob, struct display_info *disp, + int node, const char *property) +{ + const void *value = NULL; + int len, err = 0; + + switch (disp->mode) { + case MODE_LIST_PROPS: + err = list_properties(blob, node); + break; + + case MODE_LIST_SUBNODES: + err = list_subnodes(blob, node); + break; + + default: + assert(property); + value = fdt_getprop(blob, node, property, &len); + if (value) { + if (show_data(disp, value, len)) + err = -1; + else + printf("\n"); + } else if (disp->default_val) { + puts(disp->default_val); + } else { + report_error(property, len); + err = -1; + } + break; + } + + return err; +} + +/** + * Run the main fdtget operation, given a filename and valid arguments + * + * @param disp Display information / options + * @param filename Filename of blob file + * @param arg List of arguments to process + * @param arg_count Number of arguments + * @param return 0 if ok, -ve on error + */ +static int do_fdtget(struct display_info *disp, const char *filename, + char **arg, int arg_count, int args_per_step) +{ + char *blob; + const char *prop; + int i, node; + + blob = utilfdt_read(filename); + if (!blob) + return -1; + + for (i = 0; i + args_per_step <= arg_count; i += args_per_step) { + node = fdt_path_offset(blob, arg[i]); + if (node < 0) { + if (disp->default_val) { + puts(disp->default_val); + continue; + } else { + report_error(arg[i], node); + return -1; + } + } + prop = args_per_step == 1 ? NULL : arg[i + 1]; + + if (show_data_for_item(blob, disp, node, prop)) + return -1; + } + return 0; +} + +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 <options> <dt file> [<node> <property>]...\n" + " fdtget -p <options> <dt file> [<node> ]...\n" + "Options:\n" + "\t-t <type>\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 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[]) +{ + char *filename = NULL; + struct display_info disp; + int args_per_step = 2; + + /* set defaults */ + memset(&disp, '\0', sizeof(disp)); + disp.size = -1; + disp.mode = MODE_SHOW_VALUE; + 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"); + break; + + case 'p': + disp.mode = MODE_LIST_PROPS; + args_per_step = 1; + break; + + case 'l': + disp.mode = MODE_LIST_SUBNODES; + args_per_step = 1; + break; + + case 'd': + disp.default_val = optarg; + break; + } + } + + if (optind < argc) + filename = argv[optind++]; + if (!filename) + usage("Missing filename"); + + argv += optind; + argc -= optind; + + /* Allow no arguments, and silently succeed */ + if (!argc) + return 0; + + /* Check for node, property arguments */ + if (args_per_step == 2 && (argc % 2)) + usage("Must have an even number of arguments"); + + if (do_fdtget(&disp, filename, argv, argc, args_per_step)) + return 1; + return 0; +} diff --git a/scripts/dtc/fdtput.c b/scripts/dtc/fdtput.c new file mode 100644 index 00000000000..f2197f51930 --- /dev/null +++ b/scripts/dtc/fdtput.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * + * 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 the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libfdt.h> + +#include "util.h" + +/* These are the operations we support */ +enum oper_type { + OPER_WRITE_PROP, /* Write a property in a node */ + OPER_CREATE_NODE, /* Create a new node */ +}; + +struct display_info { + enum oper_type oper; /* operation to perform */ + int type; /* data type (s/i/u/x or 0 for default) */ + int size; /* data size (1/2/4) */ + int verbose; /* verbose output */ + int auto_path; /* automatically create all path components */ +}; + + +/** + * Report an error with a particular node. + * + * @param name Node name to report error on + * @param namelen Length of node name, or -1 to use entire string + * @param err Error number to report (-FDT_ERR_...) + */ +static void report_error(const char *name, int namelen, int err) +{ + if (namelen == -1) + namelen = strlen(name); + fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name, + fdt_strerror(err)); +} + +/** + * Encode a series of arguments in a property value. + * + * @param disp Display information / options + * @param arg List of arguments from command line + * @param arg_count Number of arguments (may be 0) + * @param valuep Returns buffer containing value + * @param *value_len Returns length of value encoded + */ +static int encode_value(struct display_info *disp, char **arg, int arg_count, + char **valuep, int *value_len) +{ + char *value = NULL; /* holding area for value */ + int value_size = 0; /* size of holding area */ + char *ptr; /* pointer to current value position */ + int len; /* length of this cell/string/byte */ + int ival; + int upto; /* the number of bytes we have written to buf */ + char fmt[3]; + + upto = 0; + + if (disp->verbose) + fprintf(stderr, "Decoding value:\n"); + + fmt[0] = '%'; + fmt[1] = disp->type ? disp->type : 'd'; + fmt[2] = '\0'; + for (; arg_count > 0; arg++, arg_count--, upto += len) { + /* assume integer unless told otherwise */ + if (disp->type == 's') + len = strlen(*arg) + 1; + else + len = disp->size == -1 ? 4 : disp->size; + + /* enlarge our value buffer by a suitable margin if needed */ + if (upto + len > value_size) { + value_size = (upto + len) + 500; + value = realloc(value, value_size); + if (!value) { + fprintf(stderr, "Out of mmory: cannot alloc " + "%d bytes\n", value_size); + return -1; + } + } + + ptr = value + upto; + if (disp->type == 's') { + memcpy(ptr, *arg, len); + if (disp->verbose) + fprintf(stderr, "\tstring: '%s'\n", ptr); + } else { + int *iptr = (int *)ptr; + sscanf(*arg, fmt, &ival); + if (len == 4) + *iptr = cpu_to_fdt32(ival); + else + *ptr = (uint8_t)ival; + if (disp->verbose) { + fprintf(stderr, "\t%s: %d\n", + disp->size == 1 ? "byte" : + disp->size == 2 ? "short" : "int", + ival); + } + } + } + *value_len = upto; + *valuep = value; + if (disp->verbose) + fprintf(stderr, "Value size %d\n", upto); + return 0; +} + +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); + if (node < 0) { + report_error(node_name, -1, node); + return -1; + } + + err = fdt_setprop(blob, node, property, buf, len); + if (err) { + report_error(property, -1, err); + return -1; + } + return 0; +} + +/** + * Create paths as needed for all components of a path + * + * Any components of the path that do not exist are created. Errors are + * reported. + * + * @param blob FDT blob to write into + * @param in_path Path to process + * @return 0 if ok, -1 on error + */ +static int create_paths(void *blob, const char *in_path) +{ + const char *path = in_path; + const char *sep; + int node, offset = 0; + + /* skip leading '/' */ + while (*path == '/') + path++; + + for (sep = path; *sep; path = sep + 1, offset = node) { + /* equivalent to strchrnul(), but it requires _GNU_SOURCE */ + sep = strchr(path, '/'); + if (!sep) + sep = path + strlen(path); + + node = fdt_subnode_offset_namelen(blob, offset, path, + sep - path); + if (node == -FDT_ERR_NOTFOUND) { + node = fdt_add_subnode_namelen(blob, offset, path, + sep - path); + } + if (node < 0) { + report_error(path, sep - path, node); + return -1; + } + } + + return 0; +} + +/** + * Create a new node in the fdt. + * + * This will overwrite the node_name string. Any error is reported. + * + * TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this. + * + * @param blob FDT blob to write into + * @param node_name Name of node to create + * @return new node offset if found, or -1 on failure + */ +static int create_node(void *blob, const char *node_name) +{ + int node = 0; + char *p; + + p = strrchr(node_name, '/'); + if (!p) { + report_error(node_name, -1, -FDT_ERR_BADPATH); + return -1; + } + *p = '\0'; + + if (p > 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); + if (node < 0) { + report_error(p + 1, -1, node); + return -1; + } + + return 0; +} + +static int do_fdtput(struct display_info *disp, const char *filename, + char **arg, int arg_count) +{ + char *value; + char *blob; + int len, ret = 0; + + blob = utilfdt_read(filename); + if (!blob) + return -1; + + switch (disp->oper) { + case OPER_WRITE_PROP: + /* + * Convert the arguments into a single binary value, then + * store them into the property. + */ + assert(arg_count >= 2); + 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)) + ret = -1; + break; + case OPER_CREATE_NODE: + for (; ret >= 0 && arg_count--; arg++) { + if (disp->auto_path) + ret = create_paths(blob, *arg); + else + ret = create_node(blob, *arg); + } + break; + } + if (ret >= 0) + ret = utilfdt_write(filename, blob); + + free(blob); + return ret; +} + +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 <options> <dt file> <node> <property> [<value>...]\n" + " fdtput -c <options> <dt file> [<node>...]\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 <type>\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 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[]) +{ + struct display_info disp; + char *filename = NULL; + + memset(&disp, '\0', sizeof(disp)); + disp.size = -1; + disp.oper = OPER_WRITE_PROP; + for (;;) { + int c = getopt(argc, argv, "chpt:v"); + if (c == -1) + break; + + /* + * TODO: add options to: + * - delete property + * - delete node (optionally recursively) + * - rename node + * - pack fdt before writing + * - set amount of free space when writing + * - expand fdt if value doesn't fit + */ + switch (c) { + case 'c': + disp.oper = OPER_CREATE_NODE; + break; + case 'h': + case '?': + usage(NULL); + case 'p': + disp.auto_path = 1; + break; + case 't': + if (utilfdt_decode_type(optarg, &disp.type, + &disp.size)) + usage("Invalid type string"); + break; + + case 'v': + disp.verbose = 1; + break; + } + } + + if (optind < argc) + filename = argv[optind++]; + if (!filename) + usage("Missing filename"); + + argv += optind; + argc -= optind; + + if (disp.oper == OPER_WRITE_PROP) { + if (argc < 1) + usage("Missing node"); + if (argc < 2) + usage("Missing property"); + } + + if (do_fdtput(&disp, filename, argv, argc)) + return 1; + return 0; +} diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index 28d0b2381df..665dad7bb46 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -263,6 +263,9 @@ static void flatten_tree(struct node *tree, struct emitter *emit, struct node *child; int seen_name_prop = 0; + if (tree->deleted) + return; + emit->beginnode(etarget, tree->labels); if (vi->flags & FTF_FULLPATH) diff --git a/scripts/dtc/libfdt/Makefile.libfdt b/scripts/dtc/libfdt/Makefile.libfdt index 6c42acfa21e..91126c000a1 100644 --- a/scripts/dtc/libfdt/Makefile.libfdt +++ b/scripts/dtc/libfdt/Makefile.libfdt @@ -3,6 +3,8 @@ # This is not a complete Makefile of itself. Instead, it is designed to # be easily embeddable into other systems of Makefiles. # -LIBFDT_INCLUDES = fdt.h libfdt.h -LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c +LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 +LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h +LIBFDT_VERSION = version.lds +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index 2acaec5923a..e56833ae9b6 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -74,7 +74,7 @@ int fdt_check_header(const void *fdt) return 0; } -const void *fdt_offset_ptr(const void *fdt, int offset, int len) +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { const char *p; @@ -90,42 +90,53 @@ const void *fdt_offset_ptr(const void *fdt, int offset, int len) return p; } -uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) +uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const uint32_t *tagp, *lenp; uint32_t tag; + int offset = startoffset; const char *p; - if (offset % FDT_TAGSIZE) - return -1; - + *nextoffset = -FDT_ERR_TRUNCATED; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); - if (! tagp) + if (!tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; + *nextoffset = -FDT_ERR_BADSTRUCTURE; switch (tag) { case FDT_BEGIN_NODE: /* skip name */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); - if (! p) - return FDT_END; + if (!p) + return FDT_END; /* premature end */ break; + case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); - if (! lenp) - return FDT_END; - /* skip name offset, length and value */ - offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); + if (!lenp) + return FDT_END; /* premature end */ + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + + fdt32_to_cpu(*lenp); + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: break; + + default: + return FDT_END; } - if (nextoffset) - *nextoffset = FDT_TAGALIGN(offset); + if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + *nextoffset = FDT_TAGALIGN(offset); return tag; } @@ -138,6 +149,15 @@ int _fdt_check_node_offset(const void *fdt, int offset) return 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)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; @@ -162,15 +182,16 @@ int fdt_next_node(const void *fdt, int offset, int *depth) break; case FDT_END_NODE: - if (depth) - (*depth)--; + if (depth && ((--(*depth)) < 0)) + return nextoffset; break; case FDT_END: - return -FDT_ERR_NOTFOUND; - - default: - return -FDT_ERR_BADSTRUCTURE; + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; } } while (tag != FDT_BEGIN_NODE); diff --git a/scripts/dtc/libfdt/fdt_empty_tree.c b/scripts/dtc/libfdt/fdt_empty_tree.c new file mode 100644 index 00000000000..f72d13b1d19 --- /dev/null +++ b/scripts/dtc/libfdt/fdt_empty_tree.c @@ -0,0 +1,84 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2012 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_create_empty_tree(void *buf, int bufsize) +{ + int err; + + err = fdt_create(buf, bufsize); + if (err) + return err; + + err = fdt_finish_reservemap(buf); + if (err) + return err; + + err = fdt_begin_node(buf, ""); + if (err) + return err; + + err = fdt_end_node(buf); + if (err) + return err; + + err = fdt_finish(buf); + if (err) + return err; + + return fdt_open_into(buf, buf, bufsize); +} + diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 22e692919ff..02b6d687537 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -80,6 +80,14 @@ 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, + const char *s, int len) +{ + const char *p = fdt_string(fdt, stroffset); + + return (strlen(p) == len) && (memcmp(p, s, len) == 0); +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); @@ -97,6 +105,30 @@ int fdt_num_mem_rsv(const void *fdt) return i; } +static int _nextprop(const void *fdt, int offset) +{ + uint32_t tag; + int nextoffset; + + do { + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; + + case FDT_PROP: + return offset; + } + offset = nextoffset; + } while (tag == FDT_NOP); + + return -FDT_ERR_NOTFOUND; +} + int fdt_subnode_offset_namelen(const void *fdt, int offset, const char *name, int namelen) { @@ -104,20 +136,16 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, FDT_CHECK_HEADER(fdt); - for (depth = 0, offset = fdt_next_node(fdt, offset, &depth); - (offset >= 0) && (depth > 0); - offset = fdt_next_node(fdt, offset, &depth)) { - if (depth < 0) - return -FDT_ERR_NOTFOUND; - else if ((depth == 1) - && _fdt_nodename_eq(fdt, offset, name, namelen)) + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) + && _fdt_nodename_eq(fdt, offset, name, namelen)) return offset; - } - if (offset < 0) - return offset; /* error */ - else + if (depth < 0) return -FDT_ERR_NOTFOUND; + return offset; /* error */ } int fdt_subnode_offset(const void *fdt, int parentoffset, @@ -134,8 +162,20 @@ int fdt_path_offset(const void *fdt, const char *path) FDT_CHECK_HEADER(fdt); - if (*path != '/') - return -FDT_ERR_BADPATH; + /* see if we have an alias */ + if (*path != '/') { + const char *q = strchr(path, '/'); + + if (!q) + q = end; + + p = fdt_get_alias_namelen(fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset(fdt, p); + + p = q; + } while (*p) { const char *q; @@ -178,93 +218,142 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) return NULL; } -const struct fdt_property *fdt_get_property(const void *fdt, - int nodeoffset, - const char *name, int *lenp) +int fdt_first_property_offset(const void *fdt, int nodeoffset) +{ + int offset; + + if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +int fdt_next_property_offset(const void *fdt, int offset) +{ + if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp) { - uint32_t tag; - const struct fdt_property *prop; - int namestroff; - int offset, nextoffset; int err; + const struct fdt_property *prop; - if (((err = fdt_check_header(fdt)) != 0) - || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) - goto fail; + if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } - nextoffset = err; - do { - offset = nextoffset; + prop = _fdt_offset_ptr(fdt, offset); - tag = fdt_next_tag(fdt, offset, &nextoffset); - switch (tag) { - case FDT_END: - err = -FDT_ERR_TRUNCATED; - goto fail; + if (lenp) + *lenp = fdt32_to_cpu(prop->len); - case FDT_BEGIN_NODE: - case FDT_END_NODE: - case FDT_NOP: - break; + return prop; +} - case FDT_PROP: - err = -FDT_ERR_BADSTRUCTURE; - prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); - if (! prop) - goto fail; - namestroff = fdt32_to_cpu(prop->nameoff); - if (strcmp(fdt_string(fdt, namestroff), name) == 0) { - /* Found it! */ - int len = fdt32_to_cpu(prop->len); - prop = fdt_offset_ptr(fdt, offset, - sizeof(*prop)+len); - if (! prop) - goto fail; - - if (lenp) - *lenp = len; - - return prop; - } - break; +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int offset, + const char *name, + int namelen, int *lenp) +{ + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; - default: - err = -FDT_ERR_BADSTRUCTURE; - goto fail; + if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { + offset = -FDT_ERR_INTERNAL; + break; } - } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); + if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), + name, namelen)) + return prop; + } - err = -FDT_ERR_NOTFOUND; - fail: if (lenp) - *lenp = err; + *lenp = offset; return NULL; } -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp) +const struct fdt_property *fdt_get_property(const void *fdt, + int nodeoffset, + const char *name, int *lenp) +{ + return fdt_get_property_namelen(fdt, nodeoffset, name, + strlen(name), lenp); +} + +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) { const struct fdt_property *prop; - prop = fdt_get_property(fdt, nodeoffset, name, lenp); + prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); if (! prop) return NULL; return prop->data; } +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) + *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + return prop->data; +} + +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); +} + uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) { const uint32_t *php; int len; - php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); - if (!php || (len != sizeof(*php))) - return 0; + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop(fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof(*php))) { + php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof(*php))) + return 0; + } return fdt32_to_cpu(*php); } +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen) +{ + int aliasoffset; + + aliasoffset = fdt_path_offset(fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; + + return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); +} + +const char *fdt_get_alias(const void *fdt, const char *name) +{ + return fdt_get_alias_namelen(fdt, name, strlen(name)); +} + int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { int pdepth = 0, p = 0; @@ -279,9 +368,6 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { - if (pdepth < depth) - continue; /* overflowed buffer */ - while (pdepth > depth) { do { p--; @@ -289,14 +375,16 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) pdepth--; } - name = fdt_get_name(fdt, offset, &namelen); - if (!name) - return namelen; - if ((p + namelen + 1) <= buflen) { - memcpy(buf + p, name, namelen); - p += namelen; - buf[p++] = '/'; - pdepth++; + if (pdepth >= depth) { + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { + memcpy(buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } } if (offset == nodeoffset) { @@ -306,7 +394,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) if (p > 1) /* special case so that root path is "/", not "" */ p--; buf[p] = '\0'; - return p; + return 0; } } @@ -404,14 +492,31 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { + int offset; + if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; - phandle = cpu_to_fdt32(phandle); - return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", - &phandle, sizeof(phandle)); + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node(fdt, -1, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (fdt_get_phandle(fdt, offset) == phandle) + return offset; + } + + return offset; /* error from fdt_next_node() */ } -static int _stringlist_contains(const char *strlist, int listlen, const char *str) +static int _fdt_stringlist_contains(const char *strlist, int listlen, + const char *str) { int len = strlen(str); const char *p; @@ -437,7 +542,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; - if (_stringlist_contains(prop, len, compatible)) + if (_fdt_stringlist_contains(prop, len, compatible)) return 0; else return 1; diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 8e7ec4cb7bc..24437dfc32b 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -289,6 +289,33 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, return 0; } +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = _fdt_splice_struct(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; +} + int fdt_delprop(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; @@ -406,6 +433,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; + if (struct_size < 0) + return struct_size; } if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c index 698329e0cca..55ebebf1eb2 100644 --- a/scripts/dtc/libfdt/fdt_sw.c +++ b/scripts/dtc/libfdt/fdt_sw.c @@ -70,7 +70,7 @@ static int _fdt_sw_check_header(void *fdt) return err; \ } -static void *_fdt_grab_space(void *fdt, int 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, int len) return NULL; fdt_set_size_dt_struct(fdt, offset + len); - return fdt_offset_ptr_w(fdt, offset, len); + return _fdt_offset_ptr_w(fdt, offset); } int fdt_create(void *buf, int bufsize) @@ -237,18 +237,17 @@ 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, sizeof(*prop)); + _fdt_offset_ptr_w(fdt, offset); int nameoff; - if (! prop) - return -FDT_ERR_BADSTRUCTURE; - nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } + if (nextoffset < 0) + return nextoffset; /* Finally, adjust the header */ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c index a4652c6e787..6025fa1fe8f 100644 --- a/scripts/dtc/libfdt/fdt_wip.c +++ b/scripts/dtc/libfdt/fdt_wip.c @@ -94,41 +94,14 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name) return 0; } -int _fdt_node_end_offset(void *fdt, int nodeoffset) +int _fdt_node_end_offset(void *fdt, int offset) { - int level = 0; - uint32_t tag; - int offset, nextoffset; - - tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); - if (tag != FDT_BEGIN_NODE) - return -FDT_ERR_BADOFFSET; - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_END: - return offset; - - case FDT_BEGIN_NODE: - level++; - break; - - case FDT_END_NODE: - level--; - break; - - case FDT_PROP: - case FDT_NOP: - break; - - default: - return -FDT_ERR_BADSTRUCTURE; - } - } while (level >= 0); - - return nextoffset; + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); + + return offset; } int fdt_nop_node(void *fdt, int nodeoffset) diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index ff6246f000c..73f49759a5e 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -61,7 +61,7 @@ #define FDT_ERR_NOTFOUND 1 /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ #define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attempted to create a node or property which + /* FDT_ERR_EXISTS: Attemped to create a node or property which * already exists */ #define FDT_ERR_NOSPACE 3 /* FDT_ERR_NOSPACE: Operation needed to expand the device @@ -122,7 +122,7 @@ /* Low-level functions (you probably don't need these) */ /**********************************************************************/ -const void *fdt_offset_ptr(const void *fdt, int offset, int checklen); +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) { return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); @@ -156,7 +156,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth); #define __fdt_set_hdr(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ - struct fdt_header *fdth = fdt; \ + struct fdt_header *fdth = (struct fdt_header*)fdt; \ fdth->name = cpu_to_fdt32(val); \ } __fdt_set_hdr(magic); @@ -343,6 +343,91 @@ int fdt_path_offset(const void *fdt, const char *path); const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); /** + * fdt_first_property_offset - find the offset of a node's first property + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * + * fdt_first_property_offset() finds the first property of the node at + * the given structure block offset. + * + * returns: + * structure block offset of the property (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested node has no properties + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_first_property_offset(const void *fdt, int nodeoffset); + +/** + * fdt_next_property_offset - step through a node's properties + * @fdt: pointer to the device tree blob + * @offset: structure block offset of a property + * + * fdt_next_property_offset() finds the property immediately after the + * one at the given structure block offset. This will be a property + * of the same node as the given property. + * + * returns: + * structure block offset of the next property (>=0), on success + * -FDT_ERR_NOTFOUND, if the given property is the last in its node + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_next_property_offset(const void *fdt, int offset); + +/** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to retrieve + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property_by_offset() retrieves a pointer to the + * fdt_property structure within the device tree blob at the given + * offset. If lenp is non-NULL, the length of the property value is + * also returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp); + +/** + * fdt_get_property_namelen - find a property based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @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. + */ +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); + +/** * fdt_get_property - find a given property in a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find @@ -380,6 +465,54 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, } /** + * fdt_getprop_by_offset - retrieve the value of a property at a given offset + * @fdt: pointer to the device tree blob + * @ffset: offset of the property to read + * @namep: pointer to a string variable (will be overwritten) or NULL + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop_by_offset() retrieves a pointer to the value of the + * property at structure block offset 'offset' (this will be a pointer + * to within the device blob itself, not a copy of the value). If + * lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. If namep is non-NULL, + * the property's namne will also be returned in the char * pointed to + * by namep (this will be a pointer to within the device tree's string + * block, not a new copy of the name). + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * if namep is non-NULL *namep contiains a pointer to the property + * name. + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp); + +/** + * fdt_getprop_namelen - get property value based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + */ +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); + +/** * fdt_getprop - retrieve the value of a given property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find @@ -429,6 +562,32 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset, uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); /** + * fdt_get_alias_namelen - get alias based on substring + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * @namelen: number of characters of name to consider + * + * Identical to fdt_get_alias(), but only examine the first namelen + * characters of name for matching the alias name. + */ +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen); + +/** + * fdt_get_alias - retreive the path referenced by a given alias + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * + * fdt_get_alias() retrieves the value of a given alias. That is, the + * value of the property named 'name' in the node /aliases. + * + * returns: + * a pointer to the expansion of the alias named 'name', of it exists + * NULL, if the given alias or the /aliases node does not exist + */ +const char *fdt_get_alias(const void *fdt, const char *name); + +/** * fdt_get_path - determine the full path of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose path to find @@ -693,17 +852,17 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** - * fdt_setprop_inplace_cell - change the value of a single-cell property + * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change - * @val: cell (32-bit integer) value to replace the property with + * @val: 32-bit integer value to replace the property with * - * fdt_setprop_inplace_cell() replaces the value of a given property - * with the 32-bit integer cell value in val, converting val to - * big-endian if necessary. This function cannot change the size of a - * property, and so will only work if the property already exists and - * has length 4. + * fdt_setprop_inplace_u32() replaces the value of a given property + * with the 32-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 4. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part @@ -712,7 +871,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, * returns: * 0, on success * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 - * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, @@ -720,14 +879,60 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ -static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) +static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) { val = cpu_to_fdt32(val); return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); } /** + * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to replace the property with + * + * fdt_setprop_inplace_u64() replaces the value of a given property + * with the 64-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 8. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + val = cpu_to_fdt64(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * + * This is an alternative name for fdt_setprop_inplace_u32() + */ +static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); +} + +/** * fdt_nop_property - replace a property with nop tags * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop @@ -786,11 +991,20 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); int fdt_finish_reservemap(void *fdt); int fdt_begin_node(void *fdt, const char *name); int fdt_property(void *fdt, const char *name, const void *val, int len); -static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) { val = cpu_to_fdt32(val); return fdt_property(fdt, name, &val, sizeof(val)); } +static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) +{ + val = cpu_to_fdt64(val); + return fdt_property(fdt, name, &val, sizeof(val)); +} +static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +{ + return fdt_property_u32(fdt, name, val); +} #define fdt_property_string(fdt, name, str) \ fdt_property(fdt, name, str, strlen(str)+1) int fdt_end_node(void *fdt); @@ -800,6 +1014,7 @@ int fdt_finish(void *fdt); /* Read-write functions */ /**********************************************************************/ +int fdt_create_empty_tree(void *buf, int bufsize); int fdt_open_into(const void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt); @@ -909,14 +1124,14 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** - * fdt_setprop_cell - set a property to a single cell value + * fdt_setprop_u32 - set a property to a 32-bit integer * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value for the property (native endian) * - * fdt_setprop_cell() sets the value of the named property in the - * given node to the given cell value (converting to big-endian if + * fdt_setprop_u32() sets the value of the named property in the given + * node to the given 32-bit integer value (converting to big-endian if * necessary), or creates a new property with that value if it does * not already exist. * @@ -936,14 +1151,60 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ -static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, - uint32_t val) +static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, + uint32_t val) { val = cpu_to_fdt32(val); return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); } /** + * fdt_setprop_u64 - set a property to a 64-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value for the property (native endian) + * + * fdt_setprop_u64() sets the value of the named property in the given + * node to the given 64-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value 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 + */ +static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, + uint64_t val) +{ + val = cpu_to_fdt64(val); + return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_setprop_cell - set a property to a single cell value + * + * This is an alternative name for fdt_setprop_u32() + */ +static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + return fdt_setprop_u32(fdt, nodeoffset, name, val); +} + +/** * fdt_setprop_string - set a property to a string value * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change @@ -975,6 +1236,147 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** + * fdt_appendprop - append to or create a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to append to + * @val: pointer to data to append to the property value + * @len: length of the data to append to the property value + * + * fdt_appendprop() appends the value to the named property in the + * given node, creating the property if it does not already exist. + * + * This function may insert data into 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_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_appendprop_u32 - append a 32-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u32() appends the given 32-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into 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 + */ +static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + val = cpu_to_fdt32(val); + return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_appendprop_u64 - append a 64-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u64() appends the given 64-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into 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 + */ +static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + val = cpu_to_fdt64(val); + return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_appendprop_cell - append a single cell value to a property + * + * This is an alternative name for fdt_appendprop_u32() + */ +static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_appendprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_appendprop_string - append a string to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value to append to the property + * + * fdt_appendprop_string() appends the given string to the value of + * the named property in the given node, or creates a new property + * with that value if it does not already exist. + * + * This function may insert data into 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_appendprop_string(fdt, nodeoffset, name, str) \ + fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** * fdt_delprop - delete a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h index 449bf602daf..213d7fb81c4 100644 --- a/scripts/dtc/libfdt/libfdt_env.h +++ b/scripts/dtc/libfdt/libfdt_env.h @@ -5,19 +5,25 @@ #include <stdint.h> #include <string.h> -#define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) +#define EXTRACT_BYTE(n) ((unsigned long long)((uint8_t *)&x)[n]) +static inline uint16_t fdt16_to_cpu(uint16_t x) +{ + return (EXTRACT_BYTE(0) << 8) | EXTRACT_BYTE(1); +} +#define cpu_to_fdt16(x) fdt16_to_cpu(x) + static inline uint32_t fdt32_to_cpu(uint32_t x) { - return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3); + return (EXTRACT_BYTE(0) << 24) | (EXTRACT_BYTE(1) << 16) | (EXTRACT_BYTE(2) << 8) | EXTRACT_BYTE(3); } #define cpu_to_fdt32(x) fdt32_to_cpu(x) static inline uint64_t fdt64_to_cpu(uint64_t x) { - return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32) - | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7); + return (EXTRACT_BYTE(0) << 56) | (EXTRACT_BYTE(1) << 48) | (EXTRACT_BYTE(2) << 40) | (EXTRACT_BYTE(3) << 32) + | (EXTRACT_BYTE(4) << 24) | (EXTRACT_BYTE(5) << 16) | (EXTRACT_BYTE(6) << 8) | EXTRACT_BYTE(7); } #define cpu_to_fdt64(x) fdt64_to_cpu(x) -#undef _B +#undef EXTRACT_BYTE #endif /* _LIBFDT_ENV_H */ diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index 46eb93e4af5..381133ba81d 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -62,8 +62,8 @@ return err; \ } -uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset); int _fdt_check_node_offset(const void *fdt, int offset); +int _fdt_check_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); diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 26d0e1e60c0..b61465fb2f3 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -29,16 +29,27 @@ void add_label(struct label **labels, char *label) struct label *new; /* Make sure the label isn't already there */ - for_each_label(*labels, new) - if (streq(new->label, label)) + for_each_label_withdel(*labels, new) + if (streq(new->label, label)) { + new->deleted = 0; return; + } new = xmalloc(sizeof(*new)); + memset(new, 0, sizeof(*new)); new->label = label; new->next = *labels; *labels = new; } +void delete_labels(struct label **labels) +{ + struct label *label; + + for_each_label(*labels, label) + label->deleted = 1; +} + struct property *build_property(char *name, struct data val) { struct property *new = xmalloc(sizeof(*new)); @@ -51,6 +62,18 @@ struct property *build_property(char *name, struct data val) return new; } +struct property *build_property_delete(char *name) +{ + struct property *new = xmalloc(sizeof(*new)); + + memset(new, 0, sizeof(*new)); + + new->name = name; + new->deleted = 1; + + return new; +} + struct property *chain_property(struct property *first, struct property *list) { assert(first->next == NULL); @@ -91,6 +114,17 @@ struct node *build_node(struct property *proplist, struct node *children) return new; } +struct node *build_node_delete(void) +{ + struct node *new = xmalloc(sizeof(*new)); + + memset(new, 0, sizeof(*new)); + + new->deleted = 1; + + return new; +} + struct node *name_node(struct node *node, char *name) { assert(node->name == NULL); @@ -106,8 +140,10 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) struct node *new_child, *old_child; struct label *l; + old_node->deleted = 0; + /* Add new node labels to old node */ - for_each_label(new_node->labels, l) + for_each_label_withdel(new_node->labels, l) add_label(&old_node->labels, l->label); /* Move properties from the new node to the old node. If there @@ -118,14 +154,21 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) new_node->proplist = new_prop->next; new_prop->next = NULL; + if (new_prop->deleted) { + delete_property_by_name(old_node, new_prop->name); + free(new_prop); + continue; + } + /* Look for a collision, set new value if there is */ - for_each_property(old_node, old_prop) { + for_each_property_withdel(old_node, old_prop) { if (streq(old_prop->name, new_prop->name)) { /* Add new labels to old property */ - for_each_label(new_prop->labels, l) + for_each_label_withdel(new_prop->labels, l) add_label(&old_prop->labels, l->label); old_prop->val = new_prop->val; + old_prop->deleted = 0; free(new_prop); new_prop = NULL; break; @@ -146,8 +189,14 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) new_child->parent = NULL; new_child->next_sibling = NULL; + if (new_child->deleted) { + delete_node_by_name(old_node, new_child->name); + free(new_child); + continue; + } + /* Search for a collision. Merge if there is */ - for_each_child(old_node, old_child) { + for_each_child_withdel(old_node, old_child) { if (streq(old_child->name, new_child->name)) { merge_nodes(old_child, new_child); new_child = NULL; @@ -155,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) } } - /* if no collision occurred, add child to the old node. */ + /* if no collision occured, add child to the old node. */ if (new_child) add_child(old_node, new_child); } @@ -188,6 +237,25 @@ void add_property(struct node *node, struct property *prop) *p = prop; } +void delete_property_by_name(struct node *node, char *name) +{ + struct property *prop = node->proplist; + + while (prop) { + if (!strcmp(prop->name, name)) { + delete_property(prop); + return; + } + prop = prop->next; + } +} + +void delete_property(struct property *prop) +{ + prop->deleted = 1; + delete_labels(&prop->labels); +} + void add_child(struct node *parent, struct node *child) { struct node **p; @@ -202,6 +270,32 @@ void add_child(struct node *parent, struct node *child) *p = child; } +void delete_node_by_name(struct node *parent, char *name) +{ + struct node *node = parent->children; + + while (node) { + if (!strcmp(node->name, name)) { + delete_node(node); + return; + } + node = node->next_sibling; + } +} + +void delete_node(struct node *node) +{ + struct property *prop; + struct node *child; + + node->deleted = 1; + for_each_child(node, child) + delete_node(child); + for_each_property(node, prop) + delete_property(prop); + delete_labels(&node->labels); +} + struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) { struct reserve_info *new = xmalloc(sizeof(*new)); @@ -353,8 +447,11 @@ struct node *get_node_by_path(struct node *tree, const char *path) const char *p; struct node *child; - if (!path || ! (*path)) + if (!path || ! (*path)) { + if (tree->deleted) + return NULL; return tree; + } while (path[0] == '/') path++; @@ -397,8 +494,11 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) assert((phandle != 0) && (phandle != -1)); - if (tree->phandle == phandle) + if (tree->phandle == phandle) { + if (tree->deleted) + return NULL; return tree; + } for_each_child(tree, child) { node = get_node_by_phandle(child, phandle); @@ -535,7 +635,7 @@ static void sort_properties(struct node *node) int n = 0, i = 0; struct property *prop, **tbl; - for_each_property(node, prop) + for_each_property_withdel(node, prop) n++; if (n == 0) @@ -543,7 +643,7 @@ static void sort_properties(struct node *node) tbl = xmalloc(n * sizeof(*tbl)); - for_each_property(node, prop) + for_each_property_withdel(node, prop) tbl[i++] = prop; qsort(tbl, n, sizeof(*tbl), cmp_prop); @@ -571,7 +671,7 @@ static void sort_subnodes(struct node *node) int n = 0, i = 0; struct node *subnode, **tbl; - for_each_child(node, subnode) + for_each_child_withdel(node, subnode) n++; if (n == 0) @@ -579,7 +679,7 @@ static void sort_subnodes(struct node *node) tbl = xmalloc(n * sizeof(*tbl)); - for_each_child(node, subnode) + for_each_child_withdel(node, subnode) tbl[i++] = subnode; qsort(tbl, n, sizeof(*tbl), cmp_subnode); @@ -598,7 +698,7 @@ static void sort_node(struct node *node) sort_properties(node); sort_subnodes(node); - for_each_child(node, c) + for_each_child_withdel(node, c) sort_node(c); } diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index 36a38e9f1a2..246ab4bc0d9 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -24,6 +24,15 @@ #include "dtc.h" #include "srcpos.h" +/* A node in our list of directories to search for source/include files */ +struct search_path { + struct search_path *next; /* next node in list, NULL for end */ + const char *dirname; /* name of directory to search */ +}; + +/* This is the list of directories that we search for source files */ +static struct search_path *search_path_head, **search_path_tail; + static char *dirname(const char *path) { @@ -47,6 +56,64 @@ struct srcfile_state *current_srcfile; /* = NULL */ #define MAX_SRCFILE_DEPTH (100) static int srcfile_depth; /* = 0 */ + +/** + * Try to open a file in a given directory. + * + * If the filename is an absolute path, then dirname is ignored. If it is a + * relative path, then we look in that directory for the file. + * + * @param dirname Directory to look in, or NULL for none + * @param fname Filename to look for + * @param fp Set to NULL if file did not open + * @return allocated filename on success (caller must free), NULL on failure + */ +static char *try_open(const char *dirname, const char *fname, FILE **fp) +{ + char *fullname; + + if (!dirname || fname[0] == '/') + fullname = xstrdup(fname); + else + fullname = join_path(dirname, fname); + + *fp = fopen(fullname, "r"); + if (!*fp) { + free(fullname); + fullname = NULL; + } + + return fullname; +} + +/** + * Open a file for read access + * + * If it is a relative filename, we search the full search path for it. + * + * @param fname Filename to open + * @param fp Returns pointer to opened FILE, or NULL on failure + * @return pointer to allocated filename, which caller must free + */ +static char *fopen_any_on_path(const char *fname, FILE **fp) +{ + const char *cur_dir = NULL; + struct search_path *node; + char *fullname; + + /* Try current directory first */ + assert(fp); + if (current_srcfile) + cur_dir = current_srcfile->dir; + fullname = try_open(cur_dir, fname, fp); + + /* Failing that, try each search path in turn */ + for (node = search_path_head; !*fp && node; node = node->next) + fullname = try_open(node->dirname, fname, fp); + + return fullname; +} + FILE *srcfile_relative_open(const char *fname, char **fullnamep) { FILE *f; @@ -56,13 +123,7 @@ FILE *srcfile_relative_open(const char *fname, char **fullnamep) f = stdin; fullname = xstrdup("<stdin>"); } else { - if (!current_srcfile || !current_srcfile->dir - || (fname[0] == '/')) - fullname = xstrdup(fname); - else - fullname = join_path(current_srcfile->dir, fname); - - f = fopen(fullname, "r"); + fullname = fopen_any_on_path(fname, &f); if (!f) die("Couldn't open \"%s\": %s\n", fname, strerror(errno)); @@ -119,6 +180,23 @@ int srcfile_pop(void) return current_srcfile ? 1 : 0; } +void srcfile_add_search_path(const char *dirname) +{ + struct search_path *node; + + /* Create the node */ + node = xmalloc(sizeof(*node)); + node->next = NULL; + node->dirname = xstrdup(dirname); + + /* Add to the end of our list */ + if (search_path_tail) + *search_path_tail = node; + else + search_path_head = node; + search_path_tail = &node->next; +} + /* * The empty source position. */ @@ -250,3 +328,9 @@ srcpos_warn(struct srcpos *pos, char const *fmt, ...) va_end(va); } + +void srcpos_set_line(char *f, int l) +{ + current_srcfile->name = f; + current_srcfile->lineno = l; +} diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h index ce980cafe58..93a27123c2e 100644 --- a/scripts/dtc/srcpos.h +++ b/scripts/dtc/srcpos.h @@ -33,10 +33,39 @@ struct srcfile_state { extern FILE *depfile; /* = NULL */ extern struct srcfile_state *current_srcfile; /* = NULL */ +/** + * Open a source file. + * + * If the source file is a relative pathname, then it is searched for in the + * current directory (the directory of the last source file read) and after + * that in the search path. + * + * We work through the search path in order from the first path specified to + * the last. + * + * If the file is not found, then this function does not return, but calls + * die(). + * + * @param fname Filename to search + * @param fullnamep If non-NULL, it is set to the allocated filename of the + * file that was opened. The caller is then responsible + * for freeing the pointer. + * @return pointer to opened FILE + */ FILE *srcfile_relative_open(const char *fname, char **fullnamep); + void srcfile_push(const char *fname); int srcfile_pop(void); +/** + * Add a new directory to the search path for input files + * + * The new path is added at the end of the list. + * + * @param dirname Directory to add + */ +void srcfile_add_search_path(const char *dirname); + struct srcpos { int first_line; int first_column; @@ -84,4 +113,6 @@ extern void srcpos_error(struct srcpos *pos, char const *, ...) extern void srcpos_warn(struct srcpos *pos, char const *, ...) __attribute__((format(printf, 2, 3))); +extern void srcpos_set_line(char *f, int l); + #endif /* _SRCPOS_H_ */ diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index c09aafade31..33eeba55fb4 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -23,6 +23,7 @@ extern FILE *yyin; extern int yyparse(void); +extern YYLTYPE yylloc; struct boot_info *the_boot_info; int treesource_error; @@ -34,6 +35,7 @@ struct boot_info *dt_from_source(const char *fname) srcfile_push(fname); yyin = current_srcfile->f; + yylloc.file = current_srcfile; if (yyparse() != 0) die("Unable to parse input tree\n"); diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index d7ac27d2ae1..2422c34e11d 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -1,6 +1,10 @@ /* + * Copyright 2011 The Chromium Authors, All Rights Reserved. * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. * + * util_is_printable_string contributed by + * Pantelis Antoniou <pantelis.antoniou AT gmail.com> + * * 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 the Free Software Foundation; either version 2 of the @@ -17,11 +21,18 @@ * USA */ +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> +#include <assert.h> + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include "libfdt.h" #include "util.h" char *xstrdup(const char *s) @@ -57,3 +68,264 @@ char *join_path(const char *path, const char *name) memcpy(str+lenp, name, lenn+1); return str; } + +int util_is_printable_string(const void *data, int len) +{ + const char *s = data; + const char *ss; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + ss = s; + while (*s && isprint(*s)) + s++; + + /* not zero, or not done yet */ + if (*s != '\0' || (s + 1 - ss) < len) + return 0; + + return 1; +} + +/* + * Parse a octal encoded character starting at index i in string s. The + * resulting character will be returned and the index i will be updated to + * point at the character directly after the end of the encoding, this may be + * the '\0' terminator of the string. + */ +static char get_oct_char(const char *s, int *i) +{ + char x[4]; + char *endx; + long val; + + x[3] = '\0'; + strncpy(x, s + *i, 3); + + val = strtol(x, &endx, 8); + + assert(endx > x); + + (*i) += endx - x; + return val; +} + +/* + * Parse a hexadecimal encoded character starting at index i in string s. The + * resulting character will be returned and the index i will be updated to + * point at the character directly after the end of the encoding, this may be + * the '\0' terminator of the string. + */ +static char get_hex_char(const char *s, int *i) +{ + char x[3]; + char *endx; + long val; + + x[2] = '\0'; + strncpy(x, s + *i, 2); + + val = strtol(x, &endx, 16); + if (!(endx > x)) + die("\\x used with no following hex digits\n"); + + (*i) += endx - x; + return val; +} + +char get_escape_char(const char *s, int *i) +{ + char c = s[*i]; + int j = *i + 1; + char val; + + assert(c); + switch (c) { + case 'a': + val = '\a'; + break; + case 'b': + val = '\b'; + break; + case 't': + val = '\t'; + break; + case 'n': + val = '\n'; + break; + case 'v': + val = '\v'; + break; + case 'f': + val = '\f'; + break; + case 'r': + val = '\r'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + j--; /* need to re-read the first digit as + * part of the octal value */ + val = get_oct_char(s, &j); + break; + case 'x': + val = get_hex_char(s, &j); + break; + default: + val = c; + } + + (*i) = j; + return val; +} + +int utilfdt_read_err(const char *filename, char **buffp) +{ + int fd = 0; /* assume stdin */ + char *buf = NULL; + off_t bufsize = 1024, offset = 0; + int ret = 0; + + *buffp = NULL; + if (strcmp(filename, "-") != 0) { + fd = open(filename, O_RDONLY); + if (fd < 0) + return errno; + } + + /* Loop until we have read everything */ + buf = malloc(bufsize); + do { + /* Expand the buffer to hold the next chunk */ + if (offset == bufsize) { + bufsize *= 2; + buf = realloc(buf, bufsize); + if (!buf) { + ret = ENOMEM; + break; + } + } + + ret = read(fd, &buf[offset], bufsize - offset); + if (ret < 0) { + ret = errno; + break; + } + offset += ret; + } while (ret != 0); + + /* Clean up, including closing stdin; return errno on error */ + close(fd); + if (ret) + free(buf); + else + *buffp = buf; + return ret; +} + +char *utilfdt_read(const char *filename) +{ + char *buff; + int ret = utilfdt_read_err(filename, &buff); + + if (ret) { + fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, + strerror(ret)); + return NULL; + } + /* Successful read */ + return buff; +} + +int utilfdt_write_err(const char *filename, const void *blob) +{ + int fd = 1; /* assume stdout */ + int totalsize; + int offset; + int ret = 0; + const char *ptr = blob; + + if (strcmp(filename, "-") != 0) { + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) + return errno; + } + + totalsize = fdt_totalsize(blob); + offset = 0; + + while (offset < totalsize) { + ret = write(fd, ptr + offset, totalsize - offset); + if (ret < 0) { + ret = -errno; + break; + } + offset += ret; + } + /* Close the file/stdin; return errno on error */ + if (fd != 1) + close(fd); + return ret < 0 ? -ret : 0; +} + + +int utilfdt_write(const char *filename, const void *blob) +{ + int ret = utilfdt_write_err(filename, blob); + + if (ret) { + fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename, + strerror(ret)); + } + return ret ? -1 : 0; +} + +int utilfdt_decode_type(const char *fmt, int *type, int *size) +{ + int qualifier = 0; + + if (!*fmt) + return -1; + + /* get the conversion qualifier */ + *size = -1; + if (strchr("hlLb", *fmt)) { + qualifier = *fmt++; + if (qualifier == *fmt) { + switch (*fmt++) { +/* TODO: case 'l': qualifier = 'L'; break;*/ + case 'h': + qualifier = 'b'; + break; + } + } + } + + /* we should now have a type */ + if ((*fmt == '\0') || !strchr("iuxs", *fmt)) + return -1; + + /* convert qualifier (bhL) to byte size */ + if (*fmt != 's') + *size = qualifier == 'b' ? 1 : + qualifier == 'h' ? 2 : + qualifier == 'l' ? 4 : -1; + *type = *fmt++; + + /* that should be it! */ + if (*fmt) + return -1; + return 0; +} diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index 9cead842c11..c8eb45d9f04 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -1,7 +1,10 @@ #ifndef _UTIL_H #define _UTIL_H +#include <stdarg.h> + /* + * Copyright 2011 The Chromium Authors, All Rights Reserved. * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or @@ -53,4 +56,98 @@ static inline void *xrealloc(void *p, size_t len) extern char *xstrdup(const char *s); extern char *join_path(const char *path, const char *name); +/** + * Check a string of a given length to see if it is all printable and + * has a valid terminator. + * + * @param data The string to check + * @param len The string length including terminator + * @return 1 if a valid printable string, 0 if not */ +int util_is_printable_string(const void *data, int len); + +/* + * Parse an escaped character starting at index i in string s. The resulting + * character will be returned and the index i will be updated to point at the + * character directly after the end of the encoding, this may be the '\0' + * terminator of the string. + */ +char get_escape_char(const char *s, int *i); + +/** + * Read a device tree file into a buffer. This will report any errors on + * stderr. + * + * @param filename The filename to read, or - for stdin + * @return Pointer to allocated buffer containing fdt, or NULL on error + */ +char *utilfdt_read(const char *filename); + +/** + * Read a device tree file into a buffer. Does not report errors, but only + * returns them. The value returned can be passed to strerror() to obtain + * an error message for the user. + * + * @param filename The filename to read, or - for stdin + * @param buffp Returns pointer to buffer containing fdt + * @return 0 if ok, else an errno value representing the error + */ +int utilfdt_read_err(const char *filename, char **buffp); + + +/** + * Write a device tree buffer to a file. This will report any errors on + * stderr. + * + * @param filename The filename to write, or - for stdout + * @param blob Poiner to buffer containing fdt + * @return 0 if ok, -1 on error + */ +int utilfdt_write(const char *filename, const void *blob); + +/** + * Write a device tree buffer to a file. Does not report errors, but only + * returns them. The value returned can be passed to strerror() to obtain + * an error message for the user. + * + * @param filename The filename to write, or - for stdout + * @param blob Poiner to buffer containing fdt + * @return 0 if ok, else an errno value representing the error + */ +int utilfdt_write_err(const char *filename, const void *blob); + +/** + * Decode a data type string. The purpose of this string + * + * The string consists of an optional character followed by the type: + * Modifier characters: + * hh or b 1 byte + * h 2 byte + * l 4 byte, default + * + * Type character: + * s string + * i signed integer + * u unsigned integer + * x hex + * + * TODO: Implement ll modifier (8 bytes) + * TODO: Implement o type (octal) + * + * @param fmt Format string to process + * @param type Returns type found(s/d/u/x), or 0 if none + * @param size Returns size found(1,2,4,8) or 4 if none + * @return 0 if ok, -1 on error (no type given, or other invalid format) + */ +int utilfdt_decode_type(const char *fmt, int *type, int *size); + +/* + * This is a usage message fragment for the -t option. It is the format + * supported by utilfdt_decode_type. + */ + +#define USAGE_TYPE_MSG \ + "<type>\ts=string, i=int, u=unsigned, x=hex\n" \ + "\tOptional modifier prefix:\n" \ + "\t\thh or b=byte, h=2 byte, l=4 byte (default)\n"; + #endif /* _UTIL_H */ |