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 void property_add_marker(struct property *prop, 177 enum markertype type, unsigned int offset, char *ref) 178 { 179 add_marker(&prop->val.markers, type, offset, ref); 180 } 181 182 static void add_string_markers(struct property *prop, unsigned int offset, int len) 183 { 184 int l; 185 const char *p = prop->val.val + offset; 186 struct marker **mi = &prop->val.markers; 187 188 for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1) 189 mi = add_marker(mi, TYPE_STRING, offset + l, NULL); 190 } 191 192 void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset) 193 { 194 cell_t phandle; 195 struct node *refn; 196 char *ref; 197 198 if (prop->val.len < offset + 4) { 199 if (quiet < 1) 200 fprintf(stderr, 201 "Warning: property %s too short to contain a phandle at offset %u\n", 202 prop->name, offset); 203 return; 204 } 205 206 phandle = dtb_ld32(prop->val.val + offset); 207 refn = get_node_by_phandle(dti->dt, phandle); 208 209 if (!refn) { 210 if (quiet < 1) 211 fprintf(stderr, 212 "Warning: node referenced by phandle 0x%x in property %s not found\n", 213 phandle, prop->name); 214 return; 215 } 216 217 if (refn->labels) 218 ref = refn->labels->label; 219 else 220 ref = refn->fullpath; 221 222 add_marker(&prop->val.markers, REF_PHANDLE, offset, ref); 223 } 224 225 static enum markertype guess_value_type(struct property *prop, unsigned int offset, int len) 226 { 227 const char *p = prop->val.val + offset; 228 int nnotstring = 0, nnul = 0; 229 int i; 230 231 for (i = 0; i < len; i++) { 232 if (! isstring(p[i])) 233 nnotstring++; 234 if (p[i] == '\0') 235 nnul++; 236 } 237 238 if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= len - nnul)) { 239 if (nnul > 1) 240 add_string_markers(prop, offset, len); 241 return TYPE_STRING; 242 } else if ((len % sizeof(cell_t)) == 0) { 243 return TYPE_UINT32; 244 } 245 246 return TYPE_UINT8; 247 } 248 249 static void guess_type_markers(struct property *prop) 250 { 251 struct marker **m = &prop->val.markers; 252 unsigned int offset = 0; 253 254 for (m = &prop->val.markers; *m; m = &((*m)->next)) { 255 if (is_type_marker((*m)->type)) 256 /* assume the whole property is already marked */ 257 return; 258 259 if ((*m)->offset > offset) { 260 m = add_marker(m, guess_value_type(prop, offset, (*m)->offset - offset), 261 offset, NULL); 262 263 offset = (*m)->offset; 264 } 265 266 if ((*m)->type == REF_PHANDLE) { 267 m = add_marker(m, TYPE_UINT32, offset, NULL); 268 offset += 4; 269 } 270 } 271 272 if (offset < prop->val.len) 273 add_marker(m, guess_value_type(prop, offset, prop->val.len - offset), 274 offset, NULL); 275 } 276 277 static void write_propval(FILE *f, struct property *prop) 278 { 279 size_t len = prop->val.len; 280 struct marker *m; 281 enum markertype emit_type = TYPE_NONE; 282 char *srcstr; 283 284 if (len == 0) { 285 fprintf(f, ";"); 286 if (annotate) { 287 srcstr = srcpos_string_first(prop->srcpos, annotate); 288 if (srcstr) { 289 fprintf(f, " /* %s */", srcstr); 290 free(srcstr); 291 } 292 } 293 fprintf(f, "\n"); 294 return; 295 } 296 297 fprintf(f, " ="); 298 299 guess_type_markers(prop); 300 m = prop->val.markers; 301 302 for_each_marker(m) { 303 size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; 304 size_t data_len = type_marker_length(m) ? : len - m->offset; 305 const char *p = &prop->val.val[m->offset]; 306 struct marker *m_phandle; 307 308 if (is_type_marker(m->type)) { 309 emit_type = m->type; 310 fprintf(f, " %s", delim_start[emit_type]); 311 } else if (m->type == LABEL) 312 fprintf(f, " %s:", m->ref); 313 314 if (emit_type == TYPE_NONE || chunk_len == 0) 315 continue; 316 317 switch(emit_type) { 318 case TYPE_UINT16: 319 write_propval_int(f, p, chunk_len, 2); 320 break; 321 case TYPE_UINT32: 322 m_phandle = prop->val.markers; 323 for_each_marker_of_type(m_phandle, REF_PHANDLE) 324 if (m->offset == m_phandle->offset) 325 break; 326 327 if (m_phandle) { 328 if (m_phandle->ref[0] == '/') 329 fprintf(f, "&{%s}", m_phandle->ref); 330 else 331 fprintf(f, "&%s", m_phandle->ref); 332 if (chunk_len > 4) { 333 fputc(' ', f); 334 write_propval_int(f, p + 4, chunk_len - 4, 4); 335 } 336 } else { 337 write_propval_int(f, p, chunk_len, 4); 338 } 339 if (data_len > chunk_len) 340 fputc(' ', f); 341 break; 342 case TYPE_UINT64: 343 write_propval_int(f, p, chunk_len, 8); 344 break; 345 case TYPE_STRING: 346 write_propval_string(f, p, chunk_len); 347 break; 348 default: 349 write_propval_int(f, p, chunk_len, 1); 350 } 351 352 if (chunk_len == data_len) { 353 size_t pos = m->offset + chunk_len; 354 fprintf(f, pos == len ? "%s" : "%s,", 355 delim_end[emit_type] ? : ""); 356 emit_type = TYPE_NONE; 357 } 358 } 359 fprintf(f, ";"); 360 if (annotate) { 361 srcstr = srcpos_string_first(prop->srcpos, annotate); 362 if (srcstr) { 363 fprintf(f, " /* %s */", srcstr); 364 free(srcstr); 365 } 366 } 367 fprintf(f, "\n"); 368 } 369 370 static void write_tree_source_node(FILE *f, struct node *tree, int level) 371 { 372 struct property *prop; 373 struct node *child; 374 struct label *l; 375 char *srcstr; 376 377 write_prefix(f, level); 378 for_each_label(tree->labels, l) 379 fprintf(f, "%s: ", l->label); 380 if (tree->name && (*tree->name)) 381 fprintf(f, "%s {", tree->name); 382 else 383 fprintf(f, "/ {"); 384 385 if (annotate) { 386 srcstr = srcpos_string_first(tree->srcpos, annotate); 387 if (srcstr) { 388 fprintf(f, " /* %s */", srcstr); 389 free(srcstr); 390 } 391 } 392 fprintf(f, "\n"); 393 394 for_each_property(tree, prop) { 395 write_prefix(f, level+1); 396 for_each_label(prop->labels, l) 397 fprintf(f, "%s: ", l->label); 398 fprintf(f, "%s", prop->name); 399 write_propval(f, prop); 400 } 401 for_each_child(tree, child) { 402 fprintf(f, "\n"); 403 write_tree_source_node(f, child, level+1); 404 } 405 write_prefix(f, level); 406 fprintf(f, "};"); 407 if (annotate) { 408 srcstr = srcpos_string_last(tree->srcpos, annotate); 409 if (srcstr) { 410 fprintf(f, " /* %s */", srcstr); 411 free(srcstr); 412 } 413 } 414 fprintf(f, "\n"); 415 } 416 417 void dt_to_source(FILE *f, struct dt_info *dti) 418 { 419 struct reserve_info *re; 420 421 fprintf(f, "/dts-v1/;\n"); 422 if (dti->dtsflags & DTSF_PLUGIN) 423 fprintf(f, "/plugin/;\n"); 424 fprintf(f, "\n"); 425 426 for (re = dti->reservelist; re; re = re->next) { 427 struct label *l; 428 429 for_each_label(re->labels, l) 430 fprintf(f, "%s: ", l->label); 431 fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", 432 (unsigned long long)re->address, 433 (unsigned long long)re->size); 434 } 435 436 write_tree_source_node(f, dti->dt, 0); 437 } 438