Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438// SPDX-License-Identifier: GPL-2.0-or-later/* * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. */
#include "dtc.h"#include "srcpos.h"
extern FILE *yyin;extern int yyparse(void);extern YYLTYPE yylloc;
struct dt_info *parser_output;bool treesource_error;
struct dt_info *dt_from_source(const char *fname){ parser_output = NULL; treesource_error = false;
srcfile_push(fname); yyin = current_srcfile->f; yylloc.file = current_srcfile;
if (yyparse() != 0) die("Unable to parse input tree\n");
if (treesource_error) die("Syntax error parsing input tree\n");
return parser_output;}
static void write_prefix(FILE *f, int level){ int i;
for (i = 0; i < level; i++) fputc('\t', f);}
static bool isstring(char c){ return (isprint((unsigned char)c) || (c == '\0') || strchr("\a\b\t\n\v\f\r", c));}
static void write_propval_string(FILE *f, const char *s, size_t len){ const char *end = s + len - 1;
if (!len) return;
assert(*end == '\0');
fprintf(f, "\""); while (s < end) { char c = *s++; switch (c) { case '\a': fprintf(f, "\\a"); break; case '\b': fprintf(f, "\\b"); break; case '\t': fprintf(f, "\\t"); break; case '\n': fprintf(f, "\\n"); break; case '\v': fprintf(f, "\\v"); break; case '\f': fprintf(f, "\\f"); break; case '\r': fprintf(f, "\\r"); break; case '\\': fprintf(f, "\\\\"); break; case '\"': fprintf(f, "\\\""); break; case '\0': fprintf(f, "\\0"); break; default: if (isprint((unsigned char)c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02"PRIx8, c); } } fprintf(f, "\"");}
static void write_propval_int(FILE *f, const char *p, size_t len, size_t width){ const char *end = p + len; assert(len % width == 0);
for (; p < end; p += width) { switch (width) { case 1: fprintf(f, "%02"PRIx8, *(const uint8_t*)p); break; 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); }}
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){ 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;}
void property_add_marker(struct property *prop, enum markertype type, unsigned int offset, char *ref){ add_marker(&prop->val.markers, type, offset, ref);}
static void add_string_markers(struct property *prop, unsigned int offset, int len){ int l; const char *p = prop->val.val + offset; struct marker **mi = &prop->val.markers;
for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1) mi = add_marker(mi, TYPE_STRING, offset + l, NULL);}
void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset){ cell_t phandle; struct node *refn; char *ref;
if (prop->val.len < offset + 4) { if (quiet < 1) fprintf(stderr, "Warning: property %s too short to contain a phandle at offset %u\n", prop->name, offset); return; }
phandle = dtb_ld32(prop->val.val + offset); refn = get_node_by_phandle(dti->dt, phandle);
if (!refn) { if (quiet < 1) fprintf(stderr, "Warning: node referenced by phandle 0x%x in property %s not found\n", phandle, prop->name); return; }
if (refn->labels) ref = refn->labels->label; else ref = refn->fullpath;
add_marker(&prop->val.markers, REF_PHANDLE, offset, ref);}
static enum markertype guess_value_type(struct property *prop, unsigned int offset, int len){ const char *p = prop->val.val + offset; int nnotstring = 0, nnul = 0; int i;
for (i = 0; i < len; i++) { if (! isstring(p[i])) nnotstring++; if (p[i] == '\0') nnul++; }
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= len - nnul)) { if (nnul > 1) add_string_markers(prop, offset, len); return TYPE_STRING; } else if ((len % sizeof(cell_t)) == 0) { return TYPE_UINT32; }
return TYPE_UINT8;}
static void guess_type_markers(struct property *prop){ struct marker **m = &prop->val.markers; unsigned int offset = 0;
for (m = &prop->val.markers; *m; m = &((*m)->next)) { if (is_type_marker((*m)->type)) /* assume the whole property is already marked */ return;
if ((*m)->offset > offset) { m = add_marker(m, guess_value_type(prop, offset, (*m)->offset - offset), offset, NULL);
offset = (*m)->offset; }
if ((*m)->type == REF_PHANDLE) { m = add_marker(m, TYPE_UINT32, offset, NULL); offset += 4; } }
if (offset < prop->val.len) add_marker(m, guess_value_type(prop, offset, prop->val.len - offset), offset, NULL);}
static void write_propval(FILE *f, struct property *prop){ size_t len = prop->val.len; struct marker *m; 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, " =");
guess_type_markers(prop); m = prop->val.markers;
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){ 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 {", tree->name); else 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); for_each_label(prop->labels, l) fprintf(f, "%s: ", l->label); fprintf(f, "%s", prop->name); write_propval(f, prop); } for_each_child(tree, child) { fprintf(f, "\n"); write_tree_source_node(f, child, level+1); } write_prefix(f, level); 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 dt_info *dti){ struct reserve_info *re;
fprintf(f, "/dts-v1/;\n"); if (dti->dtsflags & DTSF_PLUGIN) fprintf(f, "/plugin/;\n"); fprintf(f, "\n");
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->address, (unsigned long long)re->size); }
write_tree_source_node(f, dti->dt, 0);}