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(str: "Unable to parse input tree\n" ); |
27 | |
28 | if (treesource_error) |
29 | die(str: "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(c: '\t', stream: f); |
40 | } |
41 | |
42 | static bool isstring(char c) |
43 | { |
44 | return (isprint((unsigned char)c) |
45 | || (c == '\0') |
46 | || strchr(s: "\a\b\t\n\v\f\r" , c: 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(stream: f, format: "\"" ); |
59 | while (s < end) { |
60 | char c = *s++; |
61 | switch (c) { |
62 | case '\a': |
63 | fprintf(stream: f, format: "\\a" ); |
64 | break; |
65 | case '\b': |
66 | fprintf(stream: f, format: "\\b" ); |
67 | break; |
68 | case '\t': |
69 | fprintf(stream: f, format: "\\t" ); |
70 | break; |
71 | case '\n': |
72 | fprintf(stream: f, format: "\\n" ); |
73 | break; |
74 | case '\v': |
75 | fprintf(stream: f, format: "\\v" ); |
76 | break; |
77 | case '\f': |
78 | fprintf(stream: f, format: "\\f" ); |
79 | break; |
80 | case '\r': |
81 | fprintf(stream: f, format: "\\r" ); |
82 | break; |
83 | case '\\': |
84 | fprintf(stream: f, format: "\\\\" ); |
85 | break; |
86 | case '\"': |
87 | fprintf(stream: f, format: "\\\"" ); |
88 | break; |
89 | case '\0': |
90 | fprintf(stream: f, format: "\\0" ); |
91 | break; |
92 | default: |
93 | if (isprint((unsigned char)c)) |
94 | fprintf(stream: f, format: "%c" , c); |
95 | else |
96 | fprintf(stream: f, format: "\\x%02" PRIx8, c); |
97 | } |
98 | } |
99 | fprintf(stream: f, format: "\"" ); |
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(stream: f, format: "%02" PRIx8, *(const uint8_t*)p); |
111 | break; |
112 | case 2: |
113 | fprintf(stream: f, format: "0x%02" PRIx16, dtb_ld16(p)); |
114 | break; |
115 | case 4: |
116 | fprintf(stream: f, format: "0x%02" PRIx32, dtb_ld32(p)); |
117 | break; |
118 | case 8: |
119 | fprintf(stream: f, format: "0x%02" PRIx64, dtb_ld64(p)); |
120 | break; |
121 | } |
122 | if (p + width < end) |
123 | fputc(c: ' ', stream: 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 | static enum markertype guess_value_type(struct property *prop) |
143 | { |
144 | int len = prop->val.len; |
145 | const char *p = prop->val.val; |
146 | struct marker *m = prop->val.markers; |
147 | int nnotstring = 0, nnul = 0; |
148 | int nnotstringlbl = 0, nnotcelllbl = 0; |
149 | int i; |
150 | |
151 | for (i = 0; i < len; i++) { |
152 | if (! isstring(c: p[i])) |
153 | nnotstring++; |
154 | if (p[i] == '\0') |
155 | nnul++; |
156 | } |
157 | |
158 | for_each_marker_of_type(m, LABEL) { |
159 | if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0')) |
160 | nnotstringlbl++; |
161 | if ((m->offset % sizeof(cell_t)) != 0) |
162 | nnotcelllbl++; |
163 | } |
164 | |
165 | if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul)) |
166 | && (nnotstringlbl == 0)) { |
167 | return TYPE_STRING; |
168 | } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { |
169 | return TYPE_UINT32; |
170 | } |
171 | |
172 | return TYPE_UINT8; |
173 | } |
174 | |
175 | static void write_propval(FILE *f, struct property *prop) |
176 | { |
177 | size_t len = prop->val.len; |
178 | struct marker *m = prop->val.markers; |
179 | struct marker dummy_marker; |
180 | enum markertype emit_type = TYPE_NONE; |
181 | char *srcstr; |
182 | |
183 | if (len == 0) { |
184 | fprintf(stream: f, format: ";" ); |
185 | if (annotate) { |
186 | srcstr = srcpos_string_first(pos: prop->srcpos, level: annotate); |
187 | if (srcstr) { |
188 | fprintf(stream: f, format: " /* %s */" , srcstr); |
189 | free(ptr: srcstr); |
190 | } |
191 | } |
192 | fprintf(stream: f, format: "\n" ); |
193 | return; |
194 | } |
195 | |
196 | fprintf(stream: f, format: " =" ); |
197 | |
198 | if (!next_type_marker(m)) { |
199 | /* data type information missing, need to guess */ |
200 | dummy_marker.type = guess_value_type(prop); |
201 | dummy_marker.next = prop->val.markers; |
202 | dummy_marker.offset = 0; |
203 | dummy_marker.ref = NULL; |
204 | m = &dummy_marker; |
205 | } |
206 | |
207 | for_each_marker(m) { |
208 | size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; |
209 | size_t data_len = type_marker_length(m) ? : len - m->offset; |
210 | const char *p = &prop->val.val[m->offset]; |
211 | struct marker *m_phandle; |
212 | |
213 | if (is_type_marker(type: m->type)) { |
214 | emit_type = m->type; |
215 | fprintf(stream: f, format: " %s" , delim_start[emit_type]); |
216 | } else if (m->type == LABEL) |
217 | fprintf(stream: f, format: " %s:" , m->ref); |
218 | |
219 | if (emit_type == TYPE_NONE || chunk_len == 0) |
220 | continue; |
221 | |
222 | switch(emit_type) { |
223 | case TYPE_UINT16: |
224 | write_propval_int(f, p, len: chunk_len, width: 2); |
225 | break; |
226 | case TYPE_UINT32: |
227 | m_phandle = prop->val.markers; |
228 | for_each_marker_of_type(m_phandle, REF_PHANDLE) |
229 | if (m->offset == m_phandle->offset) |
230 | break; |
231 | |
232 | if (m_phandle) { |
233 | if (m_phandle->ref[0] == '/') |
234 | fprintf(stream: f, format: "&{%s}" , m_phandle->ref); |
235 | else |
236 | fprintf(stream: f, format: "&%s" , m_phandle->ref); |
237 | if (chunk_len > 4) { |
238 | fputc(c: ' ', stream: f); |
239 | write_propval_int(f, p: p + 4, len: chunk_len - 4, width: 4); |
240 | } |
241 | } else { |
242 | write_propval_int(f, p, len: chunk_len, width: 4); |
243 | } |
244 | break; |
245 | case TYPE_UINT64: |
246 | write_propval_int(f, p, len: chunk_len, width: 8); |
247 | break; |
248 | case TYPE_STRING: |
249 | write_propval_string(f, s: p, len: chunk_len); |
250 | break; |
251 | default: |
252 | write_propval_int(f, p, len: chunk_len, width: 1); |
253 | } |
254 | |
255 | if (chunk_len == data_len) { |
256 | size_t pos = m->offset + chunk_len; |
257 | fprintf(stream: f, format: pos == len ? "%s" : "%s," , |
258 | delim_end[emit_type] ? : "" ); |
259 | emit_type = TYPE_NONE; |
260 | } |
261 | } |
262 | fprintf(stream: f, format: ";" ); |
263 | if (annotate) { |
264 | srcstr = srcpos_string_first(pos: prop->srcpos, level: annotate); |
265 | if (srcstr) { |
266 | fprintf(stream: f, format: " /* %s */" , srcstr); |
267 | free(ptr: srcstr); |
268 | } |
269 | } |
270 | fprintf(stream: f, format: "\n" ); |
271 | } |
272 | |
273 | static void write_tree_source_node(FILE *f, struct node *tree, int level) |
274 | { |
275 | struct property *prop; |
276 | struct node *child; |
277 | struct label *l; |
278 | char *srcstr; |
279 | |
280 | write_prefix(f, level); |
281 | for_each_label(tree->labels, l) |
282 | fprintf(stream: f, format: "%s: " , l->label); |
283 | if (tree->name && (*tree->name)) |
284 | fprintf(stream: f, format: "%s {" , tree->name); |
285 | else |
286 | fprintf(stream: f, format: "/ {" ); |
287 | |
288 | if (annotate) { |
289 | srcstr = srcpos_string_first(pos: tree->srcpos, level: annotate); |
290 | if (srcstr) { |
291 | fprintf(stream: f, format: " /* %s */" , srcstr); |
292 | free(ptr: srcstr); |
293 | } |
294 | } |
295 | fprintf(stream: f, format: "\n" ); |
296 | |
297 | for_each_property(tree, prop) { |
298 | write_prefix(f, level: level+1); |
299 | for_each_label(prop->labels, l) |
300 | fprintf(stream: f, format: "%s: " , l->label); |
301 | fprintf(stream: f, format: "%s" , prop->name); |
302 | write_propval(f, prop); |
303 | } |
304 | for_each_child(tree, child) { |
305 | fprintf(stream: f, format: "\n" ); |
306 | write_tree_source_node(f, tree: child, level: level+1); |
307 | } |
308 | write_prefix(f, level); |
309 | fprintf(stream: f, format: "};" ); |
310 | if (annotate) { |
311 | srcstr = srcpos_string_last(pos: tree->srcpos, level: annotate); |
312 | if (srcstr) { |
313 | fprintf(stream: f, format: " /* %s */" , srcstr); |
314 | free(ptr: srcstr); |
315 | } |
316 | } |
317 | fprintf(stream: f, format: "\n" ); |
318 | } |
319 | |
320 | void dt_to_source(FILE *f, struct dt_info *dti) |
321 | { |
322 | struct reserve_info *re; |
323 | |
324 | fprintf(stream: f, format: "/dts-v1/;\n\n" ); |
325 | |
326 | for (re = dti->reservelist; re; re = re->next) { |
327 | struct label *l; |
328 | |
329 | for_each_label(re->labels, l) |
330 | fprintf(stream: f, format: "%s: " , l->label); |
331 | fprintf(stream: f, format: "/memreserve/\t0x%016llx 0x%016llx;\n" , |
332 | (unsigned long long)re->address, |
333 | (unsigned long long)re->size); |
334 | } |
335 | |
336 | write_tree_source_node(f, tree: dti->dt, level: 0); |
337 | } |
338 | |