diff options
Diffstat (limited to 'scripts/dtc')
28 files changed, 1164 insertions, 307 deletions
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 4d32b9497da9..b47f4daa4515 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -3,7 +3,7 @@ # *** Also keep .gitignore in sync when changing *** hostprogs-always-$(CONFIG_DTC) += dtc fdtoverlay -hostprogs-always-$(CHECK_DT_BINDING) += dtc +hostprogs-always-$(CHECK_DTBS) += dtc dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ srcpos.o checks.o util.o @@ -16,12 +16,12 @@ libfdt = $(addprefix libfdt/,$(libfdt-objs)) fdtoverlay-objs := $(libfdt) fdtoverlay.o util.o # Source files need to get at the userspace version of libfdt_env.h to compile -HOST_EXTRACFLAGS += -I $(srctree)/$(src)/libfdt +HOST_EXTRACFLAGS += -I $(src)/libfdt HOST_EXTRACFLAGS += -DNO_YAML # Generated files need one more search path to include headers in source tree -HOSTCFLAGS_dtc-lexer.lex.o := -I $(srctree)/$(src) -HOSTCFLAGS_dtc-parser.tab.o := -I $(srctree)/$(src) +HOSTCFLAGS_dtc-lexer.lex.o := -I $(src) +HOSTCFLAGS_dtc-parser.tab.o := -I $(src) # dependencies on generated files need to be listed explicitly $(obj)/dtc-lexer.lex.o: $(obj)/dtc-parser.tab.h diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 9f31d2607182..7e3fed5005b3 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -31,7 +31,7 @@ typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node struct check { const char *name; check_fn fn; - void *data; + const void *data; bool warn, error; enum checkstatus status; bool inprogress; @@ -114,6 +114,7 @@ static inline void PRINTF(5, 6) check_msg(struct check *c, struct dt_info *dti, } fputs(str, stderr); + free(str); } #define FAIL(c, dti, node, ...) \ @@ -207,7 +208,7 @@ static void check_is_string(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; - char *propname = c->data; + const char *propname = c->data; prop = get_property(node, propname); if (!prop) @@ -226,7 +227,7 @@ static void check_is_string_list(struct check *c, struct dt_info *dti, { int rem, l; struct property *prop; - char *propname = c->data; + const char *propname = c->data; char *str; prop = get_property(node, propname); @@ -254,7 +255,7 @@ static void check_is_cell(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; - char *propname = c->data; + const char *propname = c->data; prop = get_property(node, propname); if (!prop) @@ -1023,7 +1024,7 @@ static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct no } else if (strprefixeq(node->name, node->basenamelen, "i2c")) { struct node *child; for_each_child(node, child) { - if (strprefixeq(child->name, node->basenamelen, "i2c-bus")) + if (strprefixeq(child->name, child->basenamelen, "i2c-bus")) return; } node->bus = &i2c_bus; @@ -1078,10 +1079,11 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node /* Ignore I2C_OWN_SLAVE_ADDRESS */ reg &= ~I2C_OWN_SLAVE_ADDRESS; - if ((reg & I2C_TEN_BIT_ADDRESS) && ((reg & ~I2C_TEN_BIT_ADDRESS) > 0x3ff)) - FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"", + if (reg & I2C_TEN_BIT_ADDRESS) { + if ((reg & ~I2C_TEN_BIT_ADDRESS) > 0x3ff) + FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"", reg); - else if (reg > 0x7f) + } else if (reg > 0x7f) FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\". Set I2C_TEN_BIT_ADDRESS for 10 bit addresses or fix the property", reg); } @@ -1108,7 +1110,7 @@ static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct no for_each_child(node, child) { struct property *prop; for_each_property(child, prop) { - if (strprefixeq(prop->name, 4, "spi-")) { + if (strstarts(prop->name, "spi-")) { node->bus = &spi_bus; break; } @@ -1180,7 +1182,7 @@ static void check_unit_address_format(struct check *c, struct dt_info *dti, /* skip over 0x for next test */ unitname += 2; } - if (unitname[0] == '0' && isxdigit(unitname[1])) + if (unitname[0] == '0' && isxdigit((unsigned char)unitname[1])) FAIL(c, dti, node, "unit name should not have leading 0s"); } WARNING(unit_address_format, check_unit_address_format, NULL, @@ -1215,24 +1217,27 @@ WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *dti, struct node *node) { - struct property *prop; struct node *child; - bool has_reg = false; if (!node->parent || node->addr_cells < 0 || node->size_cells < 0) return; - if (get_property(node, "ranges") || !node->children) + if (get_property(node, "ranges") || get_property(node, "dma-ranges") || !node->children) return; for_each_child(node, child) { - prop = get_property(child, "reg"); - if (prop) - has_reg = true; + /* + * Even if the child devices' address space is not mapped into + * the parent bus (no 'ranges' property on node), children can + * still have registers on a local bus, or map local addresses + * to another subordinate address space. The properties on the + * child nodes then make #address-cells/#size-cells necessary: + */ + if (get_property(child, "reg") || get_property(child, "ranges")) + return; } - if (!has_reg) - FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\" or child \"reg\" property"); + FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\", \"dma-ranges\" or child \"reg\" or \"ranges\" property"); } WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size); @@ -1465,7 +1470,7 @@ static void check_provider_cells_property(struct check *c, struct dt_info *dti, struct node *node) { - struct provider *provider = c->data; + const struct provider *provider = c->data; struct property *prop; prop = get_property(node, provider->prop_name); @@ -1671,8 +1676,16 @@ static void check_interrupt_map(struct check *c, cellprop = get_property(provider_node, "#address-cells"); if (cellprop) parent_cellsize += propval_cell(cellprop); + else + FAIL_PROP(c, dti, node, irq_map_prop, + "Missing property '#address-cells' in node %s, using 0 as fallback", + provider_node->fullpath); cell += 1 + parent_cellsize; + if (cell > map_cells) + FAIL_PROP(c, dti, node, irq_map_prop, + "property size (%d) mismatch, expected %zu", + irq_map_prop->val.len, cell * sizeof(cell_t)); } } WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider); @@ -1765,6 +1778,11 @@ static void check_graph_nodes(struct check *c, struct dt_info *dti, get_property(child, "remote-endpoint"))) continue; + /* The root node cannot be a port */ + if (!node->parent) { + FAIL(c, dti, node, "root node contains endpoint node '%s', potentially misplaced remote-endpoint property", child->name); + continue; + } node->bus = &graph_port_bus; /* The parent of 'port' nodes can be either 'ports' or a device */ @@ -1778,31 +1796,6 @@ static void check_graph_nodes(struct check *c, struct dt_info *dti, } WARNING(graph_nodes, check_graph_nodes, NULL); -static void check_graph_child_address(struct check *c, struct dt_info *dti, - struct node *node) -{ - int cnt = 0; - struct node *child; - - if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus) - return; - - for_each_child(node, child) { - struct property *prop = get_property(child, "reg"); - - /* No error if we have any non-zero unit address */ - if (prop && propval_cell(prop) != 0) - return; - - cnt++; - } - - if (cnt == 1 && node->addr_cells != -1) - FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary", - node->children->name); -} -WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes); - static void check_graph_reg(struct check *c, struct dt_info *dti, struct node *node) { @@ -1840,10 +1833,14 @@ static void check_graph_port(struct check *c, struct dt_info *dti, if (node->bus != &graph_port_bus) return; + check_graph_reg(c, dti, node); + + /* skip checks below for overlays */ + if (dti->dtsflags & DTSF_PLUGIN) + return; + if (!strprefixeq(node->name, node->basenamelen, "port")) FAIL(c, dti, node, "graph port node name should be 'port'"); - - check_graph_reg(c, dti, node); } WARNING(graph_port, check_graph_port, NULL, &graph_nodes); @@ -1878,11 +1875,15 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti, if (!node->parent || node->parent->bus != &graph_port_bus) return; + check_graph_reg(c, dti, node); + + /* skip checks below for overlays */ + if (dti->dtsflags & DTSF_PLUGIN) + return; + if (!strprefixeq(node->name, node->basenamelen, "endpoint")) FAIL(c, dti, node, "graph endpoint node name should be 'endpoint'"); - check_graph_reg(c, dti, node); - remote_node = get_remote_endpoint(c, dti, node); if (!remote_node) return; @@ -1893,6 +1894,31 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti, } WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes); +static void check_graph_child_address(struct check *c, struct dt_info *dti, + struct node *node) +{ + int cnt = 0; + struct node *child; + + if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus) + return; + + for_each_child(node, child) { + struct property *prop = get_property(child, "reg"); + + /* No error if we have any non-zero unit address */ + if (prop && propval_cell(prop) != 0 ) + return; + + cnt++; + } + + if (cnt == 1 && node->addr_cells != -1) + FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary", + node->children->name); +} +WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes, &graph_port, &graph_endpoint); + static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, &node_name_chars, &node_name_format, &property_name_chars, diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index 14734233ad8b..5b25aa060416 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -228,11 +228,7 @@ struct data data_add_marker(struct data d, enum markertype type, char *ref) { struct marker *m; - m = xmalloc(sizeof(*m)); - m->offset = d.len; - m->type = type; - m->ref = ref; - m->next = NULL; + m = alloc_marker(d.len, type, ref); return data_append_markers(d, m); } @@ -254,3 +250,44 @@ bool data_is_one_string(struct data d) return true; } + +struct data data_insert_data(struct data d, struct marker *m, struct data old) +{ + unsigned int offset = m->offset; + struct marker *next = m->next; + struct marker *marker; + struct data new_data; + char *ref; + + new_data = data_insert_at_marker(d, m, old.val, old.len); + + /* Copy all markers from old value */ + marker = old.markers; + for_each_marker(marker) { + ref = NULL; + + if (marker->ref) + ref = xstrdup(marker->ref); + + m->next = alloc_marker(marker->offset + offset, marker->type, + ref); + m = m->next; + } + m->next = next; + + return new_data; +} + +struct marker *alloc_marker(unsigned int offset, enum markertype type, + char *ref) +{ + struct marker *m; + + m = xmalloc(sizeof(*m)); + m->offset = offset; + m->type = type; + m->ref = ref; + m->next = NULL; + + return m; +} diff --git a/scripts/dtc/dt-extract-compatibles b/scripts/dtc/dt-extract-compatibles index a1119762ed08..6570efabaa64 100755 --- a/scripts/dtc/dt-extract-compatibles +++ b/scripts/dtc/dt-extract-compatibles @@ -1,17 +1,21 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0-only +import fnmatch import os -import glob import re import argparse -def parse_of_declare_macros(data): +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 - for m in re.finditer(r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)', data): + 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: @@ -22,24 +26,65 @@ def parse_of_declare_macros(data): return compat_list -def parse_of_device_id(data): +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+[a-zA-Z0-9_]+\[\]\s*=\s*({.*?);', data): - compat_list += re.findall(r'\.compatible\s+=\s+"([a-zA-Z0-9_\-,]+)"', m[1]) + 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_of_functions(data, func_name): + """ Find all compatibles in the last argument of a given function """ + compat_list = [] + for m in re.finditer(rf'{func_name}\(([a-zA-Z0-9_>\(\)"\-]+,\s)*"([a-zA-Z0-9_,-]+)"\)', data): + compat_list.append(m[2]) return compat_list -def parse_compatibles(file): +def parse_compatibles(file, compat_ignore_list): with open(file, 'r', encoding='utf-8') as f: data = f.read().replace('\n', '') - compat_list = parse_of_declare_macros(data) - compat_list += parse_of_device_id(data) + 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) + compat_list += parse_of_functions(data, "_is_compatible") + compat_list += parse_of_functions(data, "of_find_compatible_node") + compat_list += parse_of_functions(data, "for_each_compatible_node") + compat_list += parse_of_functions(data, "of_get_compatible_child") 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 @@ -49,21 +94,41 @@ def print_compat(filename, compatibles): 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 - for f in args.cfile: - if os.path.isdir(f): - for filename in glob.iglob(f + "/**/*.c", recursive=True): - compat_list = parse_compatibles(filename) - print_compat(filename, compat_list) - else: - compat_list = parse_compatibles(f) - print_compat(f, compat_list) + 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/dt_to_config b/scripts/dtc/dt_to_config index 299d1c2b20d7..70d6d5f06bdc 100755 --- a/scripts/dtc/dt_to_config +++ b/scripts/dtc/dt_to_config @@ -51,10 +51,10 @@ $num_pr_flags = $pr_flag_pos_config_test_fail + 1; "compatible is white listed", "matching driver and/or kernel config is hard coded", "kernel config hard coded in Makefile", - "one or more kernel config file options is not set", - "one or more kernel config file options is set to 'm'", - "one or more kernel config file options is set to 'y'", - "one of more kernel config file options fails to have correct value" + "one or more kernel config file options are not set", + "one or more kernel config file options are set to 'm'", + "one or more kernel config file options are set to 'y'", + "one or more kernel config file options fail to have correct value" ); diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index de60a70b6bdb..15d585c80798 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -151,6 +151,21 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); return DT_LABEL; } +<V1>{LABEL} { + /* Missed includes or macro definitions while + * preprocessing can lead to unexpected identifiers in + * the input. Report a slightly more informative error + * in this case */ + + lexical_error("Unexpected '%s'", yytext); + + /* Treat it as a literal which often generates further + * useful error messages */ + + yylval.integer = 0; + return DT_LITERAL; + } + <V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? { char *e; DPRINT("Integer Literal: '%s'\n", yytext); diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 46457d4bc0aa..4d5eece52624 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -284,14 +284,17 @@ propdef: DT_PROPNODENAME '=' propdata ';' { $$ = build_property($1, $3, &@$); + free($1); } | DT_PROPNODENAME ';' { $$ = build_property($1, empty_data, &@$); + free($1); } | DT_DEL_PROP DT_PROPNODENAME ';' { $$ = build_property_delete($2); + free($2); } | DT_LABEL propdef { @@ -404,9 +407,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); @@ -565,10 +573,12 @@ subnode: DT_PROPNODENAME nodedef { $$ = name_node($2, $1); + free($1); } | DT_DEL_NODE DT_PROPNODENAME ';' { $$ = name_node(build_node_delete(&@$), $2); + free($2); } | DT_OMIT_NO_REF subnode { diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index bc786c543b7e..b3445b7d6473 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -15,7 +15,7 @@ int quiet; /* Level of quietness */ 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 */ +int alignsize; /* Additional padding to blob according to the alignsize */ int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties */ int generate_symbols; /* enable symbols & fixup support */ int generate_fixups; /* suppress generation of fixups on symbol support */ @@ -47,7 +47,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix) /* Usage related data. */ static const char usage_synopsis[] = "dtc [options] <input file>"; -static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv"; +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@LAThv"; static struct option const usage_long_opts[] = { {"quiet", no_argument, NULL, 'q'}, {"in-format", a_argument, NULL, 'I'}, @@ -67,6 +67,7 @@ static struct option const usage_long_opts[] = { {"warning", a_argument, NULL, 'W'}, {"error", a_argument, NULL, 'E'}, {"symbols", no_argument, NULL, '@'}, + {"local-fixups", no_argument, NULL, 'L'}, {"auto-alias", no_argument, NULL, 'A'}, {"annotate", no_argument, NULL, 'T'}, {"help", no_argument, NULL, 'h'}, @@ -104,6 +105,7 @@ static const char * const usage_opts_help[] = { "\n\tEnable/disable warnings (prefix with \"no-\")", "\n\tEnable/disable errors (prefix with \"no-\")", "\n\tEnable generation of symbols", + "\n\tPossibly generates a __local_fixups__ and a __fixups__ node at the root node", "\n\tEnable auto-alias of labels", "\n\tAnnotate output .dts with input source file and line (-T -T for more details)", "\n\tPrint this help and exit", @@ -252,6 +254,11 @@ int main(int argc, char *argv[]) case '@': generate_symbols = 1; break; + + case 'L': + generate_fixups = 1; + break; + case 'A': auto_label_aliases = 1; break; @@ -282,7 +289,9 @@ int main(int argc, char *argv[]) if (!depfile) die("Couldn't open dependency file %s: %s\n", depname, strerror(errno)); - fprintf(depfile, "%s:", outname); + + fprint_path_escaped(depfile, outname); + fputc(':', depfile); } if (inform == NULL) diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 0a1f54991026..3a220b9afc99 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -38,7 +38,7 @@ extern int quiet; /* Level of quietness */ 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 */ +extern int alignsize; /* Additional padding to blob according to the alignsize */ extern int phandle_format; /* Use linux,phandle or phandle properties */ extern int generate_symbols; /* generate symbols for nodes with labels */ extern int generate_fixups; /* generate fixups */ @@ -182,7 +182,10 @@ struct data data_append_addr(struct data d, uint64_t addr); struct data data_append_byte(struct data d, uint8_t byte); struct data data_append_zeroes(struct data d, int len); struct data data_append_align(struct data d, int align); +struct data data_insert_data(struct data d, struct marker *m, struct data old); +struct marker *alloc_marker(unsigned int offset, enum markertype type, + char *ref); struct data data_add_marker(struct data d, enum markertype type, char *ref); bool data_is_one_string(struct data d); @@ -260,16 +263,16 @@ struct node { void add_label(struct label **labels, char *label); void delete_labels(struct label **labels); -struct property *build_property(char *name, struct data val, +struct property *build_property(const char *name, struct data val, struct srcpos *srcpos); -struct property *build_property_delete(char *name); +struct property *build_property_delete(const char *name); struct property *chain_property(struct property *first, struct property *list); struct property *reverse_properties(struct property *first); struct node *build_node(struct property *proplist, struct node *children, struct srcpos *srcpos); struct node *build_node_delete(struct srcpos *srcpos); -struct node *name_node(struct node *node, char *name); +struct node *name_node(struct node *node, const char *name); struct node *omit_node_if_unused(struct node *node); struct node *reference_node(struct node *node); struct node *chain_node(struct node *first, struct node *list); @@ -336,9 +339,9 @@ struct dt_info *build_dt_info(unsigned int dtsflags, struct reserve_info *reservelist, struct node *tree, uint32_t boot_cpuid_phys); void sort_tree(struct dt_info *dti); -void generate_label_tree(struct dt_info *dti, char *name, bool allocph); -void generate_fixups_tree(struct dt_info *dti, char *name); -void generate_local_fixups_tree(struct dt_info *dti, char *name); +void generate_label_tree(struct dt_info *dti, const char *name, bool allocph); +void generate_fixups_tree(struct dt_info *dti, const char *name); +void generate_local_fixups_tree(struct dt_info *dti, const char *name); /* Checks */ diff --git a/scripts/dtc/fdtoverlay.c b/scripts/dtc/fdtoverlay.c index 5350af65679f..ee1eb8f3ad28 100644 --- a/scripts/dtc/fdtoverlay.c +++ b/scripts/dtc/fdtoverlay.c @@ -23,9 +23,7 @@ /* 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; + " fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]"; 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'}, @@ -48,9 +46,10 @@ static void *apply_one(char *base, const char *overlay, size_t *buf_len, char *tmp = NULL; char *tmpo; int ret; + bool has_symbols; /* - * We take a copies first, because a a failed apply can trash + * We take copies first, because a failed apply can trash * both the base blob and the overlay */ tmpo = xmalloc(fdt_totalsize(overlay)); @@ -64,6 +63,8 @@ static void *apply_one(char *base, const char *overlay, size_t *buf_len, fdt_strerror(ret)); goto fail; } + ret = fdt_path_offset(tmp, "/__symbols__"); + has_symbols = ret >= 0; memcpy(tmpo, overlay, fdt_totalsize(overlay)); @@ -76,6 +77,11 @@ static void *apply_one(char *base, const char *overlay, size_t *buf_len, if (ret) { fprintf(stderr, "\nFailed to apply '%s': %s\n", name, fdt_strerror(ret)); + if (!has_symbols) { + fprintf(stderr, + "base blob does not have a '/__symbols__' node, " + "make sure you have compiled the base blob with '-@' option\n"); + } goto fail; } diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index 95e43d32c3e6..30e6de2044b2 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -503,7 +503,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version) * Reserve map entries. * Align the reserve map to a doubleword boundary. * Each entry is an (address, size) pair of u64 values. - * Always supply a zero-sized temination entry. + * Always supply a zero-sized termination entry. */ asm_emit_align(f, 8); emit_label(f, symprefix, "reserve_map"); @@ -604,11 +604,11 @@ static void flat_realign(struct inbuf *inb, int align) die("Premature end of data parsing flat device tree\n"); } -static char *flat_read_string(struct inbuf *inb) +static const char *flat_read_string(struct inbuf *inb) { int len = 0; const char *p = inb->ptr; - char *str; + const char *str; do { if (p >= inb->limit) @@ -616,7 +616,7 @@ static char *flat_read_string(struct inbuf *inb) len++; } while ((*p++) != '\0'); - str = xstrdup(inb->ptr); + str = inb->ptr; inb->ptr += len; @@ -711,7 +711,7 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) } -static char *nodename_from_path(const char *ppath, const char *cpath) +static const char *nodename_from_path(const char *ppath, const char *cpath) { int plen; @@ -725,7 +725,7 @@ static char *nodename_from_path(const char *ppath, const char *cpath) if (!streq(ppath, "/")) plen++; - return xstrdup(cpath + plen); + return cpath + plen; } static struct node *unflatten_tree(struct inbuf *dtbuf, @@ -733,7 +733,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, const char *parent_flatname, int flags) { struct node *node; - char *flatname; + const char *flatname; uint32_t val; node = build_node(NULL, NULL, NULL); @@ -741,9 +741,10 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, flatname = flat_read_string(dtbuf); if (flags & FTF_FULLPATH) - node->name = nodename_from_path(parent_flatname, flatname); + node->name = xstrdup(nodename_from_path(parent_flatname, + flatname)); else - node->name = flatname; + node->name = xstrdup(flatname); do { struct property *prop; @@ -785,10 +786,6 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, } } while (val != FDT_END_NODE); - if (node->name != flatname) { - free(flatname); - } - return node; } diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c index 5e59594ab301..0f9a534bacdb 100644 --- a/scripts/dtc/fstree.c +++ b/scripts/dtc/fstree.c @@ -43,7 +43,7 @@ static struct node *read_fstree(const char *dirname) "WARNING: Cannot open %s: %s\n", tmpname, strerror(errno)); } else { - prop = build_property(xstrdup(de->d_name), + prop = build_property(de->d_name, data_copy_file(pfile, st.st_size), NULL); 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 20c6415b9ced..95f644c31f94 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -312,14 +312,14 @@ int fdt_next_subnode(const void *fdt, int offset) return offset; } -const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) +const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s, + int slen) { - int len = strlen(s) + 1; - const char *last = strtab + tabsize - len; + const char *last = strtab + tabsize - (slen + 1); const char *p; for (p = strtab; p <= last; p++) - if (memcmp(p, s, len) == 0) + if (memcmp(p, s, slen) == 0 && p[slen] == '\0') return p; return NULL; } diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h index f2e68807f277..a07abfcc7108 100644 --- a/scripts/dtc/libfdt/fdt.h +++ b/scripts/dtc/libfdt/fdt.h @@ -7,7 +7,7 @@ * Copyright 2012 Kim Phillips, Freescale Semiconductor. */ -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct fdt_header { fdt32_t magic; /* magic word FDT_MAGIC */ @@ -35,17 +35,17 @@ 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 */ +#endif /* !__ASSEMBLER__ */ #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ #define FDT_TAGSIZE sizeof(fdt32_t) diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c index 5c0c3981b89d..e6b9eb643958 100644 --- a/scripts/dtc/libfdt/fdt_overlay.c +++ b/scripts/dtc/libfdt/fdt_overlay.c @@ -101,26 +101,22 @@ int fdt_overlay_target_offset(const void *fdt, const void *fdto, static int overlay_phandle_add_offset(void *fdt, int node, const char *name, uint32_t delta) { - const fdt32_t *val; - uint32_t adj_val; + fdt32_t *valp, val; int len; - val = fdt_getprop(fdt, node, name, &len); - if (!val) + valp = fdt_getprop_w(fdt, node, name, &len); + if (!valp) return len; - if (len != sizeof(*val)) + if (len != sizeof(val)) return -FDT_ERR_BADPHANDLE; - adj_val = fdt32_to_cpu(*val); - if ((adj_val + delta) < adj_val) - return -FDT_ERR_NOPHANDLES; - - adj_val += delta; - if (adj_val == (uint32_t)-1) + val = fdt32_ld(valp); + if (val + delta < val || val + delta == (uint32_t)-1) return -FDT_ERR_NOPHANDLES; - return fdt_setprop_inplace_u32(fdt, node, name, adj_val); + fdt32_st(valp, val + delta); + return 0; } /** @@ -213,8 +209,8 @@ static int overlay_update_local_node_references(void *fdto, fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { const fdt32_t *fixup_val; - const char *tree_val; const char *name; + char *tree_val; int fixup_len; int tree_len; int i; @@ -228,7 +224,7 @@ static int overlay_update_local_node_references(void *fdto, return -FDT_ERR_BADOVERLAY; fixup_len /= sizeof(uint32_t); - tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); + tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len); if (!tree_val) { if (tree_len == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; @@ -237,33 +233,15 @@ static int overlay_update_local_node_references(void *fdto, } for (i = 0; i < fixup_len; i++) { - fdt32_t adj_val; - uint32_t poffset; + fdt32_t *refp; - poffset = fdt32_to_cpu(fixup_val[i]); + refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i)); /* - * phandles to fixup can be unaligned. - * - * Use a memcpy for the architectures that do - * not support unaligned accesses. + * phandles to fixup can be unaligned, so use + * fdt32_{ld,st}() to read/write them. */ - memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); - - adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); - - ret = fdt_setprop_inplace_namelen_partial(fdto, - tree_node, - name, - strlen(name), - poffset, - &adj_val, - sizeof(adj_val)); - if (ret == -FDT_ERR_NOSPACE) - return -FDT_ERR_BADOVERLAY; - - if (ret) - return ret; + fdt32_st(refp, fdt32_ld(refp) + delta); } } @@ -329,7 +307,6 @@ static int overlay_update_local_references(void *fdto, uint32_t delta) /** * overlay_fixup_one_phandle - Set an overlay phandle to the base one - * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * @symbols_off: Node offset of the symbols node in the base device tree * @path: Path to a node holding a phandle in the overlay @@ -337,7 +314,7 @@ static int overlay_update_local_references(void *fdto, uint32_t delta) * @name: Name of the property holding the phandle reference in the overlay * @name_len: number of name characters to consider * @poffset: Offset within the overlay property where the phandle is stored - * @label: Label of the node referenced by the phandle + * @phandle: Phandle referencing the node * * overlay_fixup_one_phandle() resolves an overlay phandle pointing to * a node in the base device tree. @@ -350,34 +327,17 @@ static int overlay_update_local_references(void *fdto, uint32_t delta) * 0 on success * Negative error code on failure */ -static int overlay_fixup_one_phandle(void *fdt, void *fdto, - int symbols_off, +static int overlay_fixup_one_phandle(void *fdto, int symbols_off, const char *path, uint32_t path_len, const char *name, uint32_t name_len, - int poffset, const char *label) + int poffset, uint32_t phandle) { - const char *symbol_path; - uint32_t phandle; fdt32_t phandle_prop; - int symbol_off, fixup_off; - int prop_len; + int fixup_off; if (symbols_off < 0) return symbols_off; - symbol_path = fdt_getprop(fdt, symbols_off, label, - &prop_len); - if (!symbol_path) - return prop_len; - - symbol_off = fdt_path_offset(fdt, symbol_path); - if (symbol_off < 0) - return symbol_off; - - phandle = fdt_get_phandle(fdt, symbol_off); - if (!phandle) - return -FDT_ERR_NOTFOUND; - fixup_off = fdt_path_offset_namelen(fdto, path, path_len); if (fixup_off == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; @@ -389,7 +349,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, name, name_len, poffset, &phandle_prop, sizeof(phandle_prop)); -}; +} /** * overlay_fixup_phandle - Set an overlay phandle to the base one @@ -416,6 +376,10 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, const char *value; const char *label; int len; + const char *symbol_path; + int prop_len; + int symbol_off; + uint32_t phandle; value = fdt_getprop_by_offset(fdto, property, &label, &len); @@ -426,6 +390,18 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, return len; } + symbol_path = fdt_getprop(fdt, symbols_off, label, &prop_len); + if (!symbol_path) + return prop_len; + + symbol_off = fdt_path_offset(fdt, symbol_path); + if (symbol_off < 0) + return symbol_off; + + phandle = fdt_get_phandle(fdt, symbol_off); + if (!phandle) + return -FDT_ERR_NOTFOUND; + do { const char *path, *name, *fixup_end; const char *fixup_str = value; @@ -465,9 +441,9 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, if ((*endptr != '\0') || (endptr <= (sep + 1))) return -FDT_ERR_BADOVERLAY; - ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, + ret = overlay_fixup_one_phandle(fdto, symbols_off, path, path_len, name, name_len, - poffset, label); + poffset, phandle); if (ret) return ret; } while (len > 0); @@ -521,6 +497,255 @@ static int overlay_fixup_phandles(void *fdt, void *fdto) } /** + * overlay_adjust_local_conflicting_phandle: Changes a phandle value + * @fdto: Device tree overlay + * @node: The node the phandle is set for + * @fdt_phandle: The new value for the phandle + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_local_conflicting_phandle(void *fdto, int node, + uint32_t fdt_phandle) +{ + const fdt32_t *php; + int len, ret; + + php = fdt_getprop(fdto, node, "phandle", &len); + if (php && len == sizeof(*php)) { + ret = fdt_setprop_inplace_u32(fdto, node, "phandle", fdt_phandle); + if (ret) + return ret; + } + + php = fdt_getprop(fdto, node, "linux,phandle", &len); + if (php && len == sizeof(*php)) { + ret = fdt_setprop_inplace_u32(fdto, node, "linux,phandle", fdt_phandle); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_update_node_conflicting_references - Recursively replace phandle values + * @fdto: Device tree overlay blob + * @tree_node: Node to recurse into + * @fixup_node: Node offset of the matching local fixups node + * @fdt_phandle: Value to replace phandles with + * @fdto_phandle: Value to be replaced + * + * Replaces all phandles with value @fdto_phandle by @fdt_phandle. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_node_conflicting_references(void *fdto, int tree_node, + int fixup_node, + uint32_t fdt_phandle, + uint32_t fdto_phandle) +{ + int fixup_prop; + int fixup_child; + int ret; + + fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { + const fdt32_t *fixup_val; + const char *name; + char *tree_val; + int fixup_len; + int tree_len; + int i; + + fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, + &name, &fixup_len); + if (!fixup_val) + return fixup_len; + + if (fixup_len % sizeof(uint32_t)) + return -FDT_ERR_BADOVERLAY; + fixup_len /= sizeof(uint32_t); + + tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len); + if (!tree_val) { + if (tree_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + + return tree_len; + } + + for (i = 0; i < fixup_len; i++) { + fdt32_t *refp; + uint32_t valp; + + refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i)); + valp = fdt32_ld(refp); + + if (valp == fdto_phandle) + fdt32_st(refp, fdt_phandle); + } + } + + fdt_for_each_subnode(fixup_child, fdto, fixup_node) { + const char *fixup_child_name = fdt_get_name(fdto, fixup_child, NULL); + int tree_child; + + tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name); + + if (tree_child == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (tree_child < 0) + return tree_child; + + ret = overlay_update_node_conflicting_references(fdto, tree_child, + fixup_child, + fdt_phandle, + fdto_phandle); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_update_local_conflicting_references - Recursively replace phandle values + * @fdto: Device tree overlay blob + * @fdt_phandle: Value to replace phandles with + * @fdto_phandle: Value to be replaced + * + * Replaces all phandles with value @fdto_phandle by @fdt_phandle. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_conflicting_references(void *fdto, + uint32_t fdt_phandle, + uint32_t fdto_phandle) +{ + int fixups; + + fixups = fdt_path_offset(fdto, "/__local_fixups__"); + if (fixups == -FDT_ERR_NOTFOUND) + return 0; + if (fixups < 0) + return fixups; + + return overlay_update_node_conflicting_references(fdto, 0, fixups, + fdt_phandle, + fdto_phandle); +} + +/** + * overlay_prevent_phandle_overwrite_node - Helper function for overlay_prevent_phandle_overwrite + * @fdt: Base Device tree blob + * @fdtnode: Node in fdt that is checked for an overwrite + * @fdto: Device tree overlay blob + * @fdtonode: Node in fdto matching @fdtnode + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_prevent_phandle_overwrite_node(void *fdt, int fdtnode, + void *fdto, int fdtonode) +{ + uint32_t fdt_phandle, fdto_phandle; + int fdtochild; + + fdt_phandle = fdt_get_phandle(fdt, fdtnode); + fdto_phandle = fdt_get_phandle(fdto, fdtonode); + + if (fdt_phandle && fdto_phandle) { + int ret; + + ret = overlay_adjust_local_conflicting_phandle(fdto, fdtonode, + fdt_phandle); + if (ret) + return ret; + + ret = overlay_update_local_conflicting_references(fdto, + fdt_phandle, + fdto_phandle); + if (ret) + return ret; + } + + fdt_for_each_subnode(fdtochild, fdto, fdtonode) { + const char *name = fdt_get_name(fdto, fdtochild, NULL); + int fdtchild; + int ret; + + fdtchild = fdt_subnode_offset(fdt, fdtnode, name); + if (fdtchild == -FDT_ERR_NOTFOUND) + /* + * no further overwrites possible here as this node is + * new + */ + continue; + + ret = overlay_prevent_phandle_overwrite_node(fdt, fdtchild, + fdto, fdtochild); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_prevent_phandle_overwrite - Fixes overlay phandles to not overwrite base phandles + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * Checks recursively if applying fdto overwrites phandle values in the base + * dtb. When such a phandle is found, the fdto is changed to use the fdt's + * phandle value to not break references in the base. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_prevent_phandle_overwrite(void *fdt, void *fdto) +{ + int fragment; + + fdt_for_each_subnode(fragment, fdto, 0) { + int overlay; + int target; + int ret; + + overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (overlay == -FDT_ERR_NOTFOUND) + continue; + + if (overlay < 0) + return overlay; + + target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); + if (target == -FDT_ERR_NOTFOUND) + /* + * The subtree doesn't exist in the base, so nothing + * will be overwritten. + */ + continue; + else if (target < 0) + return target; + + ret = overlay_prevent_phandle_overwrite_node(fdt, target, + fdto, overlay); + if (ret) + return ret; + } + + return 0; +} + +/** * overlay_apply_node - Merges a node into the base device tree * @fdt: Base Device Tree blob * @target: Node offset in the base device tree to apply the fragment to @@ -824,18 +1049,26 @@ int fdt_overlay_apply(void *fdt, void *fdto) if (ret) goto err; + /* Increase all phandles in the fdto by delta */ ret = overlay_adjust_local_phandles(fdto, delta); if (ret) goto err; + /* Adapt the phandle values in fdto to the above increase */ ret = overlay_update_local_references(fdto, delta); if (ret) goto err; + /* Update fdto's phandles using symbols from fdt */ ret = overlay_fixup_phandles(fdt, fdto); if (ret) goto err; + /* Don't overwrite phandles in fdt */ + ret = overlay_prevent_phandle_overwrite(fdt, fdto); + if (ret) + goto err; + ret = overlay_merge(fdt, fdto); if (ret) goto err; diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 9f6c551a22c2..b78c4e48f1cb 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -255,6 +255,9 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) FDT_RO_PROBE(fdt); + if (!can_assume(VALID_INPUT) && namelen <= 0) + return -FDT_ERR_BADPATH; + /* see if we have an alias */ if (*path != '/') { const char *q = memchr(path, '/', end - p); @@ -522,16 +525,31 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) return fdt32_ld_(php); } +static const void *fdt_path_getprop_namelen(const void *fdt, const char *path, + const char *propname, int propnamelen, + int *lenp) +{ + int offset = fdt_path_offset(fdt, path); + + if (offset < 0) + return NULL; + + return fdt_getprop_namelen(fdt, offset, propname, propnamelen, lenp); +} + const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen) { - int aliasoffset; + int len; + const char *alias; - aliasoffset = fdt_path_offset(fdt, "/aliases"); - if (aliasoffset < 0) + alias = fdt_path_getprop_namelen(fdt, "/aliases", name, namelen, &len); + + if (!can_assume(VALID_DTB) && + !(alias && len > 0 && alias[len - 1] == '\0' && *alias == '/')) return NULL; - return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); + return alias; } const char *fdt_get_alias(const void *fdt, const char *name) @@ -539,6 +557,17 @@ const char *fdt_get_alias(const void *fdt, const char *name) return fdt_get_alias_namelen(fdt, name, strlen(name)); } +const char *fdt_get_symbol_namelen(const void *fdt, + const char *name, int namelen) +{ + return fdt_path_getprop_namelen(fdt, "/__symbols__", name, namelen, NULL); +} + +const char *fdt_get_symbol(const void *fdt, const char *name) +{ + return fdt_get_symbol_namelen(fdt, name, strlen(name)); +} + int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { int pdepth = 0, p = 0; diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 3621d3651d3f..7475cafce071 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -124,31 +124,33 @@ static int fdt_splice_string_(void *fdt, int newlen) * allocated. Ignored if can_assume(NO_ROLLBACK) * @return offset of string in the string table (whether found or added) */ -static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) +static int fdt_find_add_string_(void *fdt, const char *s, int slen, + int *allocated) { char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); const char *p; char *new; - int len = strlen(s) + 1; int err; if (!can_assume(NO_ROLLBACK)) *allocated = 0; - p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); + p = fdt_find_string_len_(strtab, fdt_size_dt_strings(fdt), s, slen); if (p) /* found it */ return (p - strtab); new = strtab + fdt_size_dt_strings(fdt); - err = fdt_splice_string_(fdt, len); + err = fdt_splice_string_(fdt, slen + 1); if (err) return err; if (!can_assume(NO_ROLLBACK)) *allocated = 1; - memcpy(new, s, len); + memcpy(new, s, slen); + new[slen] = '\0'; + return (new - strtab); } @@ -181,13 +183,15 @@ int fdt_del_mem_rsv(void *fdt, int n) return fdt_splice_mem_rsv_(fdt, re, 1, 0); } -static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, +static int fdt_resize_property_(void *fdt, int nodeoffset, + const char *name, int namelen, int len, struct fdt_property **prop) { int oldlen; int err; - *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + *prop = fdt_get_property_namelen_w(fdt, nodeoffset, name, namelen, + &oldlen); if (!*prop) return oldlen; @@ -200,7 +204,7 @@ static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, } static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) + int namelen, int len, struct fdt_property **prop) { int proplen; int nextoffset; @@ -211,7 +215,7 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) return nextoffset; - namestroff = fdt_find_add_string_(fdt, name, &allocated); + namestroff = fdt_find_add_string_(fdt, name, namelen, &allocated); if (namestroff < 0) return namestroff; @@ -255,17 +259,18 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) return 0; } -int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, - int len, void **prop_data) +int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name, + int namelen, int len, void **prop_data) { struct fdt_property *prop; int err; FDT_RW_PROBE(fdt); - err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); + err = fdt_resize_property_(fdt, nodeoffset, name, namelen, len, &prop); if (err == -FDT_ERR_NOTFOUND) - err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + err = fdt_add_property_(fdt, nodeoffset, name, namelen, len, + &prop); if (err) return err; @@ -273,13 +278,14 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, return 0; } -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len) +int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name, + int namelen, const void *val, int len) { void *prop_data; int err; - err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); + err = fdt_setprop_placeholder_namelen(fdt, nodeoffset, name, namelen, + len, &prop_data); if (err) return err; @@ -307,7 +313,8 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, prop->len = cpu_to_fdt32(newlen); memcpy(prop->data + oldlen, val, len); } else { - err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); + err = fdt_add_property_(fdt, nodeoffset, name, strlen(name), + len, &prop); if (err) return err; memcpy(prop->data, val, len); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index 77ccff19911e..914bf90785ab 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -14,7 +14,7 @@ extern "C" { #endif #define FDT_FIRST_SUPPORTED_VERSION 0x02 -#define FDT_LAST_COMPATIBLE_VERSION 0x10 +#define FDT_LAST_COMPATIBLE_VERSION 0x10 #define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ @@ -263,16 +263,16 @@ int fdt_next_subnode(const void *fdt, int offset); struct fdt_header *fdth = (struct fdt_header *)fdt; \ fdth->name = cpu_to_fdt32(val); \ } -fdt_set_hdr_(magic); -fdt_set_hdr_(totalsize); -fdt_set_hdr_(off_dt_struct); -fdt_set_hdr_(off_dt_strings); -fdt_set_hdr_(off_mem_rsvmap); -fdt_set_hdr_(version); -fdt_set_hdr_(last_comp_version); -fdt_set_hdr_(boot_cpuid_phys); -fdt_set_hdr_(size_dt_strings); -fdt_set_hdr_(size_dt_struct); +fdt_set_hdr_(magic) +fdt_set_hdr_(totalsize) +fdt_set_hdr_(off_dt_struct) +fdt_set_hdr_(off_dt_strings) +fdt_set_hdr_(off_mem_rsvmap) +fdt_set_hdr_(version) +fdt_set_hdr_(last_comp_version) +fdt_set_hdr_(boot_cpuid_phys) +fdt_set_hdr_(size_dt_strings) +fdt_set_hdr_(size_dt_struct) #undef fdt_set_hdr_ /** @@ -285,7 +285,7 @@ size_t fdt_header_size(const void *fdt); /** * fdt_header_size_ - internal function to get header size from a version number - * @version: devicetree version number + * @version: device tree version number * * Return: size of DTB header in bytes */ @@ -524,12 +524,37 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); * level matching the given component, differentiated only by unit * address). * + * If the path is not absolute (i.e. does not begin with '/'), the + * first component is treated as an alias. That is, the property by + * that name is looked up in the /aliases node, and the value of that + * property used in place of that first component. + * + * For example, for this small fragment + * + * / { + * aliases { + * i2c2 = &foo; // RHS compiles to "/soc@0/i2c@30a40000/eeprom@52" + * }; + * soc@0 { + * foo: i2c@30a40000 { + * bar: eeprom@52 { + * }; + * }; + * }; + * }; + * + * these would be equivalent: + * + * /soc@0/i2c@30a40000/eeprom@52 + * i2c2/eeprom@52 + * * returns: * structure block offset of the node with the requested path (>=0), on * success - * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + * -FDT_ERR_BADPATH, given path does not begin with '/' and the first + * component is not a valid alias * -FDT_ERR_NOTFOUND, if the requested node does not exist - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -574,7 +599,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); * structure block offset of the property (>=0), on success * -FDT_ERR_NOTFOUND, if the requested node has no properties * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -595,7 +620,7 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); * structure block offset of the next property (>=0), on success * -FDT_ERR_NOTFOUND, if the given property is the last in its node * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -687,6 +712,13 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); +static inline struct fdt_property * +fdt_get_property_namelen_w(void *fdt, int nodeoffset, const char *name, + int namelen, int *lenp) +{ + return (struct fdt_property *)(uintptr_t)fdt_get_property_namelen( + fdt, nodeoffset, name, namelen, lenp); +} #endif /** @@ -739,7 +771,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, * to within the device blob itself, not a copy of the value). If * lenp is non-NULL, the length of the property value is also * returned, in the integer pointed to by lenp. If namep is non-NULL, - * the property's namne will also be returned in the char * pointed to + * the property's name will also be returned in the char * pointed to * by namep (this will be a pointer to within the device tree's string * block, not a new copy of the name). * @@ -747,7 +779,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, * pointer to the property's value * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) - * if namep is non-NULL *namep contiains a pointer to the property + * if namep is non-NULL *namep contains a pointer to the property * name. * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): @@ -841,7 +873,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); /** * fdt_get_alias_namelen - get alias based on substring * @fdt: pointer to the device tree blob - * @name: name of the alias th look up + * @name: name of the alias to look up * @namelen: number of characters of name to consider * * Identical to fdt_get_alias(), but only examine the first @namelen @@ -858,7 +890,7 @@ const char *fdt_get_alias_namelen(const void *fdt, /** * fdt_get_alias - retrieve the path referenced by a given alias * @fdt: pointer to the device tree blob - * @name: name of the alias th look up + * @name: name of the alias to 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. @@ -870,6 +902,42 @@ const char *fdt_get_alias_namelen(const void *fdt, const char *fdt_get_alias(const void *fdt, const char *name); /** + * fdt_get_symbol_namelen - get symbol based on substring + * @fdt: pointer to the device tree blob + * @name: name of the symbol to look up + * @namelen: number of characters of name to consider + * + * Identical to fdt_get_symbol(), but only examine the first @namelen + * characters of @name for matching the symbol name. + * + * Return: a pointer to the expansion of the symbol named @name, if it exists, + * NULL otherwise + */ +#ifndef SWIG /* Not available in Python */ +const char *fdt_get_symbol_namelen(const void *fdt, + const char *name, int namelen); +#endif + +/** + * fdt_get_symbol - retrieve the path referenced by a given symbol + * @fdt: pointer to the device tree blob + * @name: name of the symbol to look up + * + * fdt_get_symbol() retrieves the value of a given symbol. That is, + * the value of the property named @name in the node + * /__symbols__. Such a node exists only for a device tree blob that + * has been compiled with the -@ dtc option. Each property corresponds + * to a label appearing in the device tree source, with the name of + * the property being the label and the value being the full path of + * the node it is attached to. + * + * returns: + * a pointer to the expansion of the symbol named 'name', if it exists + * NULL, if the given symbol or the /__symbols__ node does not exist + */ +const char *fdt_get_symbol(const void *fdt, const char *name); + +/** * fdt_get_path - determine the full path of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose path to find @@ -1198,8 +1266,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, * * returns: * 0 <= n < FDT_MAX_NCELLS, on success - * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * 2, if the node has no #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #address-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, @@ -1219,8 +1287,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * * returns: * 0 <= n < FDT_MAX_NCELLS, on success - * 1, if the node has no #size-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * 1, if the node has no #size-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #size-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, @@ -1450,7 +1518,7 @@ int fdt_nop_node(void *fdt, int nodeoffset); * fdt_create_with_flags() begins the process of creating a new fdt with * the sequential write interface. * - * fdt creation process must end with fdt_finished() to produce a valid fdt. + * fdt creation process must end with fdt_finish() to produce a valid fdt. * * returns: * 0, on success @@ -1501,7 +1569,7 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) * @fdt: pointer to the device tree blob * @name: name of property to add * @len: length of property value in bytes - * @valp: returns a pointer to where where the value should be placed + * @valp: returns a pointer to where the value should be placed * * returns: * 0, on success @@ -1599,6 +1667,38 @@ int fdt_del_mem_rsv(void *fdt, int n); int fdt_set_name(void *fdt, int nodeoffset, const char *name); /** + * fdt_setprop_namelen - create or change 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 + * @namelen: length of the name + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop_namelen() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_namelen(void *fdt, int nodeoffset, const char *name, + int namelen, const void *val, int len); + +/** * fdt_setprop - create or change a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change @@ -1626,8 +1726,44 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name); * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); +static inline int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + return fdt_setprop_namelen(fdt, nodeoffset, name, strlen(name), val, + len); +} + +/** + * fdt_setprop_placeholder_namelen - allocate space for a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: length of the name + * @len: length of the property value + * @prop_data: return pointer to property data + * + * fdt_setprop_placeholder_namelen() allocates the named property in the given node. + * If the property exists it is resized. In either case a pointer to the + * property data is returned. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_placeholder_namelen(void *fdt, int nodeoffset, const char *name, + int namelen, int len, void **prop_data); /** * fdt_setprop_placeholder - allocate space for a property @@ -1637,7 +1773,7 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, * @len: length of the property value * @prop_data: return pointer to property data * - * fdt_setprop_placeholer() allocates the named property in the given node. + * fdt_setprop_placeholder() allocates the named property in the given node. * If the property exists it is resized. In either case a pointer to the * property data is returned. * @@ -1657,8 +1793,13 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ -int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, - int len, void **prop_data); +static inline int fdt_setprop_placeholder(void *fdt, int nodeoffset, + const char *name, int len, + void **prop_data) +{ + return fdt_setprop_placeholder_namelen(fdt, nodeoffset, name, + strlen(name), len, prop_data); +} /** * fdt_setprop_u32 - set a property to a 32-bit integer @@ -1778,6 +1919,38 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, #define fdt_setprop_string(fdt, nodeoffset, name, str) \ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) +/** + * fdt_setprop_namelen_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: number of characters of name to consider + * @str: string value for the property + * + * fdt_setprop_namelen_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_namelen_string(fdt, nodeoffset, name, namelen, str) \ + fdt_setprop_namelen((fdt), (nodeoffset), (name), (namelen), (str), \ + strlen(str) + 1) /** * fdt_setprop_empty - set a property to an empty value @@ -1968,7 +2141,7 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, * address and size) to the value of the named property in the given * node, or creates a new property with that value if it does not * already exist. - * If "name" is not specified, a default "reg" is used. + * * Cell sizes are determined by parent's #address-cells and #size-cells. * * This function may insert data into the blob, and will therefore @@ -1998,7 +2171,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, * @nodeoffset: offset of the node whose property to nop * @name: name of the property to nop * - * fdt_del_property() will delete the given property. + * fdt_delprop() will delete the given property. * * This function will delete data from the blob, and will therefore * change the offsets of some existing nodes. @@ -2050,8 +2223,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * change the offsets of some existing nodes. * * returns: - * structure block offset of the created nodeequested subnode (>=0), on - * success + * structure block offset of the created subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE * tag @@ -2061,7 +2233,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * blob to contain the new node * -FDT_ERR_NOSPACE * -FDT_ERR_BADLAYOUT - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -2106,7 +2278,7 @@ int fdt_del_node(void *fdt, int nodeoffset); * returns: * 0, on success * -FDT_ERR_NOSPACE, there's not enough space in the base device tree - * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or + * -FDT_ERR_NOTFOUND, the overlay points to some nonexistent nodes or * properties in the base DT * -FDT_ERR_BADPHANDLE, * -FDT_ERR_BADOVERLAY, diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index 16bda1906a7b..b60b5456f596 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -20,7 +20,15 @@ int32_t fdt_ro_probe_(const void *fdt); int fdt_check_node_offset_(const void *fdt, int offset); int fdt_check_prop_offset_(const void *fdt, int offset); -const char *fdt_find_string_(const char *strtab, int tabsize, const char *s); + +const char *fdt_find_string_len_(const char *strtab, int tabsize, const char *s, + int s_len); +static inline const char *fdt_find_string_(const char *strtab, int tabsize, + const char *s) +{ + return fdt_find_string_len_(strtab, tabsize, s, strlen(s)); +} + int fdt_node_end_offset_(void *fdt, int nodeoffset); static inline const void *fdt_offset_ptr_(const void *fdt, int offset) @@ -47,8 +55,8 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) } /* - * Internal helpers to access tructural elements of the device tree - * blob (rather than for exaple reading integers from within property + * Internal helpers to access structural elements of the device tree + * blob (rather than for example 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. diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index f46a098d5ada..d51d05830b18 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -36,27 +36,27 @@ void delete_labels(struct label **labels) label->deleted = 1; } -struct property *build_property(char *name, struct data val, +struct property *build_property(const char *name, struct data val, struct srcpos *srcpos) { struct property *new = xmalloc(sizeof(*new)); memset(new, 0, sizeof(*new)); - new->name = name; + new->name = xstrdup(name); new->val = val; new->srcpos = srcpos_copy(srcpos); return new; } -struct property *build_property_delete(char *name) +struct property *build_property_delete(const char *name) { struct property *new = xmalloc(sizeof(*new)); memset(new, 0, sizeof(*new)); - new->name = name; + new->name = xstrdup(name); new->deleted = 1; return new; @@ -116,11 +116,11 @@ struct node *build_node_delete(struct srcpos *srcpos) return new; } -struct node *name_node(struct node *node, char *name) +struct node *name_node(struct node *node, const char *name) { assert(node->name == NULL); - node->name = name; + node->name = xstrdup(name); return node; } @@ -174,7 +174,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) old_prop->val = new_prop->val; old_prop->deleted = 0; - free(old_prop->srcpos); + srcpos_free(old_prop->srcpos); old_prop->srcpos = new_prop->srcpos; free(new_prop); new_prop = NULL; @@ -250,6 +250,7 @@ struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref) name_node(new_node, "__overlay__"); node = build_node(p, new_node, NULL); name_node(node, name); + free(name); add_child(dt, node); return dt; @@ -440,7 +441,7 @@ cell_t propval_cell(struct property *prop) cell_t propval_cell_n(struct property *prop, unsigned int n) { - assert(prop->val.len / sizeof(cell_t) >= n); + assert(prop->val.len / sizeof(cell_t) > n); return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n)); } @@ -503,7 +504,7 @@ struct node *get_subnode(struct node *node, const char *nodename) struct node *child; for_each_child(node, child) - if (streq(child->name, nodename)) + if (streq(child->name, nodename) && !child->deleted) return child; return NULL; @@ -616,10 +617,25 @@ struct node *get_node_by_ref(struct node *tree, const char *ref) return target; } +static void add_phandle_property(struct node *node, + const char *name, int format) +{ + struct data d; + + if (!(phandle_format & format)) + return; + if (get_property(node, name)) + return; + + d = data_add_marker(empty_data, TYPE_UINT32, NULL); + d = data_append_cell(d, node->phandle); + + add_property(node, build_property(name, d, NULL)); +} + 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 (phandle_is_valid(node->phandle)) return node->phandle; @@ -629,16 +645,8 @@ cell_t get_node_phandle(struct node *root, struct node *node) node->phandle = phandle; - d = data_add_marker(d, TYPE_UINT32, NULL); - d = data_append_cell(d, phandle); - - if (!get_property(node, "linux,phandle") - && (phandle_format & PHANDLE_LEGACY)) - add_property(node, build_property("linux,phandle", d, NULL)); - - if (!get_property(node, "phandle") - && (phandle_format & PHANDLE_EPAPR)) - add_property(node, build_property("phandle", d, NULL)); + add_phandle_property(node, "linux,phandle", PHANDLE_LEGACY); + add_phandle_property(node, "phandle", PHANDLE_EPAPR); /* If the node *does* have a phandle property, we must * be dealing with a self-referencing phandle, which will be @@ -808,18 +816,18 @@ void sort_tree(struct dt_info *dti) } /* utility helper to avoid code duplication */ -static struct node *build_and_name_child_node(struct node *parent, char *name) +static struct node *build_and_name_child_node(struct node *parent, const char *name) { struct node *node; node = build_node(NULL, NULL, NULL); - name_node(node, xstrdup(name)); + name_node(node, name); add_child(parent, node); return node; } -static struct node *build_root_node(struct node *dt, char *name) +static struct node *build_root_node(struct node *dt, const char *name) { struct node *an; @@ -1006,9 +1014,7 @@ static void add_local_fixup_entry(struct dt_info *dti, /* walk the path components creating nodes if they don't exist */ for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { /* if no node exists, create it */ - nwn = get_subnode(wn, compp[i]); - if (!nwn) - nwn = build_and_name_child_node(wn, compp[i]); + nwn = build_root_node(wn, compp[i]); } free(compp); @@ -1040,7 +1046,7 @@ static void generate_local_fixups_tree_internal(struct dt_info *dti, generate_local_fixups_tree_internal(dti, lfn, c); } -void generate_label_tree(struct dt_info *dti, char *name, bool allocph) +void generate_label_tree(struct dt_info *dti, const char *name, bool allocph) { if (!any_label_tree(dti, dti->dt)) return; @@ -1048,18 +1054,31 @@ void generate_label_tree(struct dt_info *dti, char *name, bool allocph) dti->dt, allocph); } -void generate_fixups_tree(struct dt_info *dti, char *name) +void generate_fixups_tree(struct dt_info *dti, const char *name) { + struct node *n = get_subnode(dti->dt, name); + + /* Start with an empty __fixups__ node to not get duplicates */ + if (n) + n->deleted = true; + if (!any_fixup_tree(dti, dti->dt)) return; - generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), + generate_fixups_tree_internal(dti, + build_and_name_child_node(dti->dt, name), dti->dt); } -void generate_local_fixups_tree(struct dt_info *dti, char *name) +void generate_local_fixups_tree(struct dt_info *dti, const char *name) { + struct node *n = get_subnode(dti->dt, name); + + /* Start with an empty __local_fixups__ node to not get duplicates */ + if (n) + n->deleted = true; if (!any_local_fixup_tree(dti, dti->dt)) return; - generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), + generate_local_fixups_tree_internal(dti, + build_and_name_child_node(dti->dt, name), dti->dt); } diff --git a/scripts/dtc/of_unittest_expect b/scripts/dtc/of_unittest_expect index 96b12d9ea606..0a535a8e9821 100755 --- a/scripts/dtc/of_unittest_expect +++ b/scripts/dtc/of_unittest_expect @@ -9,7 +9,7 @@ # on the console log that results from executing the Linux kernel # devicetree unittest (drivers/of/unitest.c). -$VUFX = "220201a"; +$VUFX = "230211a"; use strict 'refs'; use strict subs; @@ -62,6 +62,8 @@ sub compare { } else { return 0; } + } elsif ($type eq "all") { + return 1; } elsif ($type eq "") { if ($expect_next ne $got_next) { return 0; @@ -130,6 +132,7 @@ usage: <<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. @@ -240,6 +243,8 @@ if ($#ARGV != 0) { $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 = ""; @@ -250,6 +255,8 @@ while ($line = <ARGV>) { chomp $line; + $suppress_line = 0; + $prefix = " "; ## 2 characters @@ -274,7 +281,7 @@ while ($line = <ARGV>) { if ($line =~ /^\s*$exp_begin/) { $data = $line; $data =~ s/^\s*$exp_begin//; - push @begin, $data; + push @exp_begin_stack, $data; if ($verbose) { if ($print_line_num) { @@ -302,21 +309,22 @@ while ($line = <ARGV>) { $found = 0; $no_begin = 0; - if (@found_or_begin > 0) { - $begin = pop @found_or_begin; + 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 @begin; + $begin = pop @exp_begin_stack; } else { $no_begin = 1; } if ($no_begin) { - $expect_missing_begin++; - print "** ERROR: EXPECT end without any EXPECT begin:\n"; + $exp_missing_begin++; + print "** ERROR: EXPECT end without matching EXPECT begin:\n"; print " end ---> $line\n"; } elsif (! $found) { @@ -325,21 +333,101 @@ while ($line = <ARGV>) { $line_num = sprintf("%4s ", $.); } - $expect_not_found++; + $exp_missing++; printf "** %s%s$script_name WARNING - not found ---> %s\n", $line_num, $timestamp, $data; - } elsif (! compare($data, $begin)) { + } elsif (! compare($data, $begin) and ($data ne $begin)) { - $expect_missing_end++; + $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 { - $expect_found++; + $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; @@ -357,7 +445,30 @@ while ($line = <ARGV>) { } $found = 0; - foreach $begin (@begin) { + 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; @@ -367,19 +478,22 @@ while ($line = <ARGV>) { if ($found) { $begin = shift @begin; while (! compare($begin, $line)) { - push @found_or_begin, $begin; + push @expnot_found_or_begin, $begin; $begin = shift @begin; } - push @found_or_begin, $line; + push @expnot_found_or_begin, $line; if ($hide_expect) { $suppress_line = 1; - next LINE; } - $prefix = "ok"; # 2 characters + $prefix = "**"; # 2 characters } + if ($suppress_line) { + next LINE; + } + if ($print_line_num) { $line_num = sprintf("%4s ", $.); } @@ -391,18 +505,37 @@ if (! $no_expect_stats) { print "\n"; print "** EXPECT statistics:\n"; print "**\n"; - printf "** EXPECT found : %4i\n", $expect_found; - printf "** EXPECT not found : %4i\n", $expect_not_found; - printf "** missing EXPECT begin : %4i\n", $expect_missing_begin; - printf "** missing EXPECT end : %4i\n", $expect_missing_end; - printf "** unittest FAIL : %4i\n", $unittest_fail; - printf "** internal error : %4i\n", $internal_err; + 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 (@begin) { - print "** ERROR: EXPECT begin without any EXPECT end:\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 (@begin) { + foreach $begin (@expnot_begin_stack) { print " begin ---> $begin\n"; } } diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index 4fdb22a019bd..5bb57bf6856c 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -3,7 +3,9 @@ * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include <stdio.h> @@ -158,8 +160,10 @@ FILE *srcfile_relative_open(const char *fname, char **fullnamep) strerror(errno)); } - if (depfile) - fprintf(depfile, " %s", fullname); + if (depfile) { + fputc(' ', depfile); + fprint_path_escaped(depfile, fullname); + } if (fullnamep) *fullnamep = fullname; @@ -283,6 +287,17 @@ struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail) return pos; } +void srcpos_free(struct srcpos *pos) +{ + struct srcpos *p_next; + + while (pos) { + p_next = pos->next; + free(pos); + pos = p_next; + } +} + char * srcpos_string(struct srcpos *pos) { @@ -311,8 +326,8 @@ srcpos_string(struct srcpos *pos) static char * srcpos_string_comment(struct srcpos *pos, bool first_line, int level) { - char *pos_str, *fname, *first, *rest; - bool fresh_fname = false; + char *pos_str, *fresh_fname = NULL, *first, *rest; + const char *fname; if (!pos) { if (level > 1) { @@ -330,9 +345,9 @@ srcpos_string_comment(struct srcpos *pos, bool first_line, int level) else if (level > 1) fname = pos->file->name; else { - fname = shorten_to_initial_path(pos->file->name); - if (fname) - fresh_fname = true; + fresh_fname = shorten_to_initial_path(pos->file->name); + if (fresh_fname) + fname = fresh_fname; else fname = pos->file->name; } @@ -346,7 +361,7 @@ srcpos_string_comment(struct srcpos *pos, bool first_line, int level) first_line ? pos->first_line : pos->last_line); if (fresh_fname) - free(fname); + free(fresh_fname); if (pos->next != NULL) { rest = srcpos_string_comment(pos->next, first_line, level); diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h index 4318d7ad34d9..4d60b50e3119 100644 --- a/scripts/dtc/srcpos.h +++ b/scripts/dtc/srcpos.h @@ -88,6 +88,7 @@ extern void srcpos_update(struct srcpos *pos, const char *text, int len); extern struct srcpos *srcpos_copy(struct srcpos *pos); extern struct srcpos *srcpos_extend(struct srcpos *new_srcpos, struct srcpos *old_srcpos); +extern void srcpos_free(struct srcpos *pos); extern char *srcpos_string(struct srcpos *pos); extern char *srcpos_string_first(struct srcpos *pos, int level); extern char *srcpos_string_last(struct srcpos *pos, int level); diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index 33fedee82d58..d25f01fc6937 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -139,6 +139,50 @@ static const char *delim_end[] = { [TYPE_STRING] = "", }; +/* + * The invariants in the marker list are: + * - offsets are non-strictly monotonically increasing + * - for a single offset there is at most one type marker + * - for a single offset that has both a type marker and non-type markers, the + * type marker appears before the others. + */ +static struct marker **add_marker(struct marker **mi, + enum markertype type, unsigned int offset, char *ref) +{ + struct marker *nm; + + while (*mi && (*mi)->offset < offset) + mi = &(*mi)->next; + + if (*mi && (*mi)->offset == offset && is_type_marker((*mi)->type)) { + if (is_type_marker(type)) + return mi; + mi = &(*mi)->next; + } + + if (*mi && (*mi)->offset == offset && type == (*mi)->type) + return mi; + + nm = xmalloc(sizeof(*nm)); + nm->type = type; + nm->offset = offset; + nm->ref = ref; + nm->next = *mi; + *mi = nm; + + return &nm->next; +} + +static void add_string_markers(struct property *prop) +{ + int l, len = prop->val.len; + const char *p = prop->val.val; + struct marker **mi = &prop->val.markers; + + for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1) + mi = add_marker(mi, TYPE_STRING, l, NULL); +} + static enum markertype guess_value_type(struct property *prop) { int len = prop->val.len; @@ -164,6 +208,8 @@ static enum markertype guess_value_type(struct property *prop) if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul)) && (nnotstringlbl == 0)) { + if (nnul > 1) + add_string_markers(prop); return TYPE_STRING; } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { return TYPE_UINT32; @@ -241,6 +287,8 @@ static void write_propval(FILE *f, struct property *prop) } else { write_propval_int(f, p, chunk_len, 4); } + if (data_len > chunk_len) + fputc(' ', f); break; case TYPE_UINT64: write_propval_int(f, p, chunk_len, 8); diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index 507f0120cd13..412592320265 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -23,6 +23,22 @@ #include "util.h" #include "version_gen.h" +void fprint_path_escaped(FILE *fp, const char *path) +{ + const char *p = path; + + while (*p) { + if (*p == ' ') { + fputc('\\', fp); + fputc(' ', fp); + } else { + fputc(*p, fp); + } + + p++; + } +} + char *xstrdup(const char *s) { int len = strlen(s) + 1; diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index 9d38edee9736..800f2e2c55b1 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -13,7 +13,9 @@ */ #ifdef __GNUC__ -#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) +#ifdef __MINGW_PRINTF_FORMAT +#define PRINTF(i, j) __attribute__((format (__MINGW_PRINTF_FORMAT, i, j))) +#elif __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))) @@ -40,6 +42,11 @@ static inline void NORETURN PRINTF(1, 2) die(const char *str, ...) exit(1); } +/** + * Writes path to fp, escaping spaces with a backslash. + */ +void fprint_path_escaped(FILE *fp, const char *path); + static inline void *xmalloc(size_t len) { void *new = malloc(len); @@ -65,7 +72,7 @@ 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, ...); -extern int xavsprintf_append(char **strp, const char *fmt, va_list ap); +extern int PRINTF(2, 0) xavsprintf_append(char **strp, const char *fmt, va_list ap); extern char *join_path(const char *path, const char *name); /** diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 0f303087b043..226c48bf75dc 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.6.1-g55778a03" +#define DTC_VERSION "DTC 1.7.2-g52f07dcc" |
