Merge branch 'for-5.14/core' into for-linus
[platform/kernel/linux-rpi.git] / scripts / dtc / treesource.c
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 bool has_data_type_information(struct marker *m)
128 {
129         return m->type >= TYPE_UINT8;
130 }
131
132 static struct marker *next_type_marker(struct marker *m)
133 {
134         while (m && !has_data_type_information(m))
135                 m = m->next;
136         return m;
137 }
138
139 size_t type_marker_length(struct marker *m)
140 {
141         struct marker *next = next_type_marker(m->next);
142
143         if (next)
144                 return next->offset - m->offset;
145         return 0;
146 }
147
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[] = {
156         [TYPE_UINT8] = "]",
157         [TYPE_UINT16] = ">",
158         [TYPE_UINT32] = ">",
159         [TYPE_UINT64] = ">",
160         [TYPE_STRING] = "",
161 };
162
163 static enum markertype guess_value_type(struct property *prop)
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
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
186         if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
187             && (nnotstringlbl == 0)) {
188                 return TYPE_STRING;
189         } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
190                 return TYPE_UINT32;
191         }
192
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;
202         char *srcstr;
203
204         if (len == 0) {
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");
214                 return;
215         }
216
217         fprintf(f, " =");
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
228         for_each_marker(m) {
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;
231                 const char *p = &prop->val.val[m->offset];
232
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);
240
241                 if (emit_type == TYPE_NONE) {
242                         assert(chunk_len == 0);
243                         continue;
244                 }
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                 }
262
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                 }
269         }
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");
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;
285         struct label *l;
286         char *srcstr;
287
288         write_prefix(f, level);
289         for_each_label(tree->labels, l)
290                 fprintf(f, "%s: ", l->label);
291         if (tree->name && (*tree->name))
292                 fprintf(f, "%s {", tree->name);
293         else
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");
304
305         for_each_property(tree, prop) {
306                 write_prefix(f, level+1);
307                 for_each_label(prop->labels, l)
308                         fprintf(f, "%s: ", l->label);
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);
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");
326 }
327
328 void dt_to_source(FILE *f, struct dt_info *dti)
329 {
330         struct reserve_info *re;
331
332         fprintf(f, "/dts-v1/;\n\n");
333
334         for (re = dti->reservelist; re; re = re->next) {
335                 struct label *l;
336
337                 for_each_label(re->labels, l)
338                         fprintf(f, "%s: ", l->label);
339                 fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
340                         (unsigned long long)re->address,
341                         (unsigned long long)re->size);
342         }
343
344         write_tree_source_node(f, dti->dt, 0);
345 }