| From 5f84cb93eef9f8a8ff7f49d593893f252744d0fe Mon Sep 17 00:00:00 2001 |
| From: Pantelis Antoniou <pantelis.antoniou@konsulko.com> |
| Date: Wed, 26 Aug 2015 18:28:08 +0300 |
| Subject: [PATCH] scripts/dtc: Update to version with overlays |
| |
| Update to mainline dtc with overlay support |
| |
| Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> |
| --- |
| checks.c | 20 +++++- |
| dtc-lexer.l | 5 ++ |
| dtc-parser.y | 54 ++++++++++++++-- |
| dtc.c | 83 ++++++++++++++++++++++-- |
| dtc.h | 13 +++- |
| livetree.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| treesource.c | 3 + |
| util.c | 2 +- |
| 8 files changed, 367 insertions(+), 15 deletions(-) |
| |
| diff --git a/checks.c b/checks.c |
| index 3bf0fa4..af25c2b 100644 |
| --- a/checks.c |
| +++ b/checks.c |
| @@ -465,8 +465,12 @@ static void fixup_phandle_references(struct check *c, struct node *dt, |
| |
| refnode = get_node_by_ref(dt, m->ref); |
| if (! refnode) { |
| - FAIL(c, "Reference to non-existent node or label \"%s\"\n", |
| - m->ref); |
| + if (!source_is_plugin) |
| + FAIL(c, "Reference to non-existent node or " |
| + "label \"%s\"\n", m->ref); |
| + else /* mark the entry as unresolved */ |
| + *((cell_t *)(prop->val.val + m->offset)) = |
| + cpu_to_fdt32(0xffffffff); |
| continue; |
| } |
| |
| @@ -559,7 +563,7 @@ static void check_reg_format(struct check *c, struct node *dt, |
| size_cells = node_size_cells(node->parent); |
| entrylen = (addr_cells + size_cells) * sizeof(cell_t); |
| |
| - if ((prop->val.len % entrylen) != 0) |
| + if (!entrylen || (prop->val.len % entrylen) != 0) |
| FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " |
| "(#address-cells == %d, #size-cells == %d)", |
| node->fullpath, prop->val.len, addr_cells, size_cells); |
| @@ -651,6 +655,15 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, |
| } |
| TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); |
| |
| +static void check_deprecated_plugin_syntax(struct check *c, |
| + struct node *dt) |
| +{ |
| + if (deprecated_plugin_syntax_warning) |
| + FAIL(c, "Use '/dts-v1/ /plugin/'; syntax. /dts-v1/; /plugin/; " |
| + "is going to be removed in next versions"); |
| +} |
| +TREE_WARNING(deprecated_plugin_syntax, NULL); |
| + |
| static struct check *check_table[] = { |
| &duplicate_node_names, &duplicate_property_names, |
| &node_name_chars, &node_name_format, &property_name_chars, |
| @@ -668,6 +681,7 @@ static struct check *check_table[] = { |
| |
| &avoid_default_addr_size, |
| &obsolete_chosen_interrupt_controller, |
| + &deprecated_plugin_syntax, |
| |
| &always_fail, |
| }; |
| diff --git a/dtc-lexer.l b/dtc-lexer.l |
| index 0ee1caf..dd44ba2 100644 |
| --- a/dtc-lexer.l |
| +++ b/dtc-lexer.l |
| @@ -113,6 +113,11 @@ static void lexical_error(const char *fmt, ...); |
| return DT_V1; |
| } |
| |
| +<*>"/plugin/" { |
| + DPRINT("Keyword: /plugin/\n"); |
| + return DT_PLUGIN; |
| + } |
| + |
| <*>"/memreserve/" { |
| DPRINT("Keyword: /memreserve/\n"); |
| BEGIN_DEFAULT(); |
| diff --git a/dtc-parser.y b/dtc-parser.y |
| index ea57e0a..7d9652d 100644 |
| --- a/dtc-parser.y |
| +++ b/dtc-parser.y |
| @@ -19,6 +19,7 @@ |
| */ |
| %{ |
| #include <stdio.h> |
| +#include <inttypes.h> |
| |
| #include "dtc.h" |
| #include "srcpos.h" |
| @@ -52,9 +53,11 @@ extern bool treesource_error; |
| struct node *nodelist; |
| struct reserve_info *re; |
| uint64_t integer; |
| + bool is_plugin; |
| } |
| |
| %token DT_V1 |
| +%token DT_PLUGIN |
| %token DT_MEMRESERVE |
| %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR |
| %token DT_BITS |
| @@ -71,6 +74,7 @@ extern bool treesource_error; |
| |
| %type <data> propdata |
| %type <data> propdataprefix |
| +%type <is_plugin> plugindecl |
| %type <re> memreserve |
| %type <re> memreserves |
| %type <array> arrayprefix |
| @@ -101,10 +105,39 @@ extern bool treesource_error; |
| %% |
| |
| sourcefile: |
| - DT_V1 ';' memreserves devicetree |
| + basesource |
| + | pluginsource |
| + ; |
| + |
| +basesource: |
| + DT_V1 ';' plugindecl memreserves devicetree |
| + { |
| + source_is_plugin = $3; |
| + if (source_is_plugin) |
| + deprecated_plugin_syntax_warning = true; |
| + the_boot_info = build_boot_info($4, $5, |
| + guess_boot_cpuid($5)); |
| + } |
| + ; |
| + |
| +plugindecl: |
| + /* empty */ |
| + { |
| + $$ = false; |
| + } |
| + | DT_PLUGIN ';' |
| + { |
| + $$ = true; |
| + } |
| + ; |
| + |
| +pluginsource: |
| + DT_V1 DT_PLUGIN ';' memreserves devicetree |
| { |
| - the_boot_info = build_boot_info($3, $4, |
| - guess_boot_cpuid($4)); |
| + source_is_plugin = true; |
| + deprecated_plugin_syntax_warning = false; |
| + the_boot_info = build_boot_info($4, $5, |
| + guess_boot_cpuid($5)); |
| } |
| ; |
| |
| @@ -144,10 +177,14 @@ devicetree: |
| { |
| struct node *target = get_node_by_ref($1, $2); |
| |
| - if (target) |
| + if (target) { |
| merge_nodes(target, $3); |
| - else |
| - ERROR(&@2, "Label or path %s not found", $2); |
| + } else { |
| + if (symbol_fixup_support) |
| + add_orphan_node($1, $3, $2); |
| + else |
| + ERROR(&@2, "Label or path %s not found", $2); |
| + } |
| $$ = $1; |
| } |
| | devicetree DT_DEL_NODE DT_REF ';' |
| @@ -162,6 +199,11 @@ devicetree: |
| |
| $$ = $1; |
| } |
| + | /* empty */ |
| + { |
| + /* build empty node */ |
| + $$ = name_node(build_node(NULL, NULL), ""); |
| + } |
| ; |
| |
| nodedef: |
| diff --git a/dtc.c b/dtc.c |
| index 8c4add6..ee37be9 100644 |
| --- a/dtc.c |
| +++ b/dtc.c |
| @@ -18,6 +18,8 @@ |
| * USA |
| */ |
| |
| +#include <sys/stat.h> |
| + |
| #include "dtc.h" |
| #include "srcpos.h" |
| |
| @@ -29,6 +31,8 @@ int reservenum; /* Number of memory reservation slots */ |
| int minsize; /* Minimum blob size */ |
| int padsize; /* Additional padding to blob */ |
| int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */ |
| +int symbol_fixup_support; |
| +int auto_label_aliases; |
| |
| static void fill_fullpaths(struct node *tree, const char *prefix) |
| { |
| @@ -51,7 +55,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix) |
| #define FDT_VERSION(version) _FDT_VERSION(version) |
| #define _FDT_VERSION(version) #version |
| static const char usage_synopsis[] = "dtc [options] <input file>"; |
| -static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv"; |
| +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:@Ahv"; |
| static struct option const usage_long_opts[] = { |
| {"quiet", no_argument, NULL, 'q'}, |
| {"in-format", a_argument, NULL, 'I'}, |
| @@ -69,6 +73,8 @@ static struct option const usage_long_opts[] = { |
| {"phandle", a_argument, NULL, 'H'}, |
| {"warning", a_argument, NULL, 'W'}, |
| {"error", a_argument, NULL, 'E'}, |
| + {"symbols", no_argument, NULL, '@'}, |
| + {"auto-alias", no_argument, NULL, 'A'}, |
| {"help", no_argument, NULL, 'h'}, |
| {"version", no_argument, NULL, 'v'}, |
| {NULL, no_argument, NULL, 0x0}, |
| @@ -99,16 +105,63 @@ static const char * const usage_opts_help[] = { |
| "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties", |
| "\n\tEnable/disable warnings (prefix with \"no-\")", |
| "\n\tEnable/disable errors (prefix with \"no-\")", |
| + "\n\tEnable symbols/fixup support", |
| + "\n\tEnable auto-alias of labels", |
| "\n\tPrint this help and exit", |
| "\n\tPrint version and exit", |
| NULL, |
| }; |
| |
| +static const char *guess_type_by_name(const char *fname, const char *fallback) |
| +{ |
| + const char *s; |
| + |
| + s = strrchr(fname, '.'); |
| + if (s == NULL) |
| + return fallback; |
| + if (!strcasecmp(s, ".dts")) |
| + return "dts"; |
| + if (!strcasecmp(s, ".dtb")) |
| + return "dtb"; |
| + return fallback; |
| +} |
| + |
| +static const char *guess_input_format(const char *fname, const char *fallback) |
| +{ |
| + struct stat statbuf; |
| + uint32_t magic; |
| + FILE *f; |
| + |
| + if (stat(fname, &statbuf) != 0) |
| + return fallback; |
| + |
| + if (S_ISDIR(statbuf.st_mode)) |
| + return "fs"; |
| + |
| + if (!S_ISREG(statbuf.st_mode)) |
| + return fallback; |
| + |
| + f = fopen(fname, "r"); |
| + if (f == NULL) |
| + return fallback; |
| + if (fread(&magic, 4, 1, f) != 1) { |
| + fclose(f); |
| + return fallback; |
| + } |
| + fclose(f); |
| + |
| + magic = fdt32_to_cpu(magic); |
| + if (magic == FDT_MAGIC) |
| + return "dtb"; |
| + |
| + return guess_type_by_name(fname, fallback); |
| +} |
| + |
| int main(int argc, char *argv[]) |
| { |
| struct boot_info *bi; |
| - const char *inform = "dts"; |
| - const char *outform = "dts"; |
| + const char *inform = NULL; |
| + const char *outform = NULL; |
| const char *outname = "-"; |
| const char *depname = NULL; |
| bool force = false, sort = false; |
| @@ -186,7 +239,12 @@ int main(int argc, char *argv[]) |
| case 'E': |
| parse_checks_option(false, true, optarg); |
| break; |
| - |
| + case '@': |
| + symbol_fixup_support = 1; |
| + break; |
| + case 'A': |
| + auto_label_aliases = 1; |
| + break; |
| case 'h': |
| usage(NULL); |
| default: |
| @@ -213,6 +271,17 @@ int main(int argc, char *argv[]) |
| fprintf(depfile, "%s:", outname); |
| } |
| |
| + if (inform == NULL) |
| + inform = guess_input_format(arg, "dts"); |
| + if (outform == NULL) { |
| + outform = guess_type_by_name(outname, NULL); |
| + if (outform == NULL) { |
| + if (streq(inform, "dts")) |
| + outform = "dtb"; |
| + else |
| + outform = "dts"; |
| + } |
| + } |
| if (streq(inform, "dts")) |
| bi = dt_from_source(arg); |
| else if (streq(inform, "fs")) |
| @@ -236,6 +305,12 @@ int main(int argc, char *argv[]) |
| if (sort) |
| sort_tree(bi); |
| |
| + if (symbol_fixup_support || auto_label_aliases) |
| + generate_label_node(bi->dt, bi->dt); |
| + |
| + if (symbol_fixup_support) |
| + generate_fixups_node(bi->dt, bi->dt); |
| + |
| if (streq(outname, "-")) { |
| outf = stdout; |
| } else { |
| diff --git a/dtc.h b/dtc.h |
| index 56212c8..d025111 100644 |
| --- a/dtc.h |
| +++ b/dtc.h |
| @@ -20,7 +20,7 @@ |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| * USA |
| */ |
| - |
| +#define _GNU_SOURCE |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| @@ -54,6 +54,14 @@ extern int reservenum; /* Number of memory reservation slots */ |
| extern int minsize; /* Minimum blob size */ |
| extern int padsize; /* Additional padding to blob */ |
| extern int phandle_format; /* Use linux,phandle or phandle properties */ |
| +extern int symbol_fixup_support;/* enable symbols & fixup support */ |
| +extern int auto_label_aliases; /* auto generate labels -> aliases */ |
| + |
| +/* |
| + * Tree source globals |
| + */ |
| +extern bool source_is_plugin; |
| +extern bool deprecated_plugin_syntax_warning; |
| |
| #define PHANDLE_LEGACY 0x1 |
| #define PHANDLE_EPAPR 0x2 |
| @@ -194,6 +202,7 @@ struct node *build_node_delete(void); |
| struct node *name_node(struct node *node, char *name); |
| struct node *chain_node(struct node *first, struct node *list); |
| struct node *merge_nodes(struct node *old_node, struct node *new_node); |
| +void add_orphan_node(struct node *old_node, struct node *new_node, char *ref); |
| |
| void add_property(struct node *node, struct property *prop); |
| void delete_property_by_name(struct node *node, char *name); |
| @@ -244,6 +253,8 @@ struct boot_info { |
| struct boot_info *build_boot_info(struct reserve_info *reservelist, |
| struct node *tree, uint32_t boot_cpuid_phys); |
| void sort_tree(struct boot_info *bi); |
| +void generate_label_node(struct node *node, struct node *dt); |
| +void generate_fixups_node(struct node *node, struct node *dt); |
| |
| /* Checks */ |
| |
| diff --git a/livetree.c b/livetree.c |
| index e229b84..1ef9fc4 100644 |
| --- a/livetree.c |
| +++ b/livetree.c |
| @@ -216,6 +216,34 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) |
| return old_node; |
| } |
| |
| +void add_orphan_node(struct node *dt, struct node *new_node, char *ref) |
| +{ |
| + static unsigned int next_orphan_fragment = 0; |
| + struct node *ovl = xmalloc(sizeof(*ovl)); |
| + struct property *p; |
| + struct data d = empty_data; |
| + char *name; |
| + int ret; |
| + |
| + memset(ovl, 0, sizeof(*ovl)); |
| + |
| + d = data_add_marker(d, REF_PHANDLE, ref); |
| + d = data_append_integer(d, 0xffffffff, 32); |
| + |
| + p = build_property("target", d); |
| + add_property(ovl, p); |
| + |
| + ret = asprintf(&name, "fragment@%u", |
| + next_orphan_fragment++); |
| + if (ret == -1) |
| + die("asprintf() failed\n"); |
| + name_node(ovl, name); |
| + name_node(new_node, "__overlay__"); |
| + |
| + add_child(dt, ovl); |
| + add_child(ovl, new_node); |
| +} |
| + |
| struct node *chain_node(struct node *first, struct node *list) |
| { |
| assert(first->next_sibling == NULL); |
| @@ -709,3 +737,177 @@ void sort_tree(struct boot_info *bi) |
| sort_reserve_entries(bi); |
| sort_node(bi->dt); |
| } |
| + |
| +void generate_label_node(struct node *node, struct node *dt) |
| +{ |
| + struct node *c, *an; |
| + struct property *p; |
| + struct label *l; |
| + int has_label; |
| + char *gen_node_name; |
| + |
| + if (auto_label_aliases) |
| + gen_node_name = "aliases"; |
| + else |
| + gen_node_name = "__symbols__"; |
| + |
| + /* Make sure the label isn't already there */ |
| + has_label = 0; |
| + for_each_label(node->labels, l) { |
| + has_label = 1; |
| + break; |
| + } |
| + |
| + if (has_label) { |
| + |
| + /* an is the aliases/__symbols__ node */ |
| + an = get_subnode(dt, gen_node_name); |
| + /* if no node exists, create it */ |
| + if (!an) { |
| + an = build_node(NULL, NULL); |
| + name_node(an, gen_node_name); |
| + add_child(dt, an); |
| + } |
| + |
| + /* now add the label in the node */ |
| + for_each_label(node->labels, l) { |
| + /* check whether the label already exists */ |
| + p = get_property(an, l->label); |
| + if (p) { |
| + fprintf(stderr, "WARNING: label %s already" |
| + " exists in /%s", l->label, |
| + gen_node_name); |
| + continue; |
| + } |
| + |
| + /* insert it */ |
| + p = build_property(l->label, |
| + data_copy_escape_string(node->fullpath, |
| + strlen(node->fullpath))); |
| + add_property(an, p); |
| + } |
| + |
| + /* force allocation of a phandle for this node */ |
| + if (symbol_fixup_support) |
| + (void)get_node_phandle(dt, node); |
| + } |
| + |
| + for_each_child(node, c) |
| + generate_label_node(c, dt); |
| +} |
| + |
| +static void add_fixup_entry(struct node *dt, struct node *node, |
| + struct property *prop, struct marker *m) |
| +{ |
| + struct node *fn; /* local fixup node */ |
| + struct property *p; |
| + char *fixups_name = "__fixups__"; |
| + struct data d; |
| + char *entry; |
| + int ret; |
| + |
| + /* fn is the node we're putting entries in */ |
| + fn = get_subnode(dt, fixups_name); |
| + /* if no node exists, create it */ |
| + if (!fn) { |
| + fn = build_node(NULL, NULL); |
| + name_node(fn, fixups_name); |
| + add_child(dt, fn); |
| + } |
| + |
| + ret = asprintf(&entry, "%s:%s:%u", |
| + node->fullpath, prop->name, m->offset); |
| + if (ret == -1) |
| + die("asprintf() failed\n"); |
| + |
| + p = get_property(fn, m->ref); |
| + d = data_append_data(p ? p->val : empty_data, entry, strlen(entry) + 1); |
| + if (!p) |
| + add_property(fn, build_property(m->ref, d)); |
| + else |
| + p->val = d; |
| +} |
| + |
| +static void add_local_fixup_entry(struct node *dt, struct node *node, |
| + struct property *prop, struct marker *m, |
| + struct node *refnode) |
| +{ |
| + struct node *lfn, *wn, *nwn; /* local fixup node, walk node, new */ |
| + struct property *p; |
| + struct data d; |
| + char *local_fixups_name = "__local_fixups__"; |
| + char *s, *e, *comp; |
| + int len; |
| + |
| + /* fn is the node we're putting entries in */ |
| + lfn = get_subnode(dt, local_fixups_name); |
| + /* if no node exists, create it */ |
| + if (!lfn) { |
| + lfn = build_node(NULL, NULL); |
| + name_node(lfn, local_fixups_name); |
| + add_child(dt, lfn); |
| + } |
| + |
| + /* walk the path components creating nodes if they don't exist */ |
| + comp = NULL; |
| + /* start skipping the first / */ |
| + s = node->fullpath + 1; |
| + wn = lfn; |
| + while (*s) { |
| + /* retrieve path component */ |
| + e = strchr(s, '/'); |
| + if (e == NULL) |
| + e = s + strlen(s); |
| + len = e - s; |
| + comp = xrealloc(comp, len + 1); |
| + memcpy(comp, s, len); |
| + comp[len] = '\0'; |
| + |
| + /* if no node exists, create it */ |
| + nwn = get_subnode(wn, comp); |
| + if (!nwn) { |
| + nwn = build_node(NULL, NULL); |
| + name_node(nwn, strdup(comp)); |
| + add_child(wn, nwn); |
| + } |
| + wn = nwn; |
| + |
| + /* last path component */ |
| + if (!*e) |
| + break; |
| + |
| + /* next path component */ |
| + s = e + 1; |
| + } |
| + free(comp); |
| + |
| + p = get_property(wn, prop->name); |
| + d = data_append_cell(p ? p->val : empty_data, (cell_t)m->offset); |
| + if (!p) |
| + add_property(wn, build_property(prop->name, d)); |
| + else |
| + p->val = d; |
| +} |
| + |
| +void generate_fixups_node(struct node *node, struct node *dt) |
| +{ |
| + struct node *c; |
| + struct property *prop; |
| + struct marker *m; |
| + struct node *refnode; |
| + |
| + for_each_property(node, prop) { |
| + m = prop->val.markers; |
| + for_each_marker_of_type(m, REF_PHANDLE) { |
| + refnode = get_node_by_ref(dt, m->ref); |
| + if (!refnode) |
| + add_fixup_entry(dt, node, prop, m); |
| + else |
| + add_local_fixup_entry(dt, node, prop, m, |
| + refnode); |
| + } |
| + } |
| + |
| + for_each_child(node, c) |
| + generate_fixups_node(c, dt); |
| +} |
| diff --git a/treesource.c b/treesource.c |
| index a55d1d1..e1d6657 100644 |
| --- a/treesource.c |
| +++ b/treesource.c |
| @@ -28,6 +28,9 @@ extern YYLTYPE yylloc; |
| struct boot_info *the_boot_info; |
| bool treesource_error; |
| |
| +bool source_is_plugin; |
| +bool deprecated_plugin_syntax_warning; |
| + |
| struct boot_info *dt_from_source(const char *fname) |
| { |
| the_boot_info = NULL; |
| diff --git a/util.c b/util.c |
| index 9d65226..cbb945b 100644 |
| --- a/util.c |
| +++ b/util.c |
| @@ -349,7 +349,6 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) |
| void utilfdt_print_data(const char *data, int len) |
| { |
| int i; |
| - const char *p = data; |
| const char *s; |
| |
| /* no data, don't print */ |
| @@ -376,6 +375,7 @@ void utilfdt_print_data(const char *data, int len) |
| i < (len - 1) ? " " : ""); |
| printf(">"); |
| } else { |
| + const unsigned char *p = (const unsigned char *)data; |
| printf(" = ["); |
| for (i = 0; i < len; i++) |
| printf("%02x%s", *p++, i < len - 1 ? " " : ""); |
| -- |
| 2.7.0 |
| |