xref: /openbmc/linux/scripts/dtc/treesource.c (revision da2ef666)
1 /*
2  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3  *
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18  *                                                                   USA
19  */
20 
21 #include "dtc.h"
22 #include "srcpos.h"
23 
24 extern FILE *yyin;
25 extern int yyparse(void);
26 extern YYLTYPE yylloc;
27 
28 struct dt_info *parser_output;
29 bool treesource_error;
30 
31 struct dt_info *dt_from_source(const char *fname)
32 {
33 	parser_output = NULL;
34 	treesource_error = false;
35 
36 	srcfile_push(fname);
37 	yyin = current_srcfile->f;
38 	yylloc.file = current_srcfile;
39 
40 	if (yyparse() != 0)
41 		die("Unable to parse input tree\n");
42 
43 	if (treesource_error)
44 		die("Syntax error parsing input tree\n");
45 
46 	return parser_output;
47 }
48 
49 static void write_prefix(FILE *f, int level)
50 {
51 	int i;
52 
53 	for (i = 0; i < level; i++)
54 		fputc('\t', f);
55 }
56 
57 static bool isstring(char c)
58 {
59 	return (isprint((unsigned char)c)
60 		|| (c == '\0')
61 		|| strchr("\a\b\t\n\v\f\r", c));
62 }
63 
64 static void write_propval_string(FILE *f, const char *s, size_t len)
65 {
66 	const char *end = s + len - 1;
67 	assert(*end == '\0');
68 
69 	fprintf(f, "\"");
70 	while (s < end) {
71 		char c = *s++;
72 		switch (c) {
73 		case '\a':
74 			fprintf(f, "\\a");
75 			break;
76 		case '\b':
77 			fprintf(f, "\\b");
78 			break;
79 		case '\t':
80 			fprintf(f, "\\t");
81 			break;
82 		case '\n':
83 			fprintf(f, "\\n");
84 			break;
85 		case '\v':
86 			fprintf(f, "\\v");
87 			break;
88 		case '\f':
89 			fprintf(f, "\\f");
90 			break;
91 		case '\r':
92 			fprintf(f, "\\r");
93 			break;
94 		case '\\':
95 			fprintf(f, "\\\\");
96 			break;
97 		case '\"':
98 			fprintf(f, "\\\"");
99 			break;
100 		case '\0':
101 			fprintf(f, "\\0");
102 			break;
103 		default:
104 			if (isprint((unsigned char)c))
105 				fprintf(f, "%c", c);
106 			else
107 				fprintf(f, "\\x%02"PRIx8, c);
108 		}
109 	}
110 	fprintf(f, "\"");
111 }
112 
113 static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
114 {
115 	const char *end = p + len;
116 	assert(len % width == 0);
117 
118 	for (; p < end; p += width) {
119 		switch (width) {
120 		case 1:
121 			fprintf(f, " %02"PRIx8, *(const uint8_t*)p);
122 			break;
123 		case 2:
124 			fprintf(f, " 0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p));
125 			break;
126 		case 4:
127 			fprintf(f, " 0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p));
128 			break;
129 		case 8:
130 			fprintf(f, " 0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p));
131 			break;
132 		}
133 	}
134 }
135 
136 static bool has_data_type_information(struct marker *m)
137 {
138 	return m->type >= TYPE_UINT8;
139 }
140 
141 static struct marker *next_type_marker(struct marker *m)
142 {
143 	while (m && !has_data_type_information(m))
144 		m = m->next;
145 	return m;
146 }
147 
148 size_t type_marker_length(struct marker *m)
149 {
150 	struct marker *next = next_type_marker(m->next);
151 
152 	if (next)
153 		return next->offset - m->offset;
154 	return 0;
155 }
156 
157 static const char *delim_start[] = {
158 	[TYPE_UINT8] = "[",
159 	[TYPE_UINT16] = "/bits/ 16 <",
160 	[TYPE_UINT32] = "<",
161 	[TYPE_UINT64] = "/bits/ 64 <",
162 	[TYPE_STRING] = "",
163 };
164 static const char *delim_end[] = {
165 	[TYPE_UINT8] = " ]",
166 	[TYPE_UINT16] = " >",
167 	[TYPE_UINT32] = " >",
168 	[TYPE_UINT64] = " >",
169 	[TYPE_STRING] = "",
170 };
171 
172 static enum markertype guess_value_type(struct property *prop)
173 {
174 	int len = prop->val.len;
175 	const char *p = prop->val.val;
176 	struct marker *m = prop->val.markers;
177 	int nnotstring = 0, nnul = 0;
178 	int nnotstringlbl = 0, nnotcelllbl = 0;
179 	int i;
180 
181 	for (i = 0; i < len; i++) {
182 		if (! isstring(p[i]))
183 			nnotstring++;
184 		if (p[i] == '\0')
185 			nnul++;
186 	}
187 
188 	for_each_marker_of_type(m, LABEL) {
189 		if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0'))
190 			nnotstringlbl++;
191 		if ((m->offset % sizeof(cell_t)) != 0)
192 			nnotcelllbl++;
193 	}
194 
195 	if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
196 	    && (nnotstringlbl == 0)) {
197 		return TYPE_STRING;
198 	} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
199 		return TYPE_UINT32;
200 	}
201 
202 	return TYPE_UINT8;
203 }
204 
205 static void write_propval(FILE *f, struct property *prop)
206 {
207 	size_t len = prop->val.len;
208 	struct marker *m = prop->val.markers;
209 	struct marker dummy_marker;
210 	enum markertype emit_type = TYPE_NONE;
211 
212 	if (len == 0) {
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 	struct marker *m_label = prop->val.markers;
229 	for_each_marker(m) {
230 		size_t chunk_len;
231 		const char *p = &prop->val.val[m->offset];
232 
233 		if (!has_data_type_information(m))
234 			continue;
235 
236 		chunk_len = type_marker_length(m);
237 		if (!chunk_len)
238 			chunk_len = len - m->offset;
239 
240 		if (emit_type != TYPE_NONE)
241 			fprintf(f, "%s, ", delim_end[emit_type]);
242 		emit_type = m->type;
243 
244 		for_each_marker_of_type(m_label, LABEL) {
245 			if (m_label->offset > m->offset)
246 				break;
247 			fprintf(f, "%s: ", m_label->ref);
248 		}
249 
250 		fprintf(f, "%s", delim_start[emit_type]);
251 
252 		if (chunk_len <= 0)
253 			continue;
254 
255 		switch(emit_type) {
256 		case TYPE_UINT16:
257 			write_propval_int(f, p, chunk_len, 2);
258 			break;
259 		case TYPE_UINT32:
260 			write_propval_int(f, p, chunk_len, 4);
261 			break;
262 		case TYPE_UINT64:
263 			write_propval_int(f, p, chunk_len, 8);
264 			break;
265 		case TYPE_STRING:
266 			write_propval_string(f, p, chunk_len);
267 			break;
268 		default:
269 			write_propval_int(f, p, chunk_len, 1);
270 		}
271 	}
272 
273 	/* Wrap up any labels at the end of the value */
274 	for_each_marker_of_type(m_label, LABEL) {
275 		assert (m_label->offset == len);
276 		fprintf(f, " %s:", m_label->ref);
277 	}
278 
279 	fprintf(f, "%s;\n", delim_end[emit_type] ? : "");
280 }
281 
282 static void write_tree_source_node(FILE *f, struct node *tree, int level)
283 {
284 	struct property *prop;
285 	struct node *child;
286 	struct label *l;
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 {\n", tree->name);
293 	else
294 		fprintf(f, "/ {\n");
295 
296 	for_each_property(tree, prop) {
297 		write_prefix(f, level+1);
298 		for_each_label(prop->labels, l)
299 			fprintf(f, "%s: ", l->label);
300 		fprintf(f, "%s", prop->name);
301 		write_propval(f, prop);
302 	}
303 	for_each_child(tree, child) {
304 		fprintf(f, "\n");
305 		write_tree_source_node(f, child, level+1);
306 	}
307 	write_prefix(f, level);
308 	fprintf(f, "};\n");
309 }
310 
311 
312 void dt_to_source(FILE *f, struct dt_info *dti)
313 {
314 	struct reserve_info *re;
315 
316 	fprintf(f, "/dts-v1/;\n\n");
317 
318 	for (re = dti->reservelist; re; re = re->next) {
319 		struct label *l;
320 
321 		for_each_label(re->labels, l)
322 			fprintf(f, "%s: ", l->label);
323 		fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
324 			(unsigned long long)re->address,
325 			(unsigned long long)re->size);
326 	}
327 
328 	write_tree_source_node(f, dti->dt, 0);
329 }
330