diff options
Diffstat (limited to 'scripts/dtc')
36 files changed, 1489 insertions, 462 deletions
diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore index b814e6076bdb..e0b5c1d2464a 100644 --- a/scripts/dtc/.gitignore +++ b/scripts/dtc/.gitignore @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -dtc +/dtc +/fdtoverlay diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 0b44917f981c..4d32b9497da9 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -1,30 +1,23 @@ # SPDX-License-Identifier: GPL-2.0 # scripts/dtc makefile -hostprogs := dtc -always-$(CONFIG_DTC) += $(hostprogs) -always-$(CHECK_DT_BINDING) += $(hostprogs) +# *** Also keep .gitignore in sync when changing *** +hostprogs-always-$(CONFIG_DTC) += dtc fdtoverlay +hostprogs-always-$(CHECK_DT_BINDING) += dtc dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ srcpos.o checks.o util.o dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o -# Source files need to get at the userspace version of libfdt_env.h to compile -HOST_EXTRACFLAGS := -I $(srctree)/$(src)/libfdt +# The upstream project builds libfdt as a separate library. We are choosing to +# instead directly link the libfdt object files into fdtoverlay. +libfdt-objs := fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o fdt_strerror.o fdt_empty_tree.o fdt_addresses.o fdt_overlay.o +libfdt = $(addprefix libfdt/,$(libfdt-objs)) +fdtoverlay-objs := $(libfdt) fdtoverlay.o util.o -ifeq ($(shell pkg-config --exists yaml-0.1 2>/dev/null && echo yes),) -ifneq ($(CHECK_DT_BINDING)$(CHECK_DTBS),) -$(error dtc needs libyaml for DT schema validation support. \ - Install the necessary libyaml development package.) -endif +# Source files need to get at the userspace version of libfdt_env.h to compile +HOST_EXTRACFLAGS += -I $(srctree)/$(src)/libfdt HOST_EXTRACFLAGS += -DNO_YAML -else -dtc-objs += yamltree.o -# To include <yaml.h> installed in a non-default path -HOSTCFLAGS_yamltree.o := $(shell pkg-config --cflags yaml-0.1) -# To link libyaml installed in a non-default path -HOSTLDLIBS_dtc := $(shell pkg-config yaml-0.1 --libs) -endif # Generated files need one more search path to include headers in source tree HOSTCFLAGS_dtc-lexer.lex.o := -I $(srctree)/$(src) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index b7955dbd71ca..9f31d2607182 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -143,6 +143,14 @@ static void check_nodes_props(struct check *c, struct dt_info *dti, struct node check_nodes_props(c, dti, child); } +static bool is_multiple_of(int multiple, int divisor) +{ + if (divisor == 0) + return multiple == 0; + else + return (multiple % divisor) == 0; +} + static bool run_check(struct check *c, struct dt_info *dti) { struct node *dt = dti->dt; @@ -297,19 +305,20 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL); #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define DIGITS "0123456789" -#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" +#define NODECHARS LOWERCASE UPPERCASE DIGITS ",._+-@" +#define PROPCHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" #define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-" static void check_node_name_chars(struct check *c, struct dt_info *dti, struct node *node) { - int n = strspn(node->name, c->data); + size_t n = strspn(node->name, c->data); if (n < strlen(node->name)) FAIL(c, dti, node, "Bad character '%c' in node name", node->name[n]); } -ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); +ERROR(node_name_chars, check_node_name_chars, NODECHARS); static void check_node_name_chars_strict(struct check *c, struct dt_info *dti, struct node *node) @@ -330,6 +339,20 @@ static void check_node_name_format(struct check *c, struct dt_info *dti, } ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); +static void check_node_name_vs_property_name(struct check *c, + struct dt_info *dti, + struct node *node) +{ + if (!node->parent) + return; + + if (get_property(node->parent, node->name)) { + FAIL(c, dti, node, "node name and property name conflict"); + } +} +WARNING(node_name_vs_property_name, check_node_name_vs_property_name, + NULL, &node_name_chars); + static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, struct node *node) { @@ -363,14 +386,14 @@ static void check_property_name_chars(struct check *c, struct dt_info *dti, struct property *prop; for_each_property(node, prop) { - int n = strspn(prop->name, c->data); + size_t n = strspn(prop->name, c->data); if (n < strlen(prop->name)) FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name", prop->name[n]); } } -ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); +ERROR(property_name_chars, check_property_name_chars, PROPCHARS); static void check_property_name_chars_strict(struct check *c, struct dt_info *dti, @@ -380,7 +403,7 @@ static void check_property_name_chars_strict(struct check *c, for_each_property(node, prop) { const char *name = prop->name; - int n = strspn(name, c->data); + size_t n = strspn(name, c->data); if (n == strlen(prop->name)) continue; @@ -497,7 +520,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, phandle = propval_cell(prop); - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property", phandle, prop->name); return 0; @@ -556,7 +579,7 @@ static void check_name_properties(struct check *c, struct dt_info *dti, if (!prop) return; /* No name property, that's fine */ - if ((prop->val.len != node->basenamelen+1) + if ((prop->val.len != node->basenamelen + 1U) || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead" " of base node name)", prop->val.val); @@ -657,7 +680,6 @@ ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &pa */ WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); -WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); WARNING_IF_NOT_STRING(model_is_string, "model"); @@ -672,8 +694,7 @@ static void check_names_is_string_list(struct check *c, struct dt_info *dti, struct property *prop; for_each_property(node, prop) { - const char *s = strrchr(prop->name, '-'); - if (!s || !streq(s, "-names")) + if (!strends(prop->name, "-names")) continue; c->data = prop->name; @@ -753,7 +774,7 @@ static void check_reg_format(struct check *c, struct dt_info *dti, size_cells = node_size_cells(node->parent); entrylen = (addr_cells + size_cells) * sizeof(cell_t); - if (!entrylen || (prop->val.len % entrylen) != 0) + if (!is_multiple_of(prop->val.len, entrylen)) FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) " "(#address-cells == %d, #size-cells == %d)", prop->val.len, addr_cells, size_cells); @@ -794,7 +815,7 @@ static void check_ranges_format(struct check *c, struct dt_info *dti, "#size-cells (%d) differs from %s (%d)", ranges, c_size_cells, node->parent->fullpath, p_size_cells); - } else if ((prop->val.len % entrylen) != 0) { + } else if (!is_multiple_of(prop->val.len, entrylen)) { FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) " "(parent #address-cells == %d, child #address-cells == %d, " "#size-cells == %d)", ranges, prop->val.len, @@ -871,7 +892,7 @@ static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struc } else { cells = (cell_t *)prop->val.val; min_bus = fdt32_to_cpu(cells[0]); - max_bus = fdt32_to_cpu(cells[0]); + max_bus = fdt32_to_cpu(cells[1]); } if ((bus_num < min_bus) || (bus_num > max_bus)) FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)", @@ -891,10 +912,8 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no return; prop = get_property(node, "reg"); - if (!prop) { - FAIL(c, dti, node, "missing PCI reg property"); + if (!prop) return; - } cells = (cell_t *)prop->val.val; if (cells[1] || cells[2]) @@ -1363,15 +1382,15 @@ struct provider { }; static void check_property_phandle_args(struct check *c, - struct dt_info *dti, - struct node *node, - struct property *prop, - const struct provider *provider) + struct dt_info *dti, + struct node *node, + struct property *prop, + const struct provider *provider) { struct node *root = dti->dt; - int cell, cellsize = 0; + unsigned int cell, cellsize = 0; - if (prop->val.len % sizeof(cell_t)) { + if (!is_multiple_of(prop->val.len, sizeof(cell_t))) { FAIL_PROP(c, dti, node, prop, "property size (%d) is invalid, expected multiple of %zu", prop->val.len, sizeof(cell_t)); @@ -1381,14 +1400,15 @@ static void check_property_phandle_args(struct check *c, for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) { struct node *provider_node; struct property *cellprop; - int phandle; + cell_t phandle; + unsigned int expected; phandle = propval_cell_n(prop, cell); /* * Some bindings use a cell value 0 or -1 to skip over optional * entries when each index position has a specific definition. */ - if (phandle == 0 || phandle == -1) { + if (!phandle_is_valid(phandle)) { /* Give up if this is an overlay with external references */ if (dti->dtsflags & DTSF_PLUGIN) break; @@ -1431,10 +1451,12 @@ static void check_property_phandle_args(struct check *c, break; } - if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) { + expected = (cell + cellsize + 1) * sizeof(cell_t); + if ((expected <= cell) || prop->val.len < expected) { FAIL_PROP(c, dti, node, prop, - "property size (%d) too small for cell size %d", + "property size (%d) too small for cell size %u", prop->val.len, cellsize); + break; } } } @@ -1454,7 +1476,8 @@ static void check_provider_cells_property(struct check *c, } #define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \ static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \ - WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references); + WARNING_IF_NOT_CELL(nm##_is_cell, cells_name); \ + WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &nm##_is_cell, &phandle_references); WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells"); WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells"); @@ -1475,24 +1498,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sen static bool prop_is_gpio(struct property *prop) { - char *str; - /* * *-gpios and *-gpio can appear in property names, * so skip over any false matches (only one known ATM) */ - if (strstr(prop->name, "nr-gpio")) - return false; - - str = strrchr(prop->name, '-'); - if (str) - str++; - else - str = prop->name; - if (!(streq(str, "gpios") || streq(str, "gpio"))) + if (strends(prop->name, ",nr-gpios")) return false; - return true; + return strends(prop->name, "-gpios") || + streq(prop->name, "gpios") || + strends(prop->name, "-gpio") || + streq(prop->name, "gpio"); } static void check_gpios_property(struct check *c, @@ -1527,13 +1543,10 @@ static void check_deprecated_gpio_property(struct check *c, struct property *prop; for_each_property(node, prop) { - char *str; - if (!prop_is_gpio(prop)) continue; - str = strstr(prop->name, "gpio"); - if (!streq(str, "gpio")) + if (!strends(prop->name, "gpio")) continue; FAIL_PROP(c, dti, node, prop, @@ -1563,21 +1576,106 @@ static void check_interrupt_provider(struct check *c, struct node *node) { struct property *prop; + bool irq_provider = node_is_interrupt_provider(node); - if (!node_is_interrupt_provider(node)) + prop = get_property(node, "#interrupt-cells"); + if (irq_provider && !prop) { + FAIL(c, dti, node, + "Missing '#interrupt-cells' in interrupt provider"); return; + } - prop = get_property(node, "#interrupt-cells"); - if (!prop) + if (!irq_provider && prop) { FAIL(c, dti, node, - "Missing #interrupt-cells in interrupt provider"); + "'#interrupt-cells' found, but node is not an interrupt provider"); + return; + } +} +WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell); - prop = get_property(node, "#address-cells"); - if (!prop) +static void check_interrupt_map(struct check *c, + struct dt_info *dti, + struct node *node) +{ + struct node *root = dti->dt; + struct property *prop, *irq_map_prop; + size_t cellsize, cell, map_cells; + + irq_map_prop = get_property(node, "interrupt-map"); + if (!irq_map_prop) + return; + + if (node->addr_cells < 0) { FAIL(c, dti, node, - "Missing #address-cells in interrupt provider"); + "Missing '#address-cells' in interrupt-map provider"); + return; + } + cellsize = node_addr_cells(node); + cellsize += propval_cell(get_property(node, "#interrupt-cells")); + + prop = get_property(node, "interrupt-map-mask"); + if (prop && (prop->val.len != (cellsize * sizeof(cell_t)))) + FAIL_PROP(c, dti, node, prop, + "property size (%d) is invalid, expected %zu", + prop->val.len, cellsize * sizeof(cell_t)); + + if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) { + FAIL_PROP(c, dti, node, irq_map_prop, + "property size (%d) is invalid, expected multiple of %zu", + irq_map_prop->val.len, sizeof(cell_t)); + return; + } + + map_cells = irq_map_prop->val.len / sizeof(cell_t); + for (cell = 0; cell < map_cells; ) { + struct node *provider_node; + struct property *cellprop; + int phandle; + size_t parent_cellsize; + + if ((cell + cellsize) >= map_cells) { + FAIL_PROP(c, dti, node, irq_map_prop, + "property size (%d) too small, expected > %zu", + irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t)); + break; + } + cell += cellsize; + + phandle = propval_cell_n(irq_map_prop, cell); + if (!phandle_is_valid(phandle)) { + /* Give up if this is an overlay with external references */ + if (!(dti->dtsflags & DTSF_PLUGIN)) + FAIL_PROP(c, dti, node, irq_map_prop, + "Cell %zu is not a phandle(%d)", + cell, phandle); + break; + } + + provider_node = get_node_by_phandle(root, phandle); + if (!provider_node) { + FAIL_PROP(c, dti, node, irq_map_prop, + "Could not get phandle(%d) node for (cell %zu)", + phandle, cell); + break; + } + + cellprop = get_property(provider_node, "#interrupt-cells"); + if (cellprop) { + parent_cellsize = propval_cell(cellprop); + } else { + FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])", + provider_node->fullpath, cell); + break; + } + + cellprop = get_property(provider_node, "#address-cells"); + if (cellprop) + parent_cellsize += propval_cell(cellprop); + + cell += 1 + parent_cellsize; + } } -WARNING(interrupt_provider, check_interrupt_provider, NULL); +WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider); static void check_interrupts_property(struct check *c, struct dt_info *dti, @@ -1586,13 +1684,13 @@ static void check_interrupts_property(struct check *c, struct node *root = dti->dt; struct node *irq_node = NULL, *parent = node; struct property *irq_prop, *prop = NULL; - int irq_cells, phandle; + cell_t irq_cells, phandle; irq_prop = get_property(node, "interrupts"); if (!irq_prop) return; - if (irq_prop->val.len % sizeof(cell_t)) + if (!is_multiple_of(irq_prop->val.len, sizeof(cell_t))) FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu", irq_prop->val.len, sizeof(cell_t)); @@ -1605,7 +1703,7 @@ static void check_interrupts_property(struct check *c, prop = get_property(parent, "interrupt-parent"); if (prop) { phandle = propval_cell(prop); - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { /* Give up if this is an overlay with * external references */ if (dti->dtsflags & DTSF_PLUGIN) @@ -1641,7 +1739,7 @@ static void check_interrupts_property(struct check *c, } irq_cells = propval_cell(prop); - if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) { + if (!is_multiple_of(irq_prop->val.len, irq_cells * sizeof(cell_t))) { FAIL_PROP(c, dti, node, prop, "size is (%d), expected multiple of %d", irq_prop->val.len, (int)(irq_cells * sizeof(cell_t))); @@ -1752,7 +1850,7 @@ WARNING(graph_port, check_graph_port, NULL, &graph_nodes); static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, struct node *endpoint) { - int phandle; + cell_t phandle; struct node *node; struct property *prop; @@ -1762,7 +1860,7 @@ static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, phandle = propval_cell(prop); /* Give up if this is an overlay with external references */ - if (phandle == 0 || phandle == -1) + if (!phandle_is_valid(phandle)) return NULL; node = get_node_by_phandle(dti->dt, phandle); @@ -1798,7 +1896,7 @@ WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, &node_name_chars, &node_name_format, &property_name_chars, - &name_is_string, &name_properties, + &name_is_string, &name_properties, &node_name_vs_property_name, &duplicate_label, @@ -1806,7 +1904,7 @@ static struct check *check_table[] = { &phandle_references, &path_references, &omit_unused_nodes, - &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, + &address_cells_is_cell, &size_cells_is_cell, &device_type_is_string, &model_is_string, &status_is_string, &label_is_string, @@ -1841,26 +1939,43 @@ static struct check *check_table[] = { &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, &clocks_property, + &clocks_is_cell, &cooling_device_property, + &cooling_device_is_cell, &dmas_property, + &dmas_is_cell, &hwlocks_property, + &hwlocks_is_cell, &interrupts_extended_property, + &interrupts_extended_is_cell, &io_channels_property, + &io_channels_is_cell, &iommus_property, + &iommus_is_cell, &mboxes_property, + &mboxes_is_cell, &msi_parent_property, + &msi_parent_is_cell, &mux_controls_property, + &mux_controls_is_cell, &phys_property, + &phys_is_cell, &power_domains_property, + &power_domains_is_cell, &pwms_property, + &pwms_is_cell, &resets_property, + &resets_is_cell, &sound_dai_property, + &sound_dai_is_cell, &thermal_sensors_property, + &thermal_sensors_is_cell, &deprecated_gpio_property, &gpios_property, &interrupts_property, &interrupt_provider, + &interrupt_map, &alias_paths, @@ -1884,7 +1999,7 @@ static void enable_warning_error(struct check *c, bool warn, bool error) static void disable_warning_error(struct check *c, bool warn, bool error) { - int i; + unsigned int i; /* Lowering level, also lower it for things this is the prereq * for */ @@ -1905,7 +2020,7 @@ static void disable_warning_error(struct check *c, bool warn, bool error) void parse_checks_option(bool warn, bool error, const char *arg) { - int i; + unsigned int i; const char *name = arg; bool enable = true; @@ -1932,7 +2047,7 @@ void parse_checks_option(bool warn, bool error, const char *arg) void process_checks(bool force, struct dt_info *dti) { - int i; + unsigned int i; int error = 0; for (i = 0; i < ARRAY_SIZE(check_table); i++) { diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index 0a43b6de3264..14734233ad8b 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -21,10 +21,10 @@ void data_free(struct data d) free(d.val); } -struct data data_grow_for(struct data d, int xlen) +struct data data_grow_for(struct data d, unsigned int xlen) { struct data nd; - int newsize; + unsigned int newsize; if (xlen == 0) return d; @@ -84,7 +84,7 @@ struct data data_copy_file(FILE *f, size_t maxlen) while (!feof(f) && (d.len < maxlen)) { size_t chunksize, ret; - if (maxlen == -1) + if (maxlen == (size_t)-1) chunksize = 4096; else chunksize = maxlen - d.len; diff --git a/scripts/dtc/dt-extract-compatibles b/scripts/dtc/dt-extract-compatibles new file mode 100755 index 000000000000..5ffb2364409b --- /dev/null +++ b/scripts/dtc/dt-extract-compatibles @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only + +import fnmatch +import os +import re +import argparse + + +def parse_of_declare_macros(data, include_driver_macros=True): + """ Find all compatible strings in OF_DECLARE() style macros """ + compat_list = [] + # CPU_METHOD_OF_DECLARE does not have a compatible string + if include_driver_macros: + re_macros = r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)' + else: + re_macros = r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)\(.*?\)' + for m in re.finditer(re_macros, data): + try: + compat = re.search(r'"(.*?)"', m[0])[1] + except: + # Fails on compatible strings in #define, so just skip + continue + compat_list += [compat] + + return compat_list + + +def parse_of_device_id(data, match_table_list=None): + """ Find all compatible strings in of_device_id structs """ + compat_list = [] + for m in re.finditer(r'of_device_id(\s+\S+)?\s+(\S+)\[\](\s+\S+)?\s*=\s*({.*?);', data): + if match_table_list is not None and m[2] not in match_table_list: + continue + compat_list += re.findall(r'\.compatible\s+=\s+"(\S+)"', m[4]) + + return compat_list + + +def parse_of_match_table(data): + """ Find all driver's of_match_table """ + match_table_list = [] + for m in re.finditer(r'\.of_match_table\s+=\s+(of_match_ptr\()?([a-zA-Z0-9_-]+)', data): + match_table_list.append(m[2]) + + return match_table_list + + +def parse_compatibles(file, compat_ignore_list): + with open(file, 'r', encoding='utf-8') as f: + data = f.read().replace('\n', '') + + if compat_ignore_list is not None: + # For a compatible in the DT to be matched to a driver it needs to show + # up in a driver's of_match_table + match_table_list = parse_of_match_table(data) + compat_list = parse_of_device_id(data, match_table_list) + + compat_list = [compat for compat in compat_list if compat not in compat_ignore_list] + else: + compat_list = parse_of_declare_macros(data) + compat_list += parse_of_device_id(data) + + return compat_list + +def parse_compatibles_to_ignore(file): + with open(file, 'r', encoding='utf-8') as f: + data = f.read().replace('\n', '') + + # Compatibles that show up in OF_DECLARE macros can't be expected to + # match a driver, except for the _DRIVER ones. + return parse_of_declare_macros(data, include_driver_macros=False) + + +def print_compat(filename, compatibles): + if not compatibles: + return + if show_filename: + compat_str = ' '.join(compatibles) + print(filename + ": compatible(s): " + compat_str) + else: + print(*compatibles, sep='\n') + +def glob_without_symlinks(root, glob): + for path, dirs, files in os.walk(root): + # Ignore hidden directories + for d in dirs: + if fnmatch.fnmatch(d, ".*"): + dirs.remove(d) + for f in files: + if fnmatch.fnmatch(f, glob): + yield os.path.join(path, f) + +def files_to_parse(path_args): + for f in path_args: + if os.path.isdir(f): + for filename in glob_without_symlinks(f, "*.c"): + yield filename + else: + yield f + +show_filename = False + +if __name__ == "__main__": + ap = argparse.ArgumentParser() + ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse") + ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true") + ap.add_argument('-d', '--driver-match', help="Only print compatibles that should match to a driver", action="store_true") + args = ap.parse_args() + + show_filename = args.with_filename + compat_ignore_list = None + + if args.driver_match: + compat_ignore_list = [] + for f in files_to_parse(args.cfile): + compat_ignore_list.extend(parse_compatibles_to_ignore(f)) + + for f in files_to_parse(args.cfile): + compat_list = parse_compatibles(f, compat_ignore_list) + print_compat(f, compat_list) diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index b3b7270300de..de60a70b6bdb 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -57,7 +57,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); push_input_file(name); } -<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { +<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* { char *line, *fnstart, *fnend; struct data fn; /* skip text before line # */ @@ -200,7 +200,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); return DT_LABEL_REF; } -<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */ +<*>"&{"{PATHCHAR}*\} { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); yylval.labelref = xstrdup(yytext+2); diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 40dcf4f149da..bff1337ec266 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -23,6 +23,12 @@ extern void yyerror(char const *s); extern struct dt_info *parser_output; extern bool treesource_error; + +static bool is_ref_relative(const char *ref) +{ + return ref[0] != '/' && strchr(&ref[1], '/'); +} + %} %union { @@ -169,6 +175,8 @@ devicetree: */ if (!($<flags>-1 & DTSF_PLUGIN)) ERROR(&@2, "Label or path %s not found", $1); + else if (is_ref_relative($1)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $1); $$ = add_orphan_node( name_node(build_node(NULL, NULL, NULL), ""), @@ -178,6 +186,9 @@ devicetree: { struct node *target = get_node_by_ref($1, $3); + if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $3); + if (target) { add_label(&target->labels, $2); merge_nodes(target, $4); @@ -193,6 +204,8 @@ devicetree: * so $-1 is what we want (plugindecl) */ if ($<flags>-1 & DTSF_PLUGIN) { + if (is_ref_relative($2)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $2); add_orphan_node($1, $3, $2); } else { struct node *target = get_node_by_ref($1, $2); @@ -391,9 +404,14 @@ arrayprefix: * within the mask to one (i.e. | in the * mask), all bits are one. */ - if (($2 > mask) && (($2 | mask) != -1ULL)) - ERROR(&@2, "Value out of range for" - " %d-bit array element", $1.bits); + if (($2 > mask) && (($2 | mask) != -1ULL)) { + char *loc = srcpos_string(&@2); + fprintf(stderr, + "WARNING: %s: Value 0x%016" PRIx64 + " truncated to 0x%0*" PRIx64 "\n", + loc, $2, $1.bits / 4, ($2 & mask)); + free(loc); + } } $$.data = data_append_integer($1.data, $2, $1.bits); @@ -476,8 +494,8 @@ integer_rela: ; integer_shift: - integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; } - | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; } + integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; } + | integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; } | integer_add ; diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index bdb3f5945699..bc786c543b7e 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -12,7 +12,7 @@ * Command line options */ int quiet; /* Level of quietness */ -int reservenum; /* Number of memory reservation slots */ +unsigned int reservenum;/* Number of memory reservation slots */ int minsize; /* Minimum blob size */ int padsize; /* Additional padding to blob */ int alignsize; /* Additional padding to blob accroding to the alignsize */ @@ -122,6 +122,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback) return "dts"; if (!strcasecmp(s, ".yaml")) return "yaml"; + if (!strcasecmp(s, ".dtbo")) + return "dtb"; if (!strcasecmp(s, ".dtb")) return "dtb"; return fallback; @@ -195,7 +197,7 @@ int main(int argc, char *argv[]) depname = optarg; break; case 'R': - reservenum = strtol(optarg, NULL, 0); + reservenum = strtoul(optarg, NULL, 0); break; case 'S': minsize = strtol(optarg, NULL, 0); diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index a08f4159cd03..0a1f54991026 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -35,7 +35,7 @@ * Command line options */ extern int quiet; /* Level of quietness */ -extern int reservenum; /* Number of memory reservation slots */ +extern unsigned int reservenum; /* Number of memory reservation slots */ extern int minsize; /* Minimum blob size */ extern int padsize; /* Additional padding to blob */ extern int alignsize; /* Additional padding to blob accroding to the alignsize */ @@ -51,6 +51,11 @@ extern int annotate; /* annotate .dts with input source location */ typedef uint32_t cell_t; +static inline bool phandle_is_valid(cell_t phandle) +{ + return phandle != 0 && phandle != ~0U; +} + static inline uint16_t dtb_ld16(const void *p) { const uint8_t *bp = (const uint8_t *)p; @@ -86,6 +91,16 @@ static inline uint64_t dtb_ld64(const void *p) #define streq(a, b) (strcmp((a), (b)) == 0) #define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0) #define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0)) +static inline bool strends(const char *str, const char *suffix) +{ + unsigned int len, suffix_len; + + len = strlen(str); + suffix_len = strlen(suffix); + if (len < suffix_len) + return false; + return streq(str + len - suffix_len, suffix); +} #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) @@ -101,17 +116,23 @@ enum markertype { TYPE_UINT64, TYPE_STRING, }; + +static inline bool is_type_marker(enum markertype type) +{ + return type >= TYPE_UINT8; +} + extern const char *markername(enum markertype markertype); struct marker { enum markertype type; - int offset; + unsigned int offset; char *ref; struct marker *next; }; struct data { - int len; + unsigned int len; char *val; struct marker *markers; }; @@ -125,11 +146,26 @@ struct data { for_each_marker(m) \ if ((m)->type == (t)) -size_t type_marker_length(struct marker *m); +static inline struct marker *next_type_marker(struct marker *m) +{ + for_each_marker(m) + if (is_type_marker(m->type)) + break; + return m; +} + +static inline size_t type_marker_length(struct marker *m) +{ + struct marker *next = next_type_marker(m->next); + + if (next) + return next->offset - m->offset; + return 0; +} void data_free(struct data d); -struct data data_grow_for(struct data d, int xlen); +struct data data_grow_for(struct data d, unsigned int xlen); struct data data_copy_mem(const char *mem, int len); struct data data_copy_escape_string(const char *s, int len); @@ -253,7 +289,7 @@ void append_to_property(struct node *node, const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); cell_t propval_cell(struct property *prop); -cell_t propval_cell_n(struct property *prop, int n); +cell_t propval_cell_n(struct property *prop, unsigned int n); struct property *get_property_by_label(struct node *tree, const char *label, struct node **node); struct marker *get_marker_label(struct node *tree, const char *label, diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff index 541c432e7d19..f2bbde4bba86 100755 --- a/scripts/dtc/dtx_diff +++ b/scripts/dtc/dtx_diff @@ -29,7 +29,8 @@ Usage: -s SRCTREE linux kernel source tree is at path SRCTREE (default is current directory) -S linux kernel source tree is at root of current git repo - -T Annotate output .dts with input source file and line (-T -T for more details) + -T annotate output .dts with input source file and line + (-T -T for more details) -u unsorted, do not sort DTx @@ -58,12 +59,8 @@ Otherwise DTx is treated as a dts source file (aka .dts). or '/include/' to be processed. If DTx_1 and DTx_2 are in different architectures, then this script - may not work since \${ARCH} is part of the include path. Two possible - workarounds: - - `basename $0` \\ - <(ARCH=arch_of_dtx_1 `basename $0` DTx_1) \\ - <(ARCH=arch_of_dtx_2 `basename $0` DTx_2) + may not work since \${ARCH} is part of the include path. The following + workaround can be used: `basename $0` ARCH=arch_of_dtx_1 DTx_1 >tmp_dtx_1.dts `basename $0` ARCH=arch_of_dtx_2 DTx_2 >tmp_dtx_2.dts diff --git a/scripts/dtc/fdtdump.c b/scripts/dtc/fdtdump.c deleted file mode 100644 index 7d460a50b513..000000000000 --- a/scripts/dtc/fdtdump.c +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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/fdtoverlay.c b/scripts/dtc/fdtoverlay.c new file mode 100644 index 000000000000..5350af65679f --- /dev/null +++ b/scripts/dtc/fdtoverlay.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Konsulko Group Inc. All rights reserved. + * + * Author: + * Pantelis Antoniou <pantelis.antoniou@konsulko.com> + */ + +#include <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include <libfdt.h> + +#include "util.h" + +#define BUF_INCREMENT 65536 + +/* Usage related data. */ +static const char usage_synopsis[] = + "apply a number of overlays to a base blob\n" + " fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]\n" + "\n" + USAGE_TYPE_MSG; +static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS; +static struct option const usage_long_opts[] = { + {"input", required_argument, NULL, 'i'}, + {"output", required_argument, NULL, 'o'}, + {"verbose", no_argument, NULL, 'v'}, + USAGE_COMMON_LONG_OPTS, +}; +static const char * const usage_opts_help[] = { + "Input base DT blob", + "Output DT blob", + "Verbose messages", + USAGE_COMMON_OPTS_HELP +}; + +int verbose = 0; + +static void *apply_one(char *base, const char *overlay, size_t *buf_len, + const char *name) +{ + char *tmp = NULL; + char *tmpo; + int ret; + + /* + * We take a copies first, because a a failed apply can trash + * both the base blob and the overlay + */ + tmpo = xmalloc(fdt_totalsize(overlay)); + + do { + tmp = xrealloc(tmp, *buf_len); + ret = fdt_open_into(base, tmp, *buf_len); + if (ret) { + fprintf(stderr, + "\nFailed to make temporary copy: %s\n", + fdt_strerror(ret)); + goto fail; + } + + memcpy(tmpo, overlay, fdt_totalsize(overlay)); + + ret = fdt_overlay_apply(tmp, tmpo); + if (ret == -FDT_ERR_NOSPACE) { + *buf_len += BUF_INCREMENT; + } + } while (ret == -FDT_ERR_NOSPACE); + + if (ret) { + fprintf(stderr, "\nFailed to apply '%s': %s\n", + name, fdt_strerror(ret)); + goto fail; + } + + free(base); + free(tmpo); + return tmp; + +fail: + free(tmpo); + if (tmp) + free(tmp); + + return NULL; +} +static int do_fdtoverlay(const char *input_filename, + const char *output_filename, + int argc, char *argv[]) +{ + char *blob = NULL; + char **ovblob = NULL; + size_t buf_len; + int i, ret = -1; + + blob = utilfdt_read(input_filename, &buf_len); + if (!blob) { + fprintf(stderr, "\nFailed to read '%s'\n", input_filename); + goto out_err; + } + if (fdt_totalsize(blob) > buf_len) { + fprintf(stderr, + "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n", + (unsigned long)buf_len, fdt_totalsize(blob)); + goto out_err; + } + + /* allocate blob pointer array */ + ovblob = xmalloc(sizeof(*ovblob) * argc); + memset(ovblob, 0, sizeof(*ovblob) * argc); + + /* read and keep track of the overlay blobs */ + for (i = 0; i < argc; i++) { + size_t ov_len; + ovblob[i] = utilfdt_read(argv[i], &ov_len); + if (!ovblob[i]) { + fprintf(stderr, "\nFailed to read '%s'\n", argv[i]); + goto out_err; + } + if (fdt_totalsize(ovblob[i]) > ov_len) { + fprintf(stderr, +"\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n", + argv[i], (unsigned long)ov_len, + fdt_totalsize(ovblob[i])); + goto out_err; + } + } + + buf_len = fdt_totalsize(blob); + + /* apply the overlays in sequence */ + for (i = 0; i < argc; i++) { + blob = apply_one(blob, ovblob[i], &buf_len, argv[i]); + if (!blob) + goto out_err; + } + + fdt_pack(blob); + ret = utilfdt_write(output_filename, blob); + if (ret) + fprintf(stderr, "\nFailed to write '%s'\n", + output_filename); + +out_err: + if (ovblob) { + for (i = 0; i < argc; i++) { + if (ovblob[i]) + free(ovblob[i]); + } + free(ovblob); + } + free(blob); + + return ret; +} + +int main(int argc, char *argv[]) +{ + int opt, i; + char *input_filename = NULL; + char *output_filename = NULL; + + while ((opt = util_getopt_long()) != EOF) { + switch (opt) { + case_USAGE_COMMON_FLAGS + + case 'i': + input_filename = optarg; + break; + case 'o': + output_filename = optarg; + break; + case 'v': + verbose = 1; + break; + } + } + + if (!input_filename) + usage("missing input file"); + + if (!output_filename) + usage("missing output file"); + + argv += optind; + argc -= optind; + + if (argc <= 0) + usage("missing overlay file(s)"); + + if (verbose) { + printf("input = %s\n", input_filename); + printf("output = %s\n", output_filename); + for (i = 0; i < argc; i++) + printf("overlay[%d] = %s\n", i, argv[i]); + } + + if (do_fdtoverlay(input_filename, output_filename, argc, argv)) + return 1; + + return 0; +} diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index 07f10d2b5d79..95e43d32c3e6 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -124,7 +124,8 @@ static void asm_emit_cell(void *e, cell_t val) { FILE *f = e; - fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n", + fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n" + "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n", (val >> 24) & 0xff, (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); } @@ -134,9 +135,9 @@ static void asm_emit_string(void *e, const char *str, int len) FILE *f = e; if (len != 0) - fprintf(f, "\t.string\t\"%.*s\"\n", len, str); + fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str); else - fprintf(f, "\t.string\t\"%s\"\n", str); + fprintf(f, "\t.asciz\t\"%s\"\n", str); } static void asm_emit_align(void *e, int a) @@ -149,7 +150,7 @@ static void asm_emit_align(void *e, int a) static void asm_emit_data(void *e, struct data d) { FILE *f = e; - int off = 0; + unsigned int off = 0; struct marker *m = d.markers; for_each_marker_of_type(m, LABEL) @@ -219,7 +220,7 @@ static struct emitter asm_emitter = { static int stringtable_insert(struct data *d, const char *str) { - int i; + unsigned int i; /* FIXME: do this more efficiently? */ @@ -295,7 +296,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist, { struct reserve_info *re; struct data d = empty_data; - int j; + unsigned int j; for (re = reservelist; re; re = re->next) { d = data_append_re(d, re->address, re->size); @@ -345,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt, void dt_to_blob(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; - int i; + unsigned int i; struct data blob = empty_data; struct data reservebuf = empty_data; struct data dtbuf = empty_data; @@ -438,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) while (p < (strbuf.val + strbuf.len)) { len = strlen(p); - fprintf(f, "\t.string \"%s\"\n", p); + fprintf(f, "\t.asciz \"%s\"\n", p); p += len+1; } } @@ -446,7 +447,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) void dt_to_asm(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; - int i; + unsigned int i; struct data strbuf = empty_data; struct reserve_info *re; const char *symprefix = "dt"; diff --git a/scripts/dtc/include-prefixes/c6x b/scripts/dtc/include-prefixes/c6x deleted file mode 120000 index 49ded4cae2be..000000000000 --- a/scripts/dtc/include-prefixes/c6x +++ /dev/null @@ -1 +0,0 @@ -../../../arch/c6x/boot/dts
\ No newline at end of file diff --git a/scripts/dtc/include-prefixes/h8300 b/scripts/dtc/include-prefixes/h8300 deleted file mode 120000 index 3bdaa332c54c..000000000000 --- a/scripts/dtc/include-prefixes/h8300 +++ /dev/null @@ -1 +0,0 @@ -../../../arch/h8300/boot/dts
\ No newline at end of file diff --git a/scripts/dtc/include-prefixes/riscv b/scripts/dtc/include-prefixes/riscv new file mode 120000 index 000000000000..202509418938 --- /dev/null +++ b/scripts/dtc/include-prefixes/riscv @@ -0,0 +1 @@ +../../../arch/riscv/boot/dts
\ No newline at end of file diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index c28fcc115771..20c6415b9ced 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -22,6 +22,10 @@ int32_t fdt_ro_probe_(const void *fdt) if (can_assume(VALID_DTB)) return totalsize; + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ if (!can_assume(LATEST)) { @@ -86,6 +90,10 @@ int fdt_check_header(const void *fdt) { size_t hdrsize; + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + if (fdt_magic(fdt) != FDT_MAGIC) return -FDT_ERR_BADMAGIC; if (!can_assume(LATEST)) { @@ -98,7 +106,6 @@ int fdt_check_header(const void *fdt) } hdrsize = fdt_header_size(fdt); if (!can_assume(VALID_DTB)) { - if ((fdt_totalsize(fdt) < hdrsize) || (fdt_totalsize(fdt) > INT_MAX)) return -FDT_ERR_TRUNCATED; @@ -107,9 +114,7 @@ int fdt_check_header(const void *fdt) if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt))) return -FDT_ERR_TRUNCATED; - } - if (!can_assume(VALID_DTB)) { /* Bounds check structure block */ if (!can_assume(LATEST) && fdt_version(fdt) < 17) { if (!check_off_(hdrsize, fdt_totalsize(fdt), @@ -134,16 +139,20 @@ int fdt_check_header(const void *fdt) const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { - unsigned absoffset = offset + fdt_off_dt_struct(fdt); + unsigned int uoffset = offset; + unsigned int absoffset = offset + fdt_off_dt_struct(fdt); + + if (offset < 0) + return NULL; if (!can_assume(VALID_INPUT)) - if ((absoffset < offset) + if ((absoffset < uoffset) || ((absoffset + len) < absoffset) || (absoffset + len) > fdt_totalsize(fdt)) return NULL; if (can_assume(LATEST) || fdt_version(fdt) >= 0x11) - if (((offset + len) < offset) + if (((uoffset + len) < uoffset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; @@ -153,7 +162,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const fdt32_t *tagp, *lenp; - uint32_t tag; + uint32_t tag, len, sum; int offset = startoffset; const char *p; @@ -179,12 +188,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); if (!can_assume(VALID_DTB) && !lenp) return FDT_END; /* premature end */ + + len = fdt32_to_cpu(*lenp); + sum = len + offset; + if (!can_assume(VALID_DTB) && + (INT_MAX <= sum || sum < (uint32_t) offset)) + return FDT_END; /* premature end */ + /* skip-name offset, length and value */ - offset += sizeof(struct fdt_property) - FDT_TAGSIZE - + fdt32_to_cpu(*lenp); + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len; + if (!can_assume(LATEST) && - fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && - ((offset - fdt32_to_cpu(*lenp)) % 8) != 0) + fdt_version(fdt) < 0x10 && len >= 8 && + ((offset - len) % 8) != 0) offset += 4; break; @@ -206,10 +222,11 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) int fdt_check_node_offset_(const void *fdt, int offset) { - if (can_assume(VALID_INPUT)) - return offset; - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; + + if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE) return -FDT_ERR_BADOFFSET; return offset; @@ -217,8 +234,11 @@ int fdt_check_node_offset_(const void *fdt, int offset) int fdt_check_prop_offset_(const void *fdt, int offset) { - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; + + if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP) return -FDT_ERR_BADOFFSET; return offset; @@ -306,9 +326,12 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) int fdt_move(const void *fdt, void *buf, int bufsize) { + if (!can_assume(VALID_INPUT) && bufsize < 0) + return -FDT_ERR_NOSPACE; + FDT_RO_PROBE(fdt); - if (fdt_totalsize(fdt) > bufsize) + if (fdt_totalsize(fdt) > (unsigned int)bufsize) return -FDT_ERR_NOSPACE; memmove(buf, fdt, fdt_totalsize(fdt)); diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h index f2e68807f277..0c91aa7f67b5 100644 --- a/scripts/dtc/libfdt/fdt.h +++ b/scripts/dtc/libfdt/fdt.h @@ -35,14 +35,14 @@ struct fdt_reserve_entry { struct fdt_node_header { fdt32_t tag; - char name[0]; + char name[]; }; struct fdt_property { fdt32_t tag; fdt32_t len; fdt32_t nameoff; - char data[0]; + char data[]; }; #endif /* !__ASSEMBLY */ diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c index 9a82cd0ba2f9..c40ba094f1f8 100644 --- a/scripts/dtc/libfdt/fdt_addresses.c +++ b/scripts/dtc/libfdt/fdt_addresses.c @@ -73,7 +73,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, /* check validity of address */ prop = data; if (addr_cells == 1) { - if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size)) + if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) return -FDT_ERR_BADVALUE; fdt32_st(prop, (uint32_t)addr); diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c index b310e49a698e..5c0c3981b89d 100644 --- a/scripts/dtc/libfdt/fdt_overlay.c +++ b/scripts/dtc/libfdt/fdt_overlay.c @@ -40,37 +40,22 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) return fdt32_to_cpu(*val); } -/** - * overlay_get_target - retrieves the offset of a fragment's target - * @fdt: Base device tree blob - * @fdto: Device tree overlay blob - * @fragment: node offset of the fragment in the overlay - * @pathp: pointer which receives the path of the target (or NULL) - * - * overlay_get_target() retrieves the target offset in the base - * device tree of a fragment, no matter how the actual targeting is - * done (through a phandle or a path) - * - * returns: - * the targeted node offset in the base device tree - * Negative error code on error - */ -static int overlay_get_target(const void *fdt, const void *fdto, - int fragment, char const **pathp) +int fdt_overlay_target_offset(const void *fdt, const void *fdto, + int fragment_offset, char const **pathp) { uint32_t phandle; const char *path = NULL; int path_len = 0, ret; /* Try first to do a phandle based lookup */ - phandle = overlay_get_target_phandle(fdto, fragment); + phandle = overlay_get_target_phandle(fdto, fragment_offset); if (phandle == (uint32_t)-1) return -FDT_ERR_BADPHANDLE; /* no phandle, try path */ if (!phandle) { /* And then a path based lookup */ - path = fdt_getprop(fdto, fragment, "target-path", &path_len); + path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len); if (path) ret = fdt_path_offset(fdt, path); else @@ -241,6 +226,7 @@ static int overlay_update_local_node_references(void *fdto, if (fixup_len % sizeof(uint32_t)) return -FDT_ERR_BADOVERLAY; + fixup_len /= sizeof(uint32_t); tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); if (!tree_val) { @@ -250,7 +236,7 @@ static int overlay_update_local_node_references(void *fdto, return tree_len; } - for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { + for (i = 0; i < fixup_len; i++) { fdt32_t adj_val; uint32_t poffset; @@ -635,7 +621,7 @@ static int overlay_merge(void *fdt, void *fdto) if (overlay < 0) return overlay; - target = overlay_get_target(fdt, fdto, fragment, NULL); + target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); if (target < 0) return target; @@ -778,7 +764,7 @@ static int overlay_symbol_update(void *fdt, void *fdto) return -FDT_ERR_BADOVERLAY; /* get the target of the fragment */ - ret = overlay_get_target(fdt, fdto, fragment, &target_path); + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); if (ret < 0) return ret; target = ret; @@ -800,7 +786,7 @@ static int overlay_symbol_update(void *fdt, void *fdto) if (!target_path) { /* again in case setprop_placeholder changed it */ - ret = overlay_get_target(fdt, fdto, fragment, &target_path); + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); if (ret < 0) return ret; target = ret; diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index e03570a56eb5..9f6c551a22c2 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -53,7 +53,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) err = -FDT_ERR_BADOFFSET; absoffset = stroffset + fdt_off_dt_strings(fdt); - if (absoffset >= totalsize) + if (absoffset >= (unsigned)totalsize) goto fail; len = totalsize - absoffset; @@ -61,17 +61,19 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) if (stroffset < 0) goto fail; if (can_assume(LATEST) || fdt_version(fdt) >= 17) { - if (stroffset >= fdt_size_dt_strings(fdt)) + if ((unsigned)stroffset >= fdt_size_dt_strings(fdt)) goto fail; if ((fdt_size_dt_strings(fdt) - stroffset) < len) len = fdt_size_dt_strings(fdt) - stroffset; } } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - if ((stroffset >= 0) - || (stroffset < -fdt_size_dt_strings(fdt))) + unsigned int sw_stroffset = -stroffset; + + if ((stroffset >= 0) || + (sw_stroffset > fdt_size_dt_strings(fdt))) goto fail; - if ((-stroffset) < len) - len = -stroffset; + if (sw_stroffset < len) + len = sw_stroffset; } else { err = -FDT_ERR_INTERNAL; goto fail; @@ -157,8 +159,8 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle) static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) { - int offset = n * sizeof(struct fdt_reserve_entry); - int absoffset = fdt_off_mem_rsvmap(fdt) + offset; + unsigned int offset = n * sizeof(struct fdt_reserve_entry); + unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset; if (!can_assume(VALID_INPUT)) { if (absoffset < fdt_off_mem_rsvmap(fdt)) @@ -179,8 +181,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) if (!can_assume(VALID_INPUT) && !re) return -FDT_ERR_BADOFFSET; - *address = fdt64_ld(&re->address); - *size = fdt64_ld(&re->size); + *address = fdt64_ld_(&re->address); + *size = fdt64_ld_(&re->size); return 0; } @@ -190,7 +192,7 @@ int fdt_num_mem_rsv(const void *fdt) const struct fdt_reserve_entry *re; for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { - if (fdt64_ld(&re->size) == 0) + if (fdt64_ld_(&re->size) == 0) return i; } return -FDT_ERR_TRUNCATED; @@ -368,7 +370,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, prop = fdt_offset_ptr_(fdt, offset); if (lenp) - *lenp = fdt32_ld(&prop->len); + *lenp = fdt32_ld_(&prop->len); return prop; } @@ -406,7 +408,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, offset = -FDT_ERR_INTERNAL; break; } - if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), + if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff), name, namelen)) { if (poffset) *poffset = offset; @@ -459,7 +461,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, /* Handle realignment */ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && - (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) + (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -477,22 +479,22 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, int namelen; if (!can_assume(VALID_INPUT)) { - name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff), + name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff), &namelen); + *namep = name; if (!name) { if (lenp) *lenp = namelen; return NULL; } - *namep = name; } else { - *namep = fdt_string(fdt, fdt32_ld(&prop->nameoff)); + *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff)); } } /* Handle realignment */ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && - (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) + (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -517,7 +519,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) return 0; } - return fdt32_ld(php); + return fdt32_ld_(php); } const char *fdt_get_alias_namelen(const void *fdt, @@ -680,7 +682,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { int offset; - if ((phandle == 0) || (phandle == -1)) + if ((phandle == 0) || (phandle == ~0U)) return -FDT_ERR_BADPHANDLE; FDT_RO_PROBE(fdt); diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 93e4a2b56348..3621d3651d3f 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -59,7 +59,7 @@ static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) return -FDT_ERR_BADOFFSET; - if ((p < (char *)fdt) || (dsize + newlen < oldlen)) + if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen)) return -FDT_ERR_BADOFFSET; if (dsize - oldlen + newlen > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; @@ -349,7 +349,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, return offset; /* Try to place the new node after the parent's properties */ - fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ + tag = fdt_next_tag(fdt, parentoffset, &nextoffset); + /* the fdt_subnode_offset_namelen() should ensure this never hits */ + if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) + return -FDT_ERR_INTERNAL; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); @@ -391,7 +394,9 @@ int fdt_del_node(void *fdt, int nodeoffset) } static void fdt_packblocks_(const char *old, char *new, - int mem_rsv_size, int struct_size) + int mem_rsv_size, + int struct_size, + int strings_size) { int mem_rsv_off, struct_off, strings_off; @@ -406,8 +411,7 @@ static void fdt_packblocks_(const char *old, char *new, fdt_set_off_dt_struct(new, struct_off); fdt_set_size_dt_struct(new, struct_size); - memmove(new + strings_off, old + fdt_off_dt_strings(old), - fdt_size_dt_strings(old)); + memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); fdt_set_off_dt_strings(new, strings_off); fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } @@ -428,12 +432,14 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) if (can_assume(LATEST) || fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); - } else { + } else if (fdt_version(fdt) == 16) { struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; if (struct_size < 0) return struct_size; + } else { + return -FDT_ERR_BADVERSION; } if (can_assume(LIBFDT_ORDER) || @@ -465,7 +471,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) return -FDT_ERR_NOSPACE; } - fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size); + fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, + fdt_size_dt_strings(fdt)); memmove(buf, tmp, newsize); fdt_set_magic(buf, FDT_MAGIC); @@ -485,7 +492,8 @@ int fdt_pack(void *fdt) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); - fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); + fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), + fdt_size_dt_strings(fdt)); fdt_set_totalsize(fdt, fdt_data_size_(fdt)); return 0; diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c index 768db66eada5..d852b77e81e7 100644 --- a/scripts/dtc/libfdt/fdt_strerror.c +++ b/scripts/dtc/libfdt/fdt_strerror.c @@ -39,8 +39,9 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_NOPHANDLES), FDT_ERRTABENT(FDT_ERR_BADFLAGS), + FDT_ERRTABENT(FDT_ERR_ALIGNMENT), }; -#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) +#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) const char *fdt_strerror(int errval) { @@ -48,7 +49,7 @@ const char *fdt_strerror(int errval) return "<valid offset/length>"; else if (errval == 0) return "<no error>"; - else if (errval > -FDT_ERRTABSIZE) { + else if (-errval < FDT_ERRTABSIZE) { const char *s = fdt_errtable[-errval].str; if (s) diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c index 94ce4bb91a00..4c569ee7eb0d 100644 --- a/scripts/dtc/libfdt/fdt_sw.c +++ b/scripts/dtc/libfdt/fdt_sw.c @@ -93,8 +93,8 @@ static inline uint32_t sw_flags(void *fdt) static void *fdt_grab_space_(void *fdt, size_t len) { - int offset = fdt_size_dt_struct(fdt); - int spaceleft; + unsigned int offset = fdt_size_dt_struct(fdt); + unsigned int spaceleft; spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - fdt_size_dt_strings(fdt); @@ -108,8 +108,8 @@ static void *fdt_grab_space_(void *fdt, size_t len) int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) { - const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry)); + const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry)); void *fdt = buf; if (bufsize < hdrsize) @@ -152,6 +152,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize) FDT_SW_PROBE(fdt); + if (bufsize < 0) + return -FDT_ERR_NOSPACE; + headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); tailsize = fdt_size_dt_strings(fdt); @@ -159,7 +162,7 @@ int fdt_resize(void *fdt, void *buf, int bufsize) headsize + tailsize > fdt_totalsize(fdt)) return -FDT_ERR_INTERNAL; - if ((headsize + tailsize) > bufsize) + if ((headsize + tailsize) > (unsigned)bufsize) return -FDT_ERR_NOSPACE; oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; @@ -247,18 +250,18 @@ int fdt_end_node(void *fdt) static int fdt_add_string_(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_totalsize(fdt); - int strtabsize = fdt_size_dt_strings(fdt); - int len = strlen(s) + 1; - int struct_top, offset; + unsigned int strtabsize = fdt_size_dt_strings(fdt); + unsigned int len = strlen(s) + 1; + unsigned int struct_top, offset; - offset = -strtabsize - len; + offset = strtabsize + len; struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - if (fdt_totalsize(fdt) + offset < struct_top) + if (fdt_totalsize(fdt) - offset < struct_top) return 0; /* no more room :( */ - memcpy(strtab + offset, s, len); + memcpy(strtab - offset, s, len); fdt_set_size_dt_strings(fdt, strtabsize + len); - return offset; + return -offset; } /* Must only be used to roll back in case of error */ @@ -374,7 +377,7 @@ int fdt_finish(void *fdt) fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); /* And fix up fields that were keeping intermediate state. */ - fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION); fdt_set_magic(fdt, FDT_MAGIC); return 0; diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c index f64139e0b3dc..c2d7566a67dc 100644 --- a/scripts/dtc/libfdt/fdt_wip.c +++ b/scripts/dtc/libfdt/fdt_wip.c @@ -23,7 +23,7 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, if (!propval) return proplen; - if (proplen < (len + idx)) + if ((unsigned)proplen < (len + idx)) return -FDT_ERR_NOSPACE; memcpy((char *)propval + idx, val, len); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index fe49b5d78938..77ccff19911e 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -14,6 +14,7 @@ extern "C" { #endif #define FDT_FIRST_SUPPORTED_VERSION 0x02 +#define FDT_LAST_COMPATIBLE_VERSION 0x10 #define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ @@ -101,7 +102,11 @@ extern "C" { /* FDT_ERR_BADFLAGS: The function was passed a flags field that * contains invalid flags or an invalid combination of flags. */ -#define FDT_ERR_MAX 18 +#define FDT_ERR_ALIGNMENT 19 + /* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte + * aligned. */ + +#define FDT_ERR_MAX 19 /* constants */ #define FDT_MAX_PHANDLE 0xfffffffe @@ -122,11 +127,16 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); /* - * Alignment helpers: - * These helpers access words from a device tree blob. They're - * built to work even with unaligned pointers on platforms (ike - * ARM) that don't like unaligned loads and stores + * External helpers to access words from a device tree blob. They're built + * to work even with unaligned pointers on platforms (such as ARMv5) that don't + * like unaligned loads and stores. */ +static inline uint16_t fdt16_ld(const fdt16_t *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint16_t)bp[0] << 8) | bp[1]; +} static inline uint32_t fdt32_ld(const fdt32_t *p) { @@ -184,23 +194,23 @@ int fdt_next_node(const void *fdt, int offset, int *depth); /** * fdt_first_subnode() - get offset of first direct subnode - * * @fdt: FDT blob * @offset: Offset of node to check - * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + * + * Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none */ int fdt_first_subnode(const void *fdt, int offset); /** * fdt_next_subnode() - get offset of next direct subnode + * @fdt: FDT blob + * @offset: Offset of previous subnode * * After first calling fdt_first_subnode(), call this function repeatedly to * get direct subnodes of a parent node. * - * @fdt: FDT blob - * @offset: Offset of previous subnode - * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more - * subnodes + * Return: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more + * subnodes */ int fdt_next_subnode(const void *fdt, int offset); @@ -225,7 +235,6 @@ int fdt_next_subnode(const void *fdt, int offset); * Note that this is implemented as a macro and @node is used as * iterator in the loop. The parent variable be constant or even a * literal. - * */ #define fdt_for_each_subnode(node, fdt, parent) \ for (node = fdt_first_subnode(fdt, parent); \ @@ -269,17 +278,21 @@ fdt_set_hdr_(size_dt_struct); /** * fdt_header_size - return the size of the tree's header * @fdt: pointer to a flattened device tree + * + * Return: size of DTB header in bytes */ size_t fdt_header_size(const void *fdt); /** - * fdt_header_size_ - internal function which takes a version number + * fdt_header_size_ - internal function to get header size from a version number + * @version: devicetree version number + * + * Return: size of DTB header in bytes */ size_t fdt_header_size_(uint32_t version); /** * fdt_check_header - sanity check a device tree header - * @fdt: pointer to data which might be a flattened device tree * * fdt_check_header() checks that the given buffer contains what @@ -404,8 +417,7 @@ static inline uint32_t fdt_get_max_phandle(const void *fdt) * highest phandle value in the device tree blob) will be returned in the * @phandle parameter. * - * Returns: - * 0 on success or a negative error-code on failure + * Return: 0 on success or a negative error-code on failure */ int fdt_generate_phandle(const void *fdt, uint32_t *phandle); @@ -425,9 +437,11 @@ int fdt_num_mem_rsv(const void *fdt); /** * fdt_get_mem_rsv - retrieve one memory reserve map entry * @fdt: pointer to the device tree blob - * @address, @size: pointers to 64-bit variables + * @n: index of reserve map entry + * @address: pointer to 64-bit variable to hold the start address + * @size: pointer to 64-bit variable to hold the size of the entry * - * On success, *address and *size will contain the address and size of + * On success, @address and @size will contain the address and size of * the n-th reserve map entry from the device tree blob, in * native-endian format. * @@ -450,6 +464,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); * namelen characters of name for matching the subnode name. This is * useful for finding subnodes based on a portion of a larger string, * such as a full path. + * + * Return: offset of the subnode or -FDT_ERR_NOTFOUND if name not found. */ #ifndef SWIG /* Not available in Python */ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, @@ -489,6 +505,8 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); * * Identical to fdt_path_offset(), but only consider the first namelen * characters of path as the path name. + * + * Return: offset of the node or negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); @@ -588,9 +606,9 @@ int fdt_next_property_offset(const void *fdt, int offset); /** * fdt_for_each_property_offset - iterate over all properties of a node * - * @property_offset: property offset (int, lvalue) - * @fdt: FDT blob (const void *) - * @node: node offset (int) + * @property: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) * * This is actually a wrapper around a for loop and would be used like so: * @@ -642,6 +660,13 @@ int fdt_next_property_offset(const void *fdt, int offset); const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int offset, int *lenp); +static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt, + int offset, + int *lenp) +{ + return (struct fdt_property *)(uintptr_t) + fdt_get_property_by_offset(fdt, offset, lenp); +} /** * fdt_get_property_namelen - find a property based on substring @@ -653,6 +678,9 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, * * Identical to fdt_get_property(), but only examine the first namelen * characters of name for matching the property name. + * + * Return: pointer to the structure representing the property, or NULL + * if not found */ #ifndef SWIG /* Not available in Python */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, @@ -745,6 +773,8 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, * * Identical to fdt_getprop(), but only examine the first namelen * characters of name for matching the property name. + * + * Return: pointer to the property's value or NULL on error */ #ifndef SWIG /* Not available in Python */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, @@ -766,10 +796,10 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_getprop() retrieves a pointer to the value of the property - * named 'name' of the node at offset nodeoffset (this will be a + * named @name of the node at offset @nodeoffset (this will be a * pointer to within the device blob itself, not a copy of the value). - * If lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. + * 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 property's value @@ -814,8 +844,11 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); * @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. + * Identical to fdt_get_alias(), but only examine the first @namelen + * characters of @name for matching the alias name. + * + * Return: a pointer to the expansion of the alias named @name, if it exists, + * NULL otherwise */ #ifndef SWIG /* Not available in Python */ const char *fdt_get_alias_namelen(const void *fdt, @@ -828,7 +861,7 @@ const char *fdt_get_alias_namelen(const void *fdt, * @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. + * value of the property named @name in the node /aliases. * * returns: * a pointer to the expansion of the alias named 'name', if it exists @@ -1004,14 +1037,13 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); /** - * fdt_node_check_compatible: check a node's compatible property + * fdt_node_check_compatible - check a node's compatible property * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @compatible: string to match against * - * * fdt_node_check_compatible() returns 0 if the given node contains a - * 'compatible' property with the given string as one of its elements, + * @compatible property with the given string as one of its elements, * it returns non-zero otherwise, or on error. * * returns: @@ -1075,7 +1107,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, * one or more strings, each terminated by \0, as is found in a device tree * "compatible" property. * - * @return: 1 if the string is found in the list, 0 not found, or invalid list + * Return: 1 if the string is found in the list, 0 not found, or invalid list */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); @@ -1084,7 +1116,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list - * @return: + * + * Return: * the number of strings in the given property * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist @@ -1104,7 +1137,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); * small-valued cell properties, such as #address-cells, when searching for * the empty string. * - * @return: + * return: * the index of the string in the list of strings * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist or does not contain @@ -1128,7 +1161,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, * If non-NULL, the length of the string (on success) or a negative error-code * (on failure) will be stored in the integer pointer to by lenp. * - * @return: + * Return: * A pointer to the string at the given index in the string list or NULL on * failure. On success the length of the string will be stored in the memory * location pointed to by the lenp parameter, if non-NULL. On failure one of @@ -1217,6 +1250,8 @@ int fdt_size_cells(const void *fdt, int nodeoffset); * starting from the given index, and using only the first characters * of the name. It is useful when you want to manipulate only one value of * an array and you have a string that doesn't end with \0. + * + * Return: 0 on success, negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, @@ -1330,8 +1365,13 @@ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, /** * fdt_setprop_inplace_cell - change the value of a single-cell property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node containing the property + * @name: name of the property to change the value of + * @val: new value of the 32-bit cell * * This is an alternative name for fdt_setprop_inplace_u32() + * Return: 0 on success, negative libfdt error number otherwise. */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1403,7 +1443,7 @@ int fdt_nop_node(void *fdt, int nodeoffset); /** * fdt_create_with_flags - begin creation of a new fdt - * @fdt: pointer to memory allocated where fdt will be created + * @buf: pointer to memory allocated where fdt will be created * @bufsize: size of the memory space at fdt * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0. * @@ -1421,7 +1461,7 @@ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags); /** * fdt_create - begin creation of a new fdt - * @fdt: pointer to memory allocated where fdt will be created + * @buf: pointer to memory allocated where fdt will be created * @bufsize: size of the memory space at fdt * * fdt_create() is equivalent to fdt_create_with_flags() with flags=0. @@ -1486,7 +1526,8 @@ int fdt_pack(void *fdt); /** * fdt_add_mem_rsv - add one memory reserve map entry * @fdt: pointer to the device tree blob - * @address, @size: 64-bit values (native endian) + * @address: 64-bit start address of the reserve map entry + * @size: 64-bit size of the reserved region * * Adds a reserve map entry to the given blob reserving a region at * address address of length size. @@ -1691,8 +1732,14 @@ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, /** * fdt_setprop_cell - set a property to a single cell value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) * * This is an alternative name for fdt_setprop_u32() + * + * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1863,8 +1910,14 @@ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, /** * fdt_appendprop_cell - append a single cell value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) * * This is an alternative name for fdt_appendprop_u32() + * + * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1967,13 +2020,16 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name); * fdt_add_subnode_namelen - creates a new node based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate + * @name: name of the subnode to create * @namelen: number of characters of name to consider * - * Identical to fdt_add_subnode(), but use only the first namelen - * characters of name as the name of the new node. This is useful for + * Identical to fdt_add_subnode(), but use only the first @namelen + * characters of @name as the name of the new node. This is useful for * creating subnodes based on a portion of a larger string, such as a * full path. + * + * Return: structure block offset of the created subnode (>=0), + * negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, @@ -1992,7 +2048,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * * This function will insert data into the blob, and will therefore * change the offsets of some existing nodes. - + * * returns: * structure block offset of the created nodeequested subnode (>=0), on * success @@ -2067,6 +2123,24 @@ int fdt_del_node(void *fdt, int nodeoffset); */ int fdt_overlay_apply(void *fdt, void *fdto); +/** + * fdt_overlay_target_offset - retrieves the offset of a fragment's target + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment_offset: node offset of the fragment in the overlay + * @pathp: pointer which receives the path of the target (or NULL) + * + * fdt_overlay_target_offset() retrieves the target offset in the base + * device tree of a fragment, no matter how the actual targeting is + * done (through a phandle or a path) + * + * returns: + * the targeted node offset in the base device tree + * Negative error code on error + */ +int fdt_overlay_target_offset(const void *fdt, const void *fdto, + int fragment_offset, char const **pathp); + /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index d4e0bd49c037..16bda1906a7b 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -46,6 +46,25 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); } +/* + * Internal helpers to access tructural elements of the device tree + * blob (rather than for exaple reading integers from within property + * values). We assume that we are either given a naturally aligned + * address for the platform or if we are not, we are on a platform + * where unaligned memory reads will be handled in a graceful manner. + * If not the external helpers fdtXX_ld() from libfdt.h can be used + * instead. + */ +static inline uint32_t fdt32_ld_(const fdt32_t *p) +{ + return fdt32_to_cpu(*p); +} + +static inline uint64_t fdt64_ld_(const fdt64_t *p) +{ + return fdt64_to_cpu(*p); +} + #define FDT_SW_MAGIC (~FDT_MAGIC) /**********************************************************************/ diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 032df5878ccc..f46a098d5ada 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -438,7 +438,7 @@ cell_t propval_cell(struct property *prop) return fdt32_to_cpu(*((fdt32_t *)prop->val.val)); } -cell_t propval_cell_n(struct property *prop, int n) +cell_t propval_cell_n(struct property *prop, unsigned int n) { assert(prop->val.len / sizeof(cell_t) >= n); return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n)); @@ -526,7 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path) p = strchr(path, '/'); for_each_child(tree, child) { - if (p && strprefixeq(path, p - path, child->name)) + if (p && strprefixeq(path, (size_t)(p - path), child->name)) return get_node_by_path(child, p+1); else if (!p && streq(path, child->name)) return child; @@ -559,7 +559,7 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) { struct node *child, *node; - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { assert(generate_fixups); return NULL; } @@ -581,12 +581,39 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) struct node *get_node_by_ref(struct node *tree, const char *ref) { + struct node *target = tree; + const char *label = NULL, *path = NULL; + if (streq(ref, "/")) return tree; - else if (ref[0] == '/') - return get_node_by_path(tree, ref); + + if (ref[0] == '/') + path = ref; else - return get_node_by_label(tree, ref); + label = ref; + + if (label) { + const char *slash = strchr(label, '/'); + char *buf = NULL; + + if (slash) { + buf = xstrndup(label, slash - label); + label = buf; + path = slash + 1; + } + + target = get_node_by_label(tree, label); + + free(buf); + + if (!target) + return NULL; + } + + if (path) + target = get_node_by_path(target, path); + + return target; } cell_t get_node_phandle(struct node *root, struct node *node) @@ -594,7 +621,7 @@ cell_t get_node_phandle(struct node *root, struct node *node) static cell_t phandle = 1; /* FIXME: ick, static local */ struct data d = empty_data; - if ((node->phandle != 0) && (node->phandle != -1)) + if (phandle_is_valid(node->phandle)) return node->phandle; while (get_node_by_phandle(root, phandle)) @@ -892,6 +919,12 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn, /* m->ref can only be a REF_PHANDLE, but check anyway */ assert(m->type == REF_PHANDLE); + /* The format only permits fixups for references to label, not + * references to path */ + if (strchr(m->ref, '/')) + die("Can't generate fixup for reference to path &{%s}\n", + m->ref); + /* there shouldn't be any ':' in the arguments */ if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) die("arguments should not contain ':'\n"); diff --git a/scripts/dtc/of_unittest_expect b/scripts/dtc/of_unittest_expect new file mode 100755 index 000000000000..0a535a8e9821 --- /dev/null +++ b/scripts/dtc/of_unittest_expect @@ -0,0 +1,541 @@ +#!/usr/bin/perl +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2020, 2022 Sony Corporation +# +# Author: Frank Rowand + +# This program is meant to be an aid to reading the verbose output of +# on the console log that results from executing the Linux kernel +# devicetree unittest (drivers/of/unitest.c). + +$VUFX = "230211a"; + +use strict 'refs'; +use strict subs; + +use Getopt::Long; +use Text::Wrap; + +# strip off everything before final "/" +(undef, $script_name) = split(/^.*\//, $0); + +# following /usr/include/sysexits.h +$EX_OK=0; +$EX_USAGE=64; + + +#______________________________________________________________________________ +sub compare { + my ($expect, $got) = @_; + my $expect_next; + my $expect_next_lit; + my $got_next; + my $type; + + while ($expect) { + + ($expect_next, $type) = split(/<</, $expect); + ($type) = split(/>>/, $type); + $expect =~ s/^.*?>>//; # '?' is non-greedy, minimal match + + # literal, ignore all metacharacters when used in a regex + $expect_next_lit = quotemeta($expect_next); + + $got_next = $got; + $got_next =~ s/^($expect_next_lit).*/\1/; + $got =~ s/^$expect_next_lit//; + + if ($expect_next ne $got_next) { + return 0; + } + + if ($type eq "int") { + if ($got =~ /^[+-]*[0-9]+/) { + $got =~ s/^[+-]*[0-9]+//; + } else { + return 0; + } + } elsif ($type eq "hex") { + if ($got =~ /^(0x)*[0-9a-f]+/) { + $got =~ s/^(0x)*[0-9a-f]+//; + } else { + return 0; + } + } elsif ($type eq "all") { + return 1; + } elsif ($type eq "") { + if ($expect_next ne $got_next) { + return 0; + } else { + return 1; + } + } else { + $internal_err++; + print "** ERROR: special pattern not recognized: <<$type>>, CONSOLE_LOG line: $.\n"; + return 0; + } + + } + + # should not get here + $internal_err++; + print "** ERROR: $script_name internal error, at end of compare(), CONSOLE_LOG line: $.\n"; + + return 0; +} + + +#______________________________________________________________________________ +sub usage { + +# ***** when editing, be careful to not put tabs in the string printed: + + print STDERR +" +usage: + + $script_name CONSOLE_LOG + + -h print program usage + --help print program usage + --hide-expect suppress output of EXPECTed lines + --line-num report line number of CONSOLE_LOG + --no-expect-stats do not report EXPECT statistics + --no-strip-ts do not strip leading console timestamps + --verbose do not suppress EXPECT begin and end lines + --version print program version and exit + + + Process a console log for EXPECTed test related messages to either + highlight expected devicetree unittest related messages or suppress + the messages. Leading console timestamps will be stripped. + + Various unittests may trigger kernel messages from outside the + unittest code. The unittest annotates that it expects the message + to occur with an 'EXPECT \\ : text' (begin) before triggering the + message, and an 'EXPECT / : text' (end) after triggering the message. + + If an expected message does not occur, that will be reported. + + For each expected message, the 'EXPECT \\ : text' (begin) and + 'EXPECT / : text' (end), 'text' will contain the message text. + + If 'EXPECT \\' (begin) and 'EXPECT /' (end) lines do not contain + matching 'text', that will be reported. + + If EXPECT lines are nested, 'EXPECT /' (end) lines must be in the + reverse order of the corresponding 'EXPECT \\' (begin) lines. + + 'EXPECT \\ : text' (begin) and 'EXPECT / : text' (end) lines can + contain special patterns in 'text': + + <<int>> matches: [+-]*[0-9]+ + <<hex>> matches: (0x)*[0-9a-f]+ + <<all>> matches: anything to end of line + + 'EXPECT \\' (begin) and 'EXPECT /' (end) lines are suppressed. + + A prefix is added to every line of output: + + 'ok ' Line matches an enclosing EXPECT begin/end pair + + '** ' Line reports $script_name warning or error + + '-> ' Line reports start or end of the unittests + + '>> ' Line reports a unittest test FAIL + + ' ' Lines that are not otherwise prefixed + + Issues detected in CONSOLE_LOG are reported to STDOUT, not to STDERR. + + Known Issues: + + --line-num causes the CONSOLE_LOG line number to be printed in 4 columns. + If CONSOLE_LOG contains more than 9999 lines then more columns will be + used to report the line number for lines greater than 9999 (eg for + lines 10000 - 99999, 5 columns will be used). +"; + + return {}; +} + +#______________________________________________________________________________ +#______________________________________________________________________________ + +if (!GetOptions( + "h" => \$help, + "help" => \$help, + "hide-expect" => \$hide_expect, + "line-num" => \$print_line_num, + "no-expect-stats" => \$no_expect_stats, + "no-strip-ts" => \$no_strip_ts, + "verbose" => \$verbose, + "version" => \$version, + )) { + print STDERR "\n"; + print STDERR "ERROR processing command line options\n"; + print STDERR "\n"; + print STDERR "For help, type '$script_name --help'\n"; + print STDERR "\n"; + + exit $EX_OK; +} + + +if ($no_strip_ts) { + $strip_ts = 1; + $no_strip_ts = 0; +} else { + $strip_ts = 0; + $no_strip_ts = 1; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if ($help){ + + &usage; + + exit $EX_OK; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +if ($version) { + print STDERR "\n$script_name $VUFX\n\n"; + print STDERR "\n"; + + exit $EX_OK; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if ($#ARGV != 0) { + + # Limit input files to exactly one. + # + # 'while ($line = <ARGV>) {' in the code below supports multiple file + # names on the command line, but the EXPECT statistics are reported + # once for all input - it is not an expected use case to generate one + # set of statistics for multiple input files. + + print STDERR "\n"; + print STDERR "Required arguments: CONSOLE_LOG\n"; + print STDERR "\n"; + + exit $EX_USAGE; +} + + +#______________________________________________________________________________ + +# Patterns to match 'EXPECT \ : ' (begin) and 'EXPECT / : ' (end) +# +# $exp_* are used as regex match patterns, +# so '\\\\' in $exp_begin matches a single '\' +# quotemeta() does not do the right thing in this case +# +# $pr_fmt is the prefix that unittest prints for every message + +$pr_fmt = "### dt-test ### "; +$exp_begin = "${pr_fmt}EXPECT \\\\ : "; +$exp_end = "${pr_fmt}EXPECT / : "; +$expnot_begin = "${pr_fmt}EXPECT_NOT \\\\ : "; +$expnot_end = "${pr_fmt}EXPECT_NOT / : "; + + +$line_num = ""; +$timestamp = ""; + +LINE: +while ($line = <ARGV>) { + + chomp $line; + + $suppress_line = 0; + + $prefix = " "; ## 2 characters + + + if ($strip_ts) { + + $timestamp = $line; + + if ($timestamp =~ /^\[\s*[0-9]+\.[0-9]*\] /) { + ($timestamp, $null) = split(/]/, $line); + $timestamp = $timestamp . "] "; + + } else { + $timestamp = ""; + } + } + + $line =~ s/^\[\s*[0-9]+\.[0-9]*\] //; + + + # ----- find EXPECT begin + + if ($line =~ /^\s*$exp_begin/) { + $data = $line; + $data =~ s/^\s*$exp_begin//; + push @exp_begin_stack, $data; + + if ($verbose) { + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line; + } + + next LINE; + } + + + # ----- find EXPECT end + + if ($line =~ /^\s*$exp_end/) { + $data = $line; + $data =~ s/^\s*$exp_end//; + + if ($verbose) { + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line; + } + + $found = 0; + $no_begin = 0; + if (@exp_found_or_begin > 0) { + $begin = pop @exp_found_or_begin; + if (compare($data, $begin)) { + $found = 1; + $exp_found++; + } + } elsif (@begin > 0) { + $begin = pop @exp_begin_stack; + } else { + $no_begin = 1; + } + + if ($no_begin) { + + $exp_missing_begin++; + print "** ERROR: EXPECT end without matching EXPECT begin:\n"; + print " end ---> $line\n"; + + } elsif (! $found) { + + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + + $exp_missing++; + printf "** %s%s$script_name WARNING - not found ---> %s\n", + $line_num, $timestamp, $data; + + } elsif (! compare($data, $begin) and ($data ne $begin)) { + + $exp_missing_end++; + print "** ERROR: EXPECT end does not match EXPECT begin:\n"; + print " begin -> $begin\n"; + print " end ---> $line\n"; + + } + + next LINE; + } + + + # ----- find EXPECT_NOT begin + + if ($line =~ /^\s*$expnot_begin/) { + $data = $line; + $data =~ s/^\s*$expnot_begin//; + push @expnot_begin_stack, $data; + + if ($verbose) { + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line; + } + + next LINE; + } + + + # ----- find EXPECT_NOT end + + if ($line =~ /^\s*$expnot_end/) { + $data = $line; + $data =~ s/^\s*$expnot_end//; + + if ($verbose) { + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line; + } + + $found = 0; + $no_begin = 0; + if (@expnot_found_or_begin > 0) { + $begin = pop @expnot_found_or_begin; + if (compare($data, $begin)) { + $found = 1; + $expnot_found++; + } + } elsif (@expnot_begin_stack <= 0) { + $no_begin = 1; + } + + if ($no_begin) { + + $expnot_missing_begin++; + print "** ERROR: EXPECT_NOT end without matching EXPECT_NOT begin:\n"; + print " end ---> $line\n"; + + } + + if ($found) { + + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + + printf "** %s%s$script_name WARNING - next line matches EXPECT_NOT\n", + $line_num, $timestamp; + printf "** %s%s%s\n", $line_num, $timestamp, $line; + + } else { + + $expnot_missing++; + + } + + if (@expnot_begin_stack > 0) { + $begin = pop @expnot_begin_stack; + + if (! compare($data, $begin) and ($data ne $begin)) { + + $expnot_missing_end++; + print "** ERROR: EXPECT_NOT end does not match EXPECT_NOT begin:\n"; + print " begin -> $begin\n"; + print " end ---> $line\n"; + + } + } + + next LINE; + } + + + # ----- not an EXPECT line + + if (($line =~ /^${pr_fmt}start of unittest - you will see error messages$/) || + ($line =~ /^${pr_fmt}end of unittest - [0-9]+ passed, [0-9]+ failed$/ ) ) { + $prefix = "->"; # 2 characters + } elsif ($line =~ /^${pr_fmt}FAIL /) { + $unittest_fail++; + $prefix = ">>"; # 2 characters + } + + $found = 0; + foreach $begin (@exp_begin_stack) { + if (compare($begin, $line)) { + $found = 1; + last; + } + } + + if ($found) { + $begin = shift @exp_begin_stack; + while (! compare($begin, $line)) { + push @exp_found_or_begin, $begin; + $begin = shift @exp_begin_stack; + } + push @exp_found_or_begin, $line; + + if ($hide_expect) { + $suppress_line = 1; + } + $prefix = "ok"; # 2 characters + } + + + $found = 0; + foreach $begin (@expnot_begin_stack) { + if (compare($begin, $line)) { + $found = 1; + last; + } + } + + if ($found) { + $begin = shift @begin; + while (! compare($begin, $line)) { + push @expnot_found_or_begin, $begin; + $begin = shift @begin; + } + push @expnot_found_or_begin, $line; + + if ($hide_expect) { + $suppress_line = 1; + } + $prefix = "**"; # 2 characters + } + + + if ($suppress_line) { + next LINE; + } + + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + + printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line; +} + +if (! $no_expect_stats) { + print "\n"; + print "** EXPECT statistics:\n"; + print "**\n"; + printf "** non-zero values expected:\n"; + print "**\n"; + printf "** EXPECT found : %4i\n", $exp_found; + printf "** EXPECT_NOT not found : %4i\n", $expnot_missing; + print "**\n"; + printf "** zero values expected:\n"; + print "**\n"; + printf "** EXPECT not found : %4i\n", $exp_missing; + printf "** missing EXPECT begin : %4i\n", $exp_missing_begin; + printf "** missing EXPECT end : %4i\n", $exp_missing_end; + print "**\n"; + printf "** EXPECT_NOT found : %4i\n", $expnot_found; + printf "** missing EXPECT_NOT begin : %4i\n", $expnot_missing_begin; + printf "** missing EXPECT_NOT end : %4i\n", $expnot_missing_end; + print "**\n"; + printf "** unittest FAIL : %4i\n", $unittest_fail; + printf "** internal error : %4i\n", $internal_err; +} + +if (@exp_begin_stack) { + print "** ERROR: EXPECT begin without matching EXPECT end:\n"; + print " This list may be misleading.\n"; + foreach $begin (@exp_begin_stack) { + print " begin ---> $begin\n"; + } +} + +if (@expnot_begin_stack) { + print "** ERROR: EXPECT_NOT begin without matching EXPECT_NOT end:\n"; + print " This list may be misleading.\n"; + foreach $begin (@expnot_begin_stack) { + print " begin ---> $begin\n"; + } +} diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index f5205fb9c1ff..4fdb22a019bd 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -20,7 +20,7 @@ struct search_path { static struct search_path *search_path_head, **search_path_tail; /* Detect infinite include recursion. */ -#define MAX_SRCFILE_DEPTH (100) +#define MAX_SRCFILE_DEPTH (200) static int srcfile_depth; /* = 0 */ static char *get_dirname(const char *path) diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index 061ba8c9c5e8..33fedee82d58 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -124,27 +124,6 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) } } -static bool has_data_type_information(struct marker *m) -{ - return m->type >= TYPE_UINT8; -} - -static struct marker *next_type_marker(struct marker *m) -{ - while (m && !has_data_type_information(m)) - m = m->next; - return m; -} - -size_t type_marker_length(struct marker *m) -{ - struct marker *next = next_type_marker(m->next); - - if (next) - return next->offset - m->offset; - return 0; -} - static const char *delim_start[] = { [TYPE_UINT8] = "[", [TYPE_UINT16] = "/bits/ 16 <", @@ -229,26 +208,39 @@ static void write_propval(FILE *f, struct property *prop) size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; size_t data_len = type_marker_length(m) ? : len - m->offset; const char *p = &prop->val.val[m->offset]; + struct marker *m_phandle; - if (has_data_type_information(m)) { + if (is_type_marker(m->type)) { emit_type = m->type; fprintf(f, " %s", delim_start[emit_type]); } else if (m->type == LABEL) fprintf(f, " %s:", m->ref); - else if (m->offset) - fputc(' ', f); - if (emit_type == TYPE_NONE) { - assert(chunk_len == 0); + if (emit_type == TYPE_NONE || chunk_len == 0) continue; - } switch(emit_type) { case TYPE_UINT16: write_propval_int(f, p, chunk_len, 2); break; case TYPE_UINT32: - write_propval_int(f, p, chunk_len, 4); + m_phandle = prop->val.markers; + for_each_marker_of_type(m_phandle, REF_PHANDLE) + if (m->offset == m_phandle->offset) + break; + + if (m_phandle) { + if (m_phandle->ref[0] == '/') + fprintf(f, "&{%s}", m_phandle->ref); + else + fprintf(f, "&%s", m_phandle->ref); + if (chunk_len > 4) { + fputc(' ', f); + write_propval_int(f, p + 4, chunk_len - 4, 4); + } + } else { + write_propval_int(f, p, chunk_len, 4); + } break; case TYPE_UINT64: write_propval_int(f, p, chunk_len, 8); diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh index bc704e2a6a4a..94627541533e 100755 --- a/scripts/dtc/update-dtc-source.sh +++ b/scripts/dtc/update-dtc-source.sh @@ -32,11 +32,12 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc DTC_LINUX_PATH=`pwd`/scripts/dtc DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \ - srcpos.h treesource.c util.c util.h version_gen.h yamltree.c \ + srcpos.h treesource.c util.c util.h version_gen.h \ dtc-lexer.l dtc-parser.y" LIBFDT_SOURCE="fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \ fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \ fdt_wip.c libfdt.h libfdt_env.h libfdt_internal.h" +FDTOVERLAY_SOURCE=fdtoverlay.c get_last_dtc_version() { git log --oneline scripts/dtc/ | grep 'upstream' | head -1 | sed -e 's/^.* \(.*\)/\1/' @@ -54,7 +55,7 @@ dtc_log=$(git log --oneline ${last_dtc_ver}..) # Copy the files into the Linux tree cd $DTC_LINUX_PATH -for f in $DTC_SOURCE; do +for f in $DTC_SOURCE $FDTOVERLAY_SOURCE; do cp ${DTC_UPSTREAM_PATH}/${f} ${f} git add ${f} done diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index 40274fb79236..507f0120cd13 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -33,6 +33,17 @@ char *xstrdup(const char *s) return d; } +char *xstrndup(const char *s, size_t n) +{ + size_t len = strnlen(s, n) + 1; + char *d = xmalloc(len); + + memcpy(d, s, len - 1); + d[len - 1] = '\0'; + + return d; +} + int xavsprintf_append(char **strp, const char *fmt, va_list ap) { int n, size = 0; /* start with 128 bytes */ @@ -353,11 +364,11 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) } /* we should now have a type */ - if ((*fmt == '\0') || !strchr("iuxs", *fmt)) + if ((*fmt == '\0') || !strchr("iuxsr", *fmt)) return -1; /* convert qualifier (bhL) to byte size */ - if (*fmt != 's') + if (*fmt != 's' && *fmt != 'r') *size = qualifier == 'b' ? 1 : qualifier == 'h' ? 2 : qualifier == 'l' ? 4 : -1; diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index 5a4172dd0f84..9d38edee9736 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -2,6 +2,7 @@ #ifndef UTIL_H #define UTIL_H +#include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <getopt.h> @@ -12,10 +13,10 @@ */ #ifdef __GNUC__ -#ifdef __clang__ -#define PRINTF(i, j) __attribute__((format (printf, i, j))) -#else +#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) #define PRINTF(i, j) __attribute__((format (gnu_printf, i, j))) +#else +#define PRINTF(i, j) __attribute__((format (printf, i, j))) #endif #define NORETURN __attribute__((noreturn)) #else @@ -60,6 +61,7 @@ static inline void *xrealloc(void *p, size_t len) } extern char *xstrdup(const char *s); +extern char *xstrndup(const char *s, size_t len); extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...); extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...); @@ -142,6 +144,7 @@ int utilfdt_write_err(const char *filename, const void *blob); * i signed integer * u unsigned integer * x hex + * r raw * * TODO: Implement ll modifier (8 bytes) * TODO: Implement o type (octal) @@ -159,7 +162,7 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size); */ #define USAGE_TYPE_MSG \ - "<type>\ts=string, i=int, u=unsigned, x=hex\n" \ + "<type>\ts=string, i=int, u=unsigned, x=hex, r=raw\n" \ "\tOptional modifier prefix:\n" \ "\t\thh or b=byte, h=2 byte, l=4 byte (default)"; diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 0714799446f8..99614ec1a289 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.6.0-g9d7888cb" +#define DTC_VERSION "DTC 1.6.1-gabbd523b" diff --git a/scripts/dtc/yamltree.c b/scripts/dtc/yamltree.c index 4e93c12dc658..55908c829c98 100644 --- a/scripts/dtc/yamltree.c +++ b/scripts/dtc/yamltree.c @@ -29,11 +29,12 @@ char *yaml_error_name[] = { (emitter)->problem, __func__, __LINE__); \ }) -static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width) +static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, + char *data, unsigned int seq_offset, unsigned int len, int width) { yaml_event_t event; void *tag; - int off, start_offset = markers->offset; + unsigned int off; switch(width) { case 1: tag = "!u8"; break; @@ -66,7 +67,7 @@ static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, ch m = markers; is_phandle = false; for_each_marker_of_type(m, REF_PHANDLE) { - if (m->offset == (start_offset + off)) { + if (m->offset == (seq_offset + off)) { is_phandle = true; break; } @@ -112,8 +113,9 @@ static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len) static void yaml_propval(yaml_emitter_t *emitter, struct property *prop) { yaml_event_t event; - int len = prop->val.len; + unsigned int len = prop->val.len; struct marker *m = prop->val.markers; + struct marker *markers = prop->val.markers; /* Emit the property name */ yaml_scalar_event_initialize(&event, NULL, @@ -151,19 +153,19 @@ static void yaml_propval(yaml_emitter_t *emitter, struct property *prop) switch(m->type) { case TYPE_UINT16: - yaml_propval_int(emitter, m, data, chunk_len, 2); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2); break; case TYPE_UINT32: - yaml_propval_int(emitter, m, data, chunk_len, 4); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4); break; case TYPE_UINT64: - yaml_propval_int(emitter, m, data, chunk_len, 8); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8); break; case TYPE_STRING: yaml_propval_string(emitter, data, chunk_len); break; default: - yaml_propval_int(emitter, m, data, chunk_len, 1); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1); break; } } |