xref: /openbmc/linux/scripts/dtc/yamltree.c (revision 750afb08)
1 /*
2  * (C) Copyright Linaro, Ltd. 2018
3  * (C) Copyright Arm Holdings.  2017
4  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
19  *                                                                   USA
20  */
21 
22 #include <stdlib.h>
23 #include <yaml.h>
24 #include "dtc.h"
25 #include "srcpos.h"
26 
27 char *yaml_error_name[] = {
28 	[YAML_NO_ERROR] = "no error",
29 	[YAML_MEMORY_ERROR] = "memory error",
30 	[YAML_READER_ERROR] = "reader error",
31 	[YAML_SCANNER_ERROR] = "scanner error",
32 	[YAML_PARSER_ERROR] = "parser error",
33 	[YAML_COMPOSER_ERROR] = "composer error",
34 	[YAML_WRITER_ERROR] = "writer error",
35 	[YAML_EMITTER_ERROR] = "emitter error",
36 };
37 
38 #define yaml_emitter_emit_or_die(emitter, event) (			\
39 {									\
40 	if (!yaml_emitter_emit(emitter, event))				\
41 		die("yaml '%s': %s in %s, line %i\n",			\
42 		    yaml_error_name[(emitter)->error], 			\
43 		    (emitter)->problem, __func__, __LINE__);		\
44 })
45 
46 static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width)
47 {
48 	yaml_event_t event;
49 	void *tag;
50 	int off, start_offset = markers->offset;
51 
52 	switch(width) {
53 		case 1: tag = "!u8"; break;
54 		case 2: tag = "!u16"; break;
55 		case 4: tag = "!u32"; break;
56 		case 8: tag = "!u64"; break;
57 		default:
58 			die("Invalid width %i", width);
59 	}
60 	assert(len % width == 0);
61 
62 	yaml_sequence_start_event_initialize(&event, NULL,
63 		(yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE);
64 	yaml_emitter_emit_or_die(emitter, &event);
65 
66 	for (off = 0; off < len; off += width) {
67 		char buf[32];
68 		struct marker *m;
69 		bool is_phandle = false;
70 
71 		switch(width) {
72 		case 1:
73 			sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
74 			break;
75 		case 2:
76 			sprintf(buf, "0x%"PRIx16, fdt16_to_cpu(*(fdt16_t*)(data + off)));
77 			break;
78 		case 4:
79 			sprintf(buf, "0x%"PRIx32, fdt32_to_cpu(*(fdt32_t*)(data + off)));
80 			m = markers;
81 			is_phandle = false;
82 			for_each_marker_of_type(m, REF_PHANDLE) {
83 				if (m->offset == (start_offset + off)) {
84 					is_phandle = true;
85 					break;
86 				}
87 			}
88 			break;
89 		case 8:
90 			sprintf(buf, "0x%"PRIx64, fdt64_to_cpu(*(fdt64_t*)(data + off)));
91 			break;
92 		}
93 
94 		if (is_phandle)
95 			yaml_scalar_event_initialize(&event, NULL,
96 				(yaml_char_t*)"!phandle", (yaml_char_t *)buf,
97 				strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE);
98 		else
99 			yaml_scalar_event_initialize(&event, NULL,
100 				(yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf,
101 				strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE);
102 		yaml_emitter_emit_or_die(emitter, &event);
103 	}
104 
105 	yaml_sequence_end_event_initialize(&event);
106 	yaml_emitter_emit_or_die(emitter, &event);
107 }
108 
109 static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
110 {
111 	yaml_event_t event;
112 	int i;
113 
114 	assert(str[len-1] == '\0');
115 
116 	/* Make sure the entire string is in the lower 7-bit ascii range */
117 	for (i = 0; i < len; i++)
118 		assert(isascii(str[i]));
119 
120 	yaml_scalar_event_initialize(&event, NULL,
121 		(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str,
122 		len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
123 	yaml_emitter_emit_or_die(emitter, &event);
124 }
125 
126 static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
127 {
128 	yaml_event_t event;
129 	int len = prop->val.len;
130 	struct marker *m = prop->val.markers;
131 
132 	/* Emit the property name */
133 	yaml_scalar_event_initialize(&event, NULL,
134 		(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name,
135 		strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE);
136 	yaml_emitter_emit_or_die(emitter, &event);
137 
138 	/* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */
139 	if (len == 0) {
140 		yaml_scalar_event_initialize(&event, NULL,
141 			(yaml_char_t *)YAML_BOOL_TAG,
142 			(yaml_char_t*)"true",
143 			strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE);
144 		yaml_emitter_emit_or_die(emitter, &event);
145 		return;
146 	}
147 
148 	if (!m)
149 		die("No markers present in property '%s' value\n", prop->name);
150 
151 	yaml_sequence_start_event_initialize(&event, NULL,
152 		(yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE);
153 	yaml_emitter_emit_or_die(emitter, &event);
154 
155 	for_each_marker(m) {
156 		int chunk_len;
157 		char *data = &prop->val.val[m->offset];
158 
159 		if (m->type < TYPE_UINT8)
160 			continue;
161 
162 		chunk_len = type_marker_length(m) ? : len;
163 		assert(chunk_len > 0);
164 		len -= chunk_len;
165 
166 		switch(m->type) {
167 		case TYPE_UINT16:
168 			yaml_propval_int(emitter, m, data, chunk_len, 2);
169 			break;
170 		case TYPE_UINT32:
171 			yaml_propval_int(emitter, m, data, chunk_len, 4);
172 			break;
173 		case TYPE_UINT64:
174 			yaml_propval_int(emitter, m, data, chunk_len, 8);
175 			break;
176 		case TYPE_STRING:
177 			yaml_propval_string(emitter, data, chunk_len);
178 			break;
179 		default:
180 			yaml_propval_int(emitter, m, data, chunk_len, 1);
181 			break;
182 		}
183 	}
184 
185 	yaml_sequence_end_event_initialize(&event);
186 	yaml_emitter_emit_or_die(emitter, &event);
187 }
188 
189 
190 static void yaml_tree(struct node *tree, yaml_emitter_t *emitter)
191 {
192 	struct property *prop;
193 	struct node *child;
194 	yaml_event_t event;
195 
196 	if (tree->deleted)
197 		return;
198 
199 	yaml_mapping_start_event_initialize(&event, NULL,
200 		(yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE);
201 	yaml_emitter_emit_or_die(emitter, &event);
202 
203 	for_each_property(tree, prop)
204 		yaml_propval(emitter, prop);
205 
206 	/* Loop over all the children, emitting them into the map */
207 	for_each_child(tree, child) {
208 		yaml_scalar_event_initialize(&event, NULL,
209 			(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name,
210 			strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE);
211 		yaml_emitter_emit_or_die(emitter, &event);
212 		yaml_tree(child, emitter);
213 	}
214 
215 	yaml_mapping_end_event_initialize(&event);
216 	yaml_emitter_emit_or_die(emitter, &event);
217 }
218 
219 void dt_to_yaml(FILE *f, struct dt_info *dti)
220 {
221 	yaml_emitter_t emitter;
222 	yaml_event_t event;
223 
224 	yaml_emitter_initialize(&emitter);
225 	yaml_emitter_set_output_file(&emitter, f);
226 	yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING);
227 	yaml_emitter_emit_or_die(&emitter, &event);
228 
229 	yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
230 	yaml_emitter_emit_or_die(&emitter, &event);
231 
232 	yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE);
233 	yaml_emitter_emit_or_die(&emitter, &event);
234 
235 	yaml_tree(dti->dt, &emitter);
236 
237 	yaml_sequence_end_event_initialize(&event);
238 	yaml_emitter_emit_or_die(&emitter, &event);
239 
240 	yaml_document_end_event_initialize(&event, 0);
241 	yaml_emitter_emit_or_die(&emitter, &event);
242 
243 	yaml_stream_end_event_initialize(&event);
244 	yaml_emitter_emit_or_die(&emitter, &event);
245 
246 	yaml_emitter_delete(&emitter);
247 }
248