1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. 4 */ 5 6 #include "dtc.h" 7 #include "srcpos.h" 8 9 extern FILE *yyin; 10 extern int yyparse(void); 11 extern YYLTYPE yylloc; 12 13 struct dt_info *parser_output; 14 bool treesource_error; 15 16 struct dt_info *dt_from_source(const char *fname) 17 { 18 parser_output = NULL; 19 treesource_error = false; 20 21 srcfile_push(fname); 22 yyin = current_srcfile->f; 23 yylloc.file = current_srcfile; 24 25 if (yyparse() != 0) 26 die("Unable to parse input tree\n"); 27 28 if (treesource_error) 29 die("Syntax error parsing input tree\n"); 30 31 return parser_output; 32 } 33 34 static void write_prefix(FILE *f, int level) 35 { 36 int i; 37 38 for (i = 0; i < level; i++) 39 fputc('\t', f); 40 } 41 42 static bool isstring(char c) 43 { 44 return (isprint((unsigned char)c) 45 || (c == '\0') 46 || strchr("\a\b\t\n\v\f\r", c)); 47 } 48 49 static void write_propval_string(FILE *f, const char *s, size_t len) 50 { 51 const char *end = s + len - 1; 52 53 if (!len) 54 return; 55 56 assert(*end == '\0'); 57 58 fprintf(f, "\""); 59 while (s < end) { 60 char c = *s++; 61 switch (c) { 62 case '\a': 63 fprintf(f, "\\a"); 64 break; 65 case '\b': 66 fprintf(f, "\\b"); 67 break; 68 case '\t': 69 fprintf(f, "\\t"); 70 break; 71 case '\n': 72 fprintf(f, "\\n"); 73 break; 74 case '\v': 75 fprintf(f, "\\v"); 76 break; 77 case '\f': 78 fprintf(f, "\\f"); 79 break; 80 case '\r': 81 fprintf(f, "\\r"); 82 break; 83 case '\\': 84 fprintf(f, "\\\\"); 85 break; 86 case '\"': 87 fprintf(f, "\\\""); 88 break; 89 case '\0': 90 fprintf(f, "\\0"); 91 break; 92 default: 93 if (isprint((unsigned char)c)) 94 fprintf(f, "%c", c); 95 else 96 fprintf(f, "\\x%02"PRIx8, c); 97 } 98 } 99 fprintf(f, "\""); 100 } 101 102 static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) 103 { 104 const char *end = p + len; 105 assert(len % width == 0); 106 107 for (; p < end; p += width) { 108 switch (width) { 109 case 1: 110 fprintf(f, "%02"PRIx8, *(const uint8_t*)p); 111 break; 112 case 2: 113 fprintf(f, "0x%02"PRIx16, dtb_ld16(p)); 114 break; 115 case 4: 116 fprintf(f, "0x%02"PRIx32, dtb_ld32(p)); 117 break; 118 case 8: 119 fprintf(f, "0x%02"PRIx64, dtb_ld64(p)); 120 break; 121 } 122 if (p + width < end) 123 fputc(' ', f); 124 } 125 } 126 127 static const char *delim_start[] = { 128 [TYPE_UINT8] = "[", 129 [TYPE_UINT16] = "/bits/ 16 <", 130 [TYPE_UINT32] = "<", 131 [TYPE_UINT64] = "/bits/ 64 <", 132 [TYPE_STRING] = "", 133 }; 134 static const char *delim_end[] = { 135 [TYPE_UINT8] = "]", 136 [TYPE_UINT16] = ">", 137 [TYPE_UINT32] = ">", 138 [TYPE_UINT64] = ">", 139 [TYPE_STRING] = "", 140 }; 141 142 /* 143 * The invariants in the marker list are: 144 * - offsets are non-strictly monotonically increasing 145 * - for a single offset there is at most one type marker 146 * - for a single offset that has both a type marker and non-type markers, the 147 * type marker appears before the others. 148 */ 149 static struct marker **add_marker(struct marker **mi, 150 enum markertype type, unsigned int offset, char *ref) 151 { 152 struct marker *nm; 153 154 while (*mi && (*mi)->offset < offset) 155 mi = &(*mi)->next; 156 157 if (*mi && (*mi)->offset == offset && is_type_marker((*mi)->type)) { 158 if (is_type_marker(type)) 159 return mi; 160 mi = &(*mi)->next; 161 } 162 163 if (*mi && (*mi)->offset == offset && type == (*mi)->type) 164 return mi; 165 166 nm = xmalloc(sizeof(*nm)); 167 nm->type = type; 168 nm->offset = offset; 169 nm->ref = ref; 170 nm->next = *mi; 171 *mi = nm; 172 173 return &nm->next; 174 } 175 176 static void add_string_markers(struct property *prop) 177 { 178 int l, len = prop->val.len; 179 const char *p = prop->val.val; 180 struct marker **mi = &prop->val.markers; 181 182 for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1) 183 mi = add_marker(mi, TYPE_STRING, l, NULL); 184 } 185 186 static enum markertype guess_value_type(struct property *prop) 187 { 188 int len = prop->val.len; 189 const char *p = prop->val.val; 190 struct marker *m = prop->val.markers; 191 int nnotstring = 0, nnul = 0; 192 int nnotstringlbl = 0, nnotcelllbl = 0; 193 int i; 194 195 for (i = 0; i < len; i++) { 196 if (! isstring(p[i])) 197 nnotstring++; 198 if (p[i] == '\0') 199 nnul++; 200 } 201 202 for_each_marker_of_type(m, LABEL) { 203 if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0')) 204 nnotstringlbl++; 205 if ((m->offset % sizeof(cell_t)) != 0) 206 nnotcelllbl++; 207 } 208 209 if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul)) 210 && (nnotstringlbl == 0)) { 211 if (nnul > 1) 212 add_string_markers(prop); 213 return TYPE_STRING; 214 } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { 215 return TYPE_UINT32; 216 } 217 218 return TYPE_UINT8; 219 } 220 221 static void write_propval(FILE *f, struct property *prop) 222 { 223 size_t len = prop->val.len; 224 struct marker *m = prop->val.markers; 225 struct marker dummy_marker; 226 enum markertype emit_type = TYPE_NONE; 227 char *srcstr; 228 229 if (len == 0) { 230 fprintf(f, ";"); 231 if (annotate) { 232 srcstr = srcpos_string_first(prop->srcpos, annotate); 233 if (srcstr) { 234 fprintf(f, " /* %s */", srcstr); 235 free(srcstr); 236 } 237 } 238 fprintf(f, "\n"); 239 return; 240 } 241 242 fprintf(f, " ="); 243 244 if (!next_type_marker(m)) { 245 /* data type information missing, need to guess */ 246 dummy_marker.type = guess_value_type(prop); 247 dummy_marker.next = prop->val.markers; 248 dummy_marker.offset = 0; 249 dummy_marker.ref = NULL; 250 m = &dummy_marker; 251 } 252 253 for_each_marker(m) { 254 size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; 255 size_t data_len = type_marker_length(m) ? : len - m->offset; 256 const char *p = &prop->val.val[m->offset]; 257 struct marker *m_phandle; 258 259 if (is_type_marker(m->type)) { 260 emit_type = m->type; 261 fprintf(f, " %s", delim_start[emit_type]); 262 } else if (m->type == LABEL) 263 fprintf(f, " %s:", m->ref); 264 265 if (emit_type == TYPE_NONE || chunk_len == 0) 266 continue; 267 268 switch(emit_type) { 269 case TYPE_UINT16: 270 write_propval_int(f, p, chunk_len, 2); 271 break; 272 case TYPE_UINT32: 273 m_phandle = prop->val.markers; 274 for_each_marker_of_type(m_phandle, REF_PHANDLE) 275 if (m->offset == m_phandle->offset) 276 break; 277 278 if (m_phandle) { 279 if (m_phandle->ref[0] == '/') 280 fprintf(f, "&{%s}", m_phandle->ref); 281 else 282 fprintf(f, "&%s", m_phandle->ref); 283 if (chunk_len > 4) { 284 fputc(' ', f); 285 write_propval_int(f, p + 4, chunk_len - 4, 4); 286 } 287 } else { 288 write_propval_int(f, p, chunk_len, 4); 289 } 290 if (data_len > chunk_len) 291 fputc(' ', f); 292 break; 293 case TYPE_UINT64: 294 write_propval_int(f, p, chunk_len, 8); 295 break; 296 case TYPE_STRING: 297 write_propval_string(f, p, chunk_len); 298 break; 299 default: 300 write_propval_int(f, p, chunk_len, 1); 301 } 302 303 if (chunk_len == data_len) { 304 size_t pos = m->offset + chunk_len; 305 fprintf(f, pos == len ? "%s" : "%s,", 306 delim_end[emit_type] ? : ""); 307 emit_type = TYPE_NONE; 308 } 309 } 310 fprintf(f, ";"); 311 if (annotate) { 312 srcstr = srcpos_string_first(prop->srcpos, annotate); 313 if (srcstr) { 314 fprintf(f, " /* %s */", srcstr); 315 free(srcstr); 316 } 317 } 318 fprintf(f, "\n"); 319 } 320 321 static void write_tree_source_node(FILE *f, struct node *tree, int level) 322 { 323 struct property *prop; 324 struct node *child; 325 struct label *l; 326 char *srcstr; 327 328 write_prefix(f, level); 329 for_each_label(tree->labels, l) 330 fprintf(f, "%s: ", l->label); 331 if (tree->name && (*tree->name)) 332 fprintf(f, "%s {", tree->name); 333 else 334 fprintf(f, "/ {"); 335 336 if (annotate) { 337 srcstr = srcpos_string_first(tree->srcpos, annotate); 338 if (srcstr) { 339 fprintf(f, " /* %s */", srcstr); 340 free(srcstr); 341 } 342 } 343 fprintf(f, "\n"); 344 345 for_each_property(tree, prop) { 346 write_prefix(f, level+1); 347 for_each_label(prop->labels, l) 348 fprintf(f, "%s: ", l->label); 349 fprintf(f, "%s", prop->name); 350 write_propval(f, prop); 351 } 352 for_each_child(tree, child) { 353 fprintf(f, "\n"); 354 write_tree_source_node(f, child, level+1); 355 } 356 write_prefix(f, level); 357 fprintf(f, "};"); 358 if (annotate) { 359 srcstr = srcpos_string_last(tree->srcpos, annotate); 360 if (srcstr) { 361 fprintf(f, " /* %s */", srcstr); 362 free(srcstr); 363 } 364 } 365 fprintf(f, "\n"); 366 } 367 368 void dt_to_source(FILE *f, struct dt_info *dti) 369 { 370 struct reserve_info *re; 371 372 fprintf(f, "/dts-v1/;\n\n"); 373 374 for (re = dti->reservelist; re; re = re->next) { 375 struct label *l; 376 377 for_each_label(re->labels, l) 378 fprintf(f, "%s: ", l->label); 379 fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", 380 (unsigned long long)re->address, 381 (unsigned long long)re->size); 382 } 383 384 write_tree_source_node(f, dti->dt, 0); 385 } 386