Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
a4da2e3e DG |
2 | /* |
3 | * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. | |
a4da2e3e DG |
4 | */ |
5 | ||
6 | #include "dtc.h" | |
7 | #include "srcpos.h" | |
8 | ||
9 | extern FILE *yyin; | |
10 | extern int yyparse(void); | |
cd296721 | 11 | extern YYLTYPE yylloc; |
a4da2e3e | 12 | |
6f05afcb | 13 | struct dt_info *parser_output; |
47605971 | 14 | bool treesource_error; |
a4da2e3e | 15 | |
6f05afcb | 16 | struct dt_info *dt_from_source(const char *fname) |
a4da2e3e | 17 | { |
6f05afcb | 18 | parser_output = NULL; |
47605971 | 19 | treesource_error = false; |
a4da2e3e | 20 | |
658f29a5 JB |
21 | srcfile_push(fname); |
22 | yyin = current_srcfile->f; | |
cd296721 | 23 | yylloc.file = current_srcfile; |
a4da2e3e DG |
24 | |
25 | if (yyparse() != 0) | |
ed95d745 | 26 | die("Unable to parse input tree\n"); |
a4da2e3e | 27 | |
ed95d745 DG |
28 | if (treesource_error) |
29 | die("Syntax error parsing input tree\n"); | |
a4da2e3e | 30 | |
6f05afcb | 31 | return parser_output; |
a4da2e3e DG |
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 | ||
47605971 | 42 | static bool isstring(char c) |
a4da2e3e | 43 | { |
47605971 | 44 | return (isprint((unsigned char)c) |
a4da2e3e DG |
45 | || (c == '\0') |
46 | || strchr("\a\b\t\n\v\f\r", c)); | |
47 | } | |
48 | ||
f858927f | 49 | static void write_propval_string(FILE *f, const char *s, size_t len) |
a4da2e3e | 50 | { |
f858927f | 51 | const char *end = s + len - 1; |
c2e7075c RH |
52 | |
53 | if (!len) | |
54 | return; | |
55 | ||
f858927f | 56 | assert(*end == '\0'); |
a4da2e3e | 57 | |
658f29a5 | 58 | fprintf(f, "\""); |
f858927f RH |
59 | while (s < end) { |
60 | char c = *s++; | |
a4da2e3e DG |
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': | |
f858927f | 90 | fprintf(f, "\\0"); |
a4da2e3e DG |
91 | break; |
92 | default: | |
47605971 | 93 | if (isprint((unsigned char)c)) |
a4da2e3e DG |
94 | fprintf(f, "%c", c); |
95 | else | |
f858927f | 96 | fprintf(f, "\\x%02"PRIx8, c); |
a4da2e3e DG |
97 | } |
98 | } | |
99 | fprintf(f, "\""); | |
a4da2e3e DG |
100 | } |
101 | ||
f858927f | 102 | static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) |
a4da2e3e | 103 | { |
f858927f RH |
104 | const char *end = p + len; |
105 | assert(len % width == 0); | |
a4da2e3e | 106 | |
f858927f RH |
107 | for (; p < end; p += width) { |
108 | switch (width) { | |
109 | case 1: | |
c2e7075c | 110 | fprintf(f, "%02"PRIx8, *(const uint8_t*)p); |
f858927f RH |
111 | break; |
112 | case 2: | |
c2e7075c | 113 | fprintf(f, "0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p)); |
f858927f RH |
114 | break; |
115 | case 4: | |
c2e7075c | 116 | fprintf(f, "0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p)); |
f858927f RH |
117 | break; |
118 | case 8: | |
c2e7075c | 119 | fprintf(f, "0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p)); |
a4da2e3e | 120 | break; |
f858927f | 121 | } |
c2e7075c RH |
122 | if (p + width < end) |
123 | fputc(' ', f); | |
a4da2e3e | 124 | } |
f858927f | 125 | } |
a4da2e3e | 126 | |
f858927f RH |
127 | static bool has_data_type_information(struct marker *m) |
128 | { | |
129 | return m->type >= TYPE_UINT8; | |
a4da2e3e DG |
130 | } |
131 | ||
f858927f | 132 | static struct marker *next_type_marker(struct marker *m) |
a4da2e3e | 133 | { |
f858927f RH |
134 | while (m && !has_data_type_information(m)) |
135 | m = m->next; | |
136 | return m; | |
137 | } | |
a4da2e3e | 138 | |
f858927f RH |
139 | size_t type_marker_length(struct marker *m) |
140 | { | |
141 | struct marker *next = next_type_marker(m->next); | |
a4da2e3e | 142 | |
f858927f RH |
143 | if (next) |
144 | return next->offset - m->offset; | |
145 | return 0; | |
a4da2e3e DG |
146 | } |
147 | ||
f858927f RH |
148 | static const char *delim_start[] = { |
149 | [TYPE_UINT8] = "[", | |
150 | [TYPE_UINT16] = "/bits/ 16 <", | |
151 | [TYPE_UINT32] = "<", | |
152 | [TYPE_UINT64] = "/bits/ 64 <", | |
153 | [TYPE_STRING] = "", | |
154 | }; | |
155 | static const char *delim_end[] = { | |
c2e7075c RH |
156 | [TYPE_UINT8] = "]", |
157 | [TYPE_UINT16] = ">", | |
158 | [TYPE_UINT32] = ">", | |
159 | [TYPE_UINT64] = ">", | |
f858927f RH |
160 | [TYPE_STRING] = "", |
161 | }; | |
162 | ||
163 | static enum markertype guess_value_type(struct property *prop) | |
a4da2e3e DG |
164 | { |
165 | int len = prop->val.len; | |
166 | const char *p = prop->val.val; | |
167 | struct marker *m = prop->val.markers; | |
168 | int nnotstring = 0, nnul = 0; | |
169 | int nnotstringlbl = 0, nnotcelllbl = 0; | |
170 | int i; | |
171 | ||
a4da2e3e DG |
172 | for (i = 0; i < len; i++) { |
173 | if (! isstring(p[i])) | |
174 | nnotstring++; | |
175 | if (p[i] == '\0') | |
176 | nnul++; | |
177 | } | |
178 | ||
179 | for_each_marker_of_type(m, LABEL) { | |
180 | if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0')) | |
181 | nnotstringlbl++; | |
182 | if ((m->offset % sizeof(cell_t)) != 0) | |
183 | nnotcelllbl++; | |
184 | } | |
185 | ||
a4da2e3e DG |
186 | if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul)) |
187 | && (nnotstringlbl == 0)) { | |
f858927f | 188 | return TYPE_STRING; |
a4da2e3e | 189 | } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { |
f858927f | 190 | return TYPE_UINT32; |
a4da2e3e DG |
191 | } |
192 | ||
f858927f RH |
193 | return TYPE_UINT8; |
194 | } | |
195 | ||
196 | static void write_propval(FILE *f, struct property *prop) | |
197 | { | |
198 | size_t len = prop->val.len; | |
199 | struct marker *m = prop->val.markers; | |
200 | struct marker dummy_marker; | |
201 | enum markertype emit_type = TYPE_NONE; | |
c2e7075c | 202 | char *srcstr; |
f858927f RH |
203 | |
204 | if (len == 0) { | |
c2e7075c RH |
205 | fprintf(f, ";"); |
206 | if (annotate) { | |
207 | srcstr = srcpos_string_first(prop->srcpos, annotate); | |
208 | if (srcstr) { | |
209 | fprintf(f, " /* %s */", srcstr); | |
210 | free(srcstr); | |
211 | } | |
212 | } | |
213 | fprintf(f, "\n"); | |
f858927f RH |
214 | return; |
215 | } | |
216 | ||
c2e7075c | 217 | fprintf(f, " ="); |
f858927f RH |
218 | |
219 | if (!next_type_marker(m)) { | |
220 | /* data type information missing, need to guess */ | |
221 | dummy_marker.type = guess_value_type(prop); | |
222 | dummy_marker.next = prop->val.markers; | |
223 | dummy_marker.offset = 0; | |
224 | dummy_marker.ref = NULL; | |
225 | m = &dummy_marker; | |
226 | } | |
227 | ||
f858927f | 228 | for_each_marker(m) { |
c2e7075c RH |
229 | size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; |
230 | size_t data_len = type_marker_length(m) ? : len - m->offset; | |
f858927f RH |
231 | const char *p = &prop->val.val[m->offset]; |
232 | ||
c2e7075c RH |
233 | if (has_data_type_information(m)) { |
234 | emit_type = m->type; | |
235 | fprintf(f, " %s", delim_start[emit_type]); | |
236 | } else if (m->type == LABEL) | |
237 | fprintf(f, " %s:", m->ref); | |
238 | else if (m->offset) | |
239 | fputc(' ', f); | |
f858927f | 240 | |
c2e7075c RH |
241 | if (emit_type == TYPE_NONE) { |
242 | assert(chunk_len == 0); | |
f858927f | 243 | continue; |
c2e7075c | 244 | } |
f858927f RH |
245 | |
246 | switch(emit_type) { | |
247 | case TYPE_UINT16: | |
248 | write_propval_int(f, p, chunk_len, 2); | |
249 | break; | |
250 | case TYPE_UINT32: | |
251 | write_propval_int(f, p, chunk_len, 4); | |
252 | break; | |
253 | case TYPE_UINT64: | |
254 | write_propval_int(f, p, chunk_len, 8); | |
255 | break; | |
256 | case TYPE_STRING: | |
257 | write_propval_string(f, p, chunk_len); | |
258 | break; | |
259 | default: | |
260 | write_propval_int(f, p, chunk_len, 1); | |
261 | } | |
f858927f | 262 | |
c2e7075c RH |
263 | if (chunk_len == data_len) { |
264 | size_t pos = m->offset + chunk_len; | |
265 | fprintf(f, pos == len ? "%s" : "%s,", | |
266 | delim_end[emit_type] ? : ""); | |
267 | emit_type = TYPE_NONE; | |
268 | } | |
f858927f | 269 | } |
c2e7075c RH |
270 | fprintf(f, ";"); |
271 | if (annotate) { | |
272 | srcstr = srcpos_string_first(prop->srcpos, annotate); | |
273 | if (srcstr) { | |
274 | fprintf(f, " /* %s */", srcstr); | |
275 | free(srcstr); | |
276 | } | |
277 | } | |
278 | fprintf(f, "\n"); | |
a4da2e3e DG |
279 | } |
280 | ||
281 | static void write_tree_source_node(FILE *f, struct node *tree, int level) | |
282 | { | |
283 | struct property *prop; | |
284 | struct node *child; | |
658f29a5 | 285 | struct label *l; |
c2e7075c | 286 | char *srcstr; |
a4da2e3e DG |
287 | |
288 | write_prefix(f, level); | |
658f29a5 JB |
289 | for_each_label(tree->labels, l) |
290 | fprintf(f, "%s: ", l->label); | |
a4da2e3e | 291 | if (tree->name && (*tree->name)) |
c2e7075c | 292 | fprintf(f, "%s {", tree->name); |
a4da2e3e | 293 | else |
c2e7075c RH |
294 | fprintf(f, "/ {"); |
295 | ||
296 | if (annotate) { | |
297 | srcstr = srcpos_string_first(tree->srcpos, annotate); | |
298 | if (srcstr) { | |
299 | fprintf(f, " /* %s */", srcstr); | |
300 | free(srcstr); | |
301 | } | |
302 | } | |
303 | fprintf(f, "\n"); | |
a4da2e3e DG |
304 | |
305 | for_each_property(tree, prop) { | |
306 | write_prefix(f, level+1); | |
658f29a5 JB |
307 | for_each_label(prop->labels, l) |
308 | fprintf(f, "%s: ", l->label); | |
a4da2e3e DG |
309 | fprintf(f, "%s", prop->name); |
310 | write_propval(f, prop); | |
311 | } | |
312 | for_each_child(tree, child) { | |
313 | fprintf(f, "\n"); | |
314 | write_tree_source_node(f, child, level+1); | |
315 | } | |
316 | write_prefix(f, level); | |
c2e7075c RH |
317 | fprintf(f, "};"); |
318 | if (annotate) { | |
319 | srcstr = srcpos_string_last(tree->srcpos, annotate); | |
320 | if (srcstr) { | |
321 | fprintf(f, " /* %s */", srcstr); | |
322 | free(srcstr); | |
323 | } | |
324 | } | |
325 | fprintf(f, "\n"); | |
a4da2e3e DG |
326 | } |
327 | ||
6f05afcb | 328 | void dt_to_source(FILE *f, struct dt_info *dti) |
a4da2e3e DG |
329 | { |
330 | struct reserve_info *re; | |
331 | ||
332 | fprintf(f, "/dts-v1/;\n\n"); | |
333 | ||
6f05afcb | 334 | for (re = dti->reservelist; re; re = re->next) { |
658f29a5 JB |
335 | struct label *l; |
336 | ||
337 | for_each_label(re->labels, l) | |
338 | fprintf(f, "%s: ", l->label); | |
a4da2e3e | 339 | fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", |
89d12310 RH |
340 | (unsigned long long)re->address, |
341 | (unsigned long long)re->size); | |
a4da2e3e DG |
342 | } |
343 | ||
6f05afcb | 344 | write_tree_source_node(f, dti->dt, 0); |
a4da2e3e | 345 | } |