diff options
Diffstat (limited to 'scripts/dtc/treesource.c')
| -rw-r--r-- | scripts/dtc/treesource.c | 349 |
1 files changed, 225 insertions, 124 deletions
diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index 33eeba55fb4d..d25f01fc6937 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -1,21 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include "dtc.h" @@ -25,13 +10,13 @@ extern FILE *yyin; extern int yyparse(void); extern YYLTYPE yylloc; -struct boot_info *the_boot_info; -int treesource_error; +struct dt_info *parser_output; +bool treesource_error; -struct boot_info *dt_from_source(const char *fname) +struct dt_info *dt_from_source(const char *fname) { - the_boot_info = NULL; - treesource_error = 0; + parser_output = NULL; + treesource_error = false; srcfile_push(fname); yyin = current_srcfile->f; @@ -43,7 +28,7 @@ struct boot_info *dt_from_source(const char *fname) if (treesource_error) die("Syntax error parsing input tree\n"); - return the_boot_info; + return parser_output; } static void write_prefix(FILE *f, int level) @@ -54,31 +39,25 @@ static void write_prefix(FILE *f, int level) fputc('\t', f); } -static int isstring(char c) +static bool isstring(char c) { - return (isprint(c) + return (isprint((unsigned char)c) || (c == '\0') || strchr("\a\b\t\n\v\f\r", c)); } -static void write_propval_string(FILE *f, struct data val) +static void write_propval_string(FILE *f, const char *s, size_t len) { - const char *str = val.val; - int i; - struct marker *m = val.markers; - - assert(str[val.len-1] == '\0'); + const char *end = s + len - 1; - while (m && (m->offset == 0)) { - if (m->type == LABEL) - fprintf(f, "%s: ", m->ref); - m = m->next; - } - fprintf(f, "\""); + if (!len) + return; - for (i = 0; i < (val.len-1); i++) { - char c = str[i]; + assert(*end == '\0'); + fprintf(f, "\""); + while (s < end) { + char c = *s++; switch (c) { case '\a': fprintf(f, "\\a"); @@ -108,91 +87,103 @@ static void write_propval_string(FILE *f, struct data val) fprintf(f, "\\\""); break; case '\0': - fprintf(f, "\", "); - while (m && (m->offset < i)) { - if (m->type == LABEL) { - assert(m->offset == (i+1)); - fprintf(f, "%s: ", m->ref); - } - m = m->next; - } - fprintf(f, "\""); + fprintf(f, "\\0"); break; default: - if (isprint(c)) + if (isprint((unsigned char)c)) fprintf(f, "%c", c); else - fprintf(f, "\\x%02hhx", c); + fprintf(f, "\\x%02"PRIx8, c); } } fprintf(f, "\""); - - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); - } } -static void write_propval_cells(FILE *f, struct data val) +static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) { - void *propend = val.val + val.len; - cell_t *cp = (cell_t *)val.val; - struct marker *m = val.markers; - - fprintf(f, "<"); - for (;;) { - while (m && (m->offset <= ((char *)cp - val.val))) { - if (m->type == LABEL) { - assert(m->offset == ((char *)cp - val.val)); - fprintf(f, "%s: ", m->ref); - } - m = m->next; - } + const char *end = p + len; + assert(len % width == 0); - fprintf(f, "0x%x", fdt32_to_cpu(*cp++)); - if ((void *)cp >= propend) + for (; p < end; p += width) { + switch (width) { + case 1: + fprintf(f, "%02"PRIx8, *(const uint8_t*)p); break; - fprintf(f, " "); - } - - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); + case 2: + fprintf(f, "0x%02"PRIx16, dtb_ld16(p)); + break; + case 4: + fprintf(f, "0x%02"PRIx32, dtb_ld32(p)); + break; + case 8: + fprintf(f, "0x%02"PRIx64, dtb_ld64(p)); + break; + } + if (p + width < end) + fputc(' ', f); } - fprintf(f, ">"); } -static void write_propval_bytes(FILE *f, struct data val) +static const char *delim_start[] = { + [TYPE_UINT8] = "[", + [TYPE_UINT16] = "/bits/ 16 <", + [TYPE_UINT32] = "<", + [TYPE_UINT64] = "/bits/ 64 <", + [TYPE_STRING] = "", +}; +static const char *delim_end[] = { + [TYPE_UINT8] = "]", + [TYPE_UINT16] = ">", + [TYPE_UINT32] = ">", + [TYPE_UINT64] = ">", + [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) { - void *propend = val.val + val.len; - const char *bp = val.val; - struct marker *m = val.markers; - - fprintf(f, "["); - for (;;) { - while (m && (m->offset == (bp-val.val))) { - if (m->type == LABEL) - fprintf(f, "%s: ", m->ref); - m = m->next; - } + struct marker *nm; - fprintf(f, "%02hhx", *bp++); - if ((const void *)bp >= propend) - break; - fprintf(f, " "); - } + while (*mi && (*mi)->offset < offset) + mi = &(*mi)->next; - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); + if (*mi && (*mi)->offset == offset && is_type_marker((*mi)->type)) { + if (is_type_marker(type)) + return mi; + mi = &(*mi)->next; } - fprintf(f, "]"); + + 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 write_propval(FILE *f, struct property *prop) +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; const char *p = prop->val.val; @@ -201,11 +192,6 @@ static void write_propval(FILE *f, struct property *prop) int nnotstringlbl = 0, nnotcelllbl = 0; int i; - if (len == 0) { - fprintf(f, ";\n"); - return; - } - for (i = 0; i < len; i++) { if (! isstring(p[i])) nnotstring++; @@ -220,17 +206,116 @@ static void write_propval(FILE *f, struct property *prop) nnotcelllbl++; } - fprintf(f, " = "); - if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul)) + if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul)) && (nnotstringlbl == 0)) { - write_propval_string(f, prop->val); + if (nnul > 1) + add_string_markers(prop); + return TYPE_STRING; } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { - write_propval_cells(f, prop->val); - } else { - write_propval_bytes(f, prop->val); + return TYPE_UINT32; } - fprintf(f, ";\n"); + return TYPE_UINT8; +} + +static void write_propval(FILE *f, struct property *prop) +{ + size_t len = prop->val.len; + struct marker *m = prop->val.markers; + struct marker dummy_marker; + enum markertype emit_type = TYPE_NONE; + char *srcstr; + + if (len == 0) { + fprintf(f, ";"); + if (annotate) { + srcstr = srcpos_string_first(prop->srcpos, annotate); + if (srcstr) { + fprintf(f, " /* %s */", srcstr); + free(srcstr); + } + } + fprintf(f, "\n"); + return; + } + + fprintf(f, " ="); + + if (!next_type_marker(m)) { + /* data type information missing, need to guess */ + dummy_marker.type = guess_value_type(prop); + dummy_marker.next = prop->val.markers; + dummy_marker.offset = 0; + dummy_marker.ref = NULL; + m = &dummy_marker; + } + + for_each_marker(m) { + size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; + size_t data_len = type_marker_length(m) ? : len - m->offset; + const char *p = &prop->val.val[m->offset]; + struct marker *m_phandle; + + if (is_type_marker(m->type)) { + emit_type = m->type; + fprintf(f, " %s", delim_start[emit_type]); + } else if (m->type == LABEL) + fprintf(f, " %s:", m->ref); + + if (emit_type == TYPE_NONE || chunk_len == 0) + continue; + + switch(emit_type) { + case TYPE_UINT16: + write_propval_int(f, p, chunk_len, 2); + break; + case TYPE_UINT32: + m_phandle = prop->val.markers; + for_each_marker_of_type(m_phandle, REF_PHANDLE) + if (m->offset == m_phandle->offset) + break; + + if (m_phandle) { + if (m_phandle->ref[0] == '/') + fprintf(f, "&{%s}", m_phandle->ref); + else + fprintf(f, "&%s", m_phandle->ref); + if (chunk_len > 4) { + fputc(' ', f); + write_propval_int(f, p + 4, chunk_len - 4, 4); + } + } else { + write_propval_int(f, p, chunk_len, 4); + } + if (data_len > chunk_len) + fputc(' ', f); + break; + case TYPE_UINT64: + write_propval_int(f, p, chunk_len, 8); + break; + case TYPE_STRING: + write_propval_string(f, p, chunk_len); + break; + default: + write_propval_int(f, p, chunk_len, 1); + } + + if (chunk_len == data_len) { + size_t pos = m->offset + chunk_len; + fprintf(f, pos == len ? "%s" : "%s,", + delim_end[emit_type] ? : ""); + emit_type = TYPE_NONE; + } + } + fprintf(f, ";"); + if (annotate) { + srcstr = srcpos_string_first(prop->srcpos, annotate); + if (srcstr) { + fprintf(f, " /* %s */", srcstr); + free(srcstr); + } + } + fprintf(f, "\n"); } static void write_tree_source_node(FILE *f, struct node *tree, int level) @@ -238,14 +323,24 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) struct property *prop; struct node *child; struct label *l; + char *srcstr; write_prefix(f, level); for_each_label(tree->labels, l) fprintf(f, "%s: ", l->label); if (tree->name && (*tree->name)) - fprintf(f, "%s {\n", tree->name); + fprintf(f, "%s {", tree->name); else - fprintf(f, "/ {\n"); + fprintf(f, "/ {"); + + if (annotate) { + srcstr = srcpos_string_first(tree->srcpos, annotate); + if (srcstr) { + fprintf(f, " /* %s */", srcstr); + free(srcstr); + } + } + fprintf(f, "\n"); for_each_property(tree, prop) { write_prefix(f, level+1); @@ -259,26 +354,32 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) write_tree_source_node(f, child, level+1); } write_prefix(f, level); - fprintf(f, "};\n"); + fprintf(f, "};"); + if (annotate) { + srcstr = srcpos_string_last(tree->srcpos, annotate); + if (srcstr) { + fprintf(f, " /* %s */", srcstr); + free(srcstr); + } + } + fprintf(f, "\n"); } - -void dt_to_source(FILE *f, struct boot_info *bi) +void dt_to_source(FILE *f, struct dt_info *dti) { struct reserve_info *re; fprintf(f, "/dts-v1/;\n\n"); - for (re = bi->reservelist; re; re = re->next) { + for (re = dti->reservelist; re; re = re->next) { struct label *l; for_each_label(re->labels, l) fprintf(f, "%s: ", l->label); fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", - (unsigned long long)re->re.address, - (unsigned long long)re->re.size); + (unsigned long long)re->address, + (unsigned long long)re->size); } - write_tree_source_node(f, bi->dt, 0); + write_tree_source_node(f, dti->dt, 0); } - |
