1245803Stheraven/*-
2245803Stheraven * Copyright (c) 2013 David Chisnall
3245803Stheraven * All rights reserved.
4245803Stheraven *
5245803Stheraven * This software was developed by SRI International and the University of
6245803Stheraven * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7245803Stheraven * ("CTSRD"), as part of the DARPA CRASH research programme.
8245803Stheraven *
9245803Stheraven * Redistribution and use in source and binary forms, with or without
10245803Stheraven * modification, are permitted provided that the following conditions
11245803Stheraven * are met:
12245803Stheraven * 1. Redistributions of source code must retain the above copyright
13245803Stheraven *    notice, this list of conditions and the following disclaimer.
14245803Stheraven * 2. Redistributions in binary form must reproduce the above copyright
15245803Stheraven *    notice, this list of conditions and the following disclaimer in the
16245803Stheraven *    documentation and/or other materials provided with the distribution.
17245803Stheraven *
18245803Stheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19245803Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20245803Stheraven * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21245803Stheraven * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22245803Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23245803Stheraven * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24245803Stheraven * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25245803Stheraven * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26245803Stheraven * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27245803Stheraven * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28245803Stheraven * SUCH DAMAGE.
29245803Stheraven *
30245803Stheraven * $FreeBSD$
31245803Stheraven */
32245803Stheraven
33253149Stheraven#define __STDC_LIMIT_MACROS 1
34253149Stheraven
35245803Stheraven#include "fdt.hh"
36245803Stheraven
37245803Stheraven#include <algorithm>
38245839Stheraven#include <ctype.h>
39245839Stheraven#include <fcntl.h>
40245803Stheraven#include <inttypes.h>
41245803Stheraven#include <libgen.h>
42245839Stheraven#include <stdio.h>
43245839Stheraven#include <stdlib.h>
44245839Stheraven#include <unistd.h>
45245803Stheraven#include "dtb.hh"
46245803Stheraven
47245803Stheravennamespace dtc
48245803Stheraven{
49245803Stheraven
50245803Stheravennamespace fdt
51245803Stheraven{
52245803Stheraven
53245803Stheravenuint32_t
54245803Stheravenproperty_value::get_as_uint32()
55245803Stheraven{
56245803Stheraven	if (byte_data.size() != 4)
57245803Stheraven	{
58245803Stheraven		return 0;
59245803Stheraven	}
60245803Stheraven	uint32_t v = 0;
61245803Stheraven	v &= byte_data[0] << 24;
62245803Stheraven	v &= byte_data[1] << 16;
63245803Stheraven	v &= byte_data[2] << 8;
64245803Stheraven	v &= byte_data[3] << 0;
65245803Stheraven	return v;
66245803Stheraven}
67245803Stheraven
68245803Stheravenvoid
69245803Stheravenproperty_value::push_to_buffer(byte_buffer &buffer)
70245803Stheraven{
71245803Stheraven	if (!byte_data.empty())
72245803Stheraven	{
73245803Stheraven		buffer.insert(buffer.end(), byte_data.begin(), byte_data.end());
74245803Stheraven	}
75245803Stheraven	else
76245803Stheraven	{
77245803Stheraven		string_data.push_to_buffer(buffer, true);
78245803Stheraven		// Trailing nul
79245803Stheraven		buffer.push_back(0);
80245803Stheraven	}
81245803Stheraven}
82245803Stheraven
83245803Stheravenvoid
84245803Stheravenproperty_value::write_dts(FILE *file)
85245803Stheraven{
86245803Stheraven	resolve_type();
87245803Stheraven	switch (type)
88245803Stheraven	{
89245803Stheraven		default:
90245803Stheraven			assert(0 && "Invalid type");
91245803Stheraven		case STRING:
92245803Stheraven		case STRING_LIST:
93245803Stheraven		case CROSS_REFERENCE:
94245803Stheraven			write_as_string(file);
95245803Stheraven			break;
96245803Stheraven		case PHANDLE:
97245803Stheraven			write_as_cells(file);
98245803Stheraven			break;
99245803Stheraven		case BINARY:
100245803Stheraven			if (byte_data.size() % 4 == 0)
101245803Stheraven			{
102245803Stheraven				write_as_cells(file);
103245803Stheraven				break;
104245803Stheraven			}
105245803Stheraven			write_as_bytes(file);
106245803Stheraven			break;
107245803Stheraven	}
108245803Stheraven}
109245803Stheraven
110245803Stheravenvoid
111245803Stheravenproperty_value::resolve_type()
112245803Stheraven{
113245803Stheraven	if (type != UNKNOWN)
114245803Stheraven	{
115245803Stheraven		return;
116245803Stheraven	}
117245803Stheraven	if (byte_data.empty())
118245803Stheraven	{
119245803Stheraven		type = STRING;
120245803Stheraven		return;
121245803Stheraven	}
122245803Stheraven	if (byte_data.back() == 0)
123245803Stheraven	{
124245803Stheraven		bool is_all_printable = true;
125245803Stheraven		int nuls = 0;
126245803Stheraven		int bytes = 0;
127245803Stheraven		for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end()-1; i<e ; i++)
128245803Stheraven		{
129245803Stheraven			bytes++;
130245803Stheraven			is_all_printable &= (*i == '\0') || isprint(*i);
131245803Stheraven			if (*i == '\0')
132245803Stheraven			{
133245803Stheraven				nuls++;
134245803Stheraven			}
135245803Stheraven			if (!is_all_printable)
136245803Stheraven			{
137245803Stheraven				break;
138245803Stheraven			}
139245803Stheraven		}
140245803Stheraven		if (is_all_printable && (bytes > nuls))
141245803Stheraven		{
142245803Stheraven			type = STRING;
143245803Stheraven			if (nuls > 0)
144245803Stheraven			{
145245803Stheraven				type = STRING_LIST;
146245803Stheraven			}
147245803Stheraven			return;
148245803Stheraven		}
149245803Stheraven	}
150245803Stheraven	type = BINARY;
151245803Stheraven}
152245803Stheraven
153245803Stheravenvoid
154245803Stheravenproperty_value::write_as_string(FILE *file)
155245803Stheraven{
156245803Stheraven	putc('"', file);
157245803Stheraven	if (byte_data.empty())
158245803Stheraven	{
159245803Stheraven		string_data.print(file);
160245803Stheraven	}
161245803Stheraven	else
162245803Stheraven	{
163245803Stheraven		for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end()-1; i!=e ; ++i)
164245803Stheraven		{
165245803Stheraven			// FIXME Escape tabs, newlines, and so on.
166245803Stheraven			if (*i == '\0')
167245803Stheraven			{
168245803Stheraven				fputs("\", \"", file);
169245803Stheraven				continue;
170245803Stheraven			}
171245803Stheraven			putc(*i, file);
172245803Stheraven		}
173245803Stheraven	}
174245803Stheraven	putc('"', file);
175245803Stheraven}
176245803Stheraven
177245803Stheravenvoid
178245803Stheravenproperty_value::write_as_cells(FILE *file)
179245803Stheraven{
180245803Stheraven	putc('<', file);
181245803Stheraven	assert((byte_data.size() % 4) == 0);
182245803Stheraven	for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i)
183245803Stheraven	{
184245803Stheraven		uint32_t v = 0;
185245803Stheraven		v = (v << 8) | *i;
186245803Stheraven		++i;
187245803Stheraven		v = (v << 8) | *i;
188245803Stheraven		++i;
189245803Stheraven		v = (v << 8) | *i;
190245803Stheraven		++i;
191245803Stheraven		v = (v << 8) | *i;
192245803Stheraven		fprintf(file, "0x%" PRIx32, v);
193245803Stheraven		if (i+1 != e)
194245803Stheraven		{
195245803Stheraven			putc(' ', file);
196245803Stheraven		}
197245803Stheraven	}
198245803Stheraven	putc('>', file);
199245803Stheraven}
200245803Stheraven
201245803Stheravenvoid
202245803Stheravenproperty_value::write_as_bytes(FILE *file)
203245803Stheraven{
204245803Stheraven	putc('[', file);
205245803Stheraven	for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end(); i!=e ; i++)
206245803Stheraven	{
207245803Stheraven		fprintf(file, "%hhx", *i);
208245803Stheraven		if (i+1 != e)
209245803Stheraven		{
210245803Stheraven			putc(' ', file);
211245803Stheraven		}
212245803Stheraven	}
213245803Stheraven	putc(']', file);
214245803Stheraven}
215245803Stheraven
216245803Stheravenvoid
217245803Stheravenproperty::parse_string(input_buffer &input)
218245803Stheraven{
219245803Stheraven	property_value v;
220245803Stheraven	assert(input[0] == '"');
221245803Stheraven	++input;
222245803Stheraven	const char *start = (const char*)input;
223245803Stheraven	int length = 0;
224245803Stheraven	while (char c = input[0])
225245803Stheraven	{
226245803Stheraven		if (c == '"' && input[-1] != '\\')
227245803Stheraven		{
228245803Stheraven			input.consume('"');
229245803Stheraven			break;
230245803Stheraven		}
231245803Stheraven		++input;
232245803Stheraven		++length;
233245803Stheraven	}
234245803Stheraven	v.string_data = string(start, length);
235245803Stheraven	values.push_back(v);
236245803Stheraven}
237245803Stheraven
238245803Stheravenvoid
239245803Stheravenproperty::parse_cells(input_buffer &input)
240245803Stheraven{
241245803Stheraven	assert(input[0] == '<');
242245803Stheraven	++input;
243245803Stheraven	property_value v;
244245803Stheraven	input.next_token();
245245803Stheraven	while (!input.consume('>'))
246245803Stheraven	{
247245803Stheraven		input.next_token();
248245803Stheraven		// If this is a phandle then we need to get the name of the
249245803Stheraven		// referenced node
250245803Stheraven		if (input.consume('&'))
251245803Stheraven		{
252245803Stheraven			input.next_token();
253245803Stheraven			// FIXME: We should support full paths here, but we
254245803Stheraven			// don't.
255245803Stheraven			string referenced = string::parse_node_name(input);
256245803Stheraven			if (referenced.empty())
257245803Stheraven			{
258245803Stheraven				input.parse_error("Expected node name");
259245803Stheraven				valid = false;
260245803Stheraven				return;
261245803Stheraven			}
262245803Stheraven			input.next_token();
263245803Stheraven			// If we already have some bytes, make the phandle a
264245803Stheraven			// separate component.
265245803Stheraven			if (!v.byte_data.empty())
266245803Stheraven			{
267245803Stheraven				values.push_back(v);
268245803Stheraven				v = property_value();
269245803Stheraven			}
270245803Stheraven			v.string_data = referenced;
271245803Stheraven			v.type = property_value::PHANDLE;
272245803Stheraven			values.push_back(v);
273245803Stheraven			v = property_value();
274245803Stheraven		}
275245803Stheraven		else
276245803Stheraven		{
277245803Stheraven			//FIXME: We should support labels in the middle
278245803Stheraven			//of these, but we don't.
279245803Stheraven			long long val;
280245803Stheraven			if (!input.consume_integer(val))
281245803Stheraven			{
282245803Stheraven				input.parse_error("Expected numbers in array of cells");
283245803Stheraven				valid = false;
284245803Stheraven				return;
285245803Stheraven			}
286253149Stheraven			if ((val < 0) || (val > UINT32_MAX))
287253149Stheraven			{
288253149Stheraven				input.parse_error("Value out of range");
289253149Stheraven				valid = false;
290253149Stheraven				return;
291253149Stheraven			}
292245803Stheraven			push_big_endian(v.byte_data, (uint32_t)val);
293245803Stheraven			input.next_token();
294245803Stheraven		}
295245803Stheraven	}
296245803Stheraven	// Don't store an empty string value here.
297245803Stheraven	if (v.byte_data.size() > 0)
298245803Stheraven	{
299245803Stheraven		values.push_back(v);
300245803Stheraven	}
301245803Stheraven}
302245803Stheraven
303245803Stheravenvoid
304245803Stheravenproperty::parse_bytes(input_buffer &input)
305245803Stheraven{
306245803Stheraven	assert(input[0] == '[');
307245803Stheraven	++input;
308245803Stheraven	property_value v;
309245803Stheraven	input.next_token();
310245803Stheraven	while (!input.consume(']'))
311245803Stheraven	{
312245803Stheraven		{
313245803Stheraven			//FIXME: We should support
314245803Stheraven			//labels in the middle of
315245803Stheraven			//these, but we don't.
316245803Stheraven			uint8_t val;
317245803Stheraven			if (!input.consume_hex_byte(val))
318245803Stheraven			{
319245803Stheraven				input.parse_error("Expected hex bytes in array of bytes");
320245803Stheraven				valid = false;
321245803Stheraven				return;
322245803Stheraven			}
323245803Stheraven			v.byte_data.push_back(val);
324245803Stheraven			input.next_token();
325245803Stheraven		}
326245803Stheraven	}
327245803Stheraven	values.push_back(v);
328245803Stheraven}
329245803Stheraven
330245803Stheravenvoid
331245803Stheravenproperty::parse_reference(input_buffer &input)
332245803Stheraven{
333245803Stheraven	assert(input[0] == '&');
334245803Stheraven	++input;
335245803Stheraven	input.next_token();
336245803Stheraven	property_value v;
337245803Stheraven	v.string_data = string::parse_node_name(input);
338245803Stheraven	if (v.string_data.empty())
339245803Stheraven	{
340245803Stheraven		input.parse_error("Expected node name");
341245803Stheraven		valid = false;
342245803Stheraven		return;
343245803Stheraven	}
344245803Stheraven	v.type = property_value::CROSS_REFERENCE;
345245803Stheraven	values.push_back(v);
346245803Stheraven}
347245803Stheraven
348245803Stheravenproperty::property(input_buffer &structs, input_buffer &strings)
349245803Stheraven{
350245803Stheraven	uint32_t name_offset;
351245803Stheraven	uint32_t length;
352245803Stheraven	valid = structs.consume_binary(length) &&
353245803Stheraven		structs.consume_binary(name_offset);
354245803Stheraven	if (!valid)
355245803Stheraven	{
356245803Stheraven		fprintf(stderr, "Failed to read property\n");
357245803Stheraven		return;
358245803Stheraven	}
359245803Stheraven	// Find the name
360245803Stheraven	input_buffer name_buffer = strings.buffer_from_offset(name_offset);
361245803Stheraven	if (name_buffer.empty())
362245803Stheraven	{
363245803Stheraven		fprintf(stderr, "Property name offset %" PRIu32
364245803Stheraven			" is past the end of the strings table\n",
365245803Stheraven			name_offset);
366245803Stheraven		valid = false;
367245803Stheraven		return;
368245803Stheraven	}
369245803Stheraven	key = string(name_buffer);
370245803Stheraven	// Read the value
371245803Stheraven	uint8_t byte;
372245803Stheraven	property_value v;
373245803Stheraven	for (uint32_t i=0 ; i<length ; i++)
374245803Stheraven	{
375245803Stheraven		if (!(valid = structs.consume_binary(byte)))
376245803Stheraven		{
377245803Stheraven			fprintf(stderr, "Failed to read property value\n");
378245803Stheraven			return;
379245803Stheraven		}
380245803Stheraven		v.byte_data.push_back(byte);
381245803Stheraven	}
382245803Stheraven	values.push_back(v);
383245803Stheraven}
384245803Stheraven
385254522Stheravenvoid property::parse_define(input_buffer &input, define_map *defines)
386245803Stheraven{
387254522Stheraven	input.consume('$');
388254522Stheraven	if (!defines)
389254522Stheraven	{
390254522Stheraven		input.parse_error("No predefined properties to match name\n");
391254522Stheraven		valid = false;
392254522Stheraven		return;
393254522Stheraven	}
394254522Stheraven	string name = string::parse_property_name(input);
395254522Stheraven	define_map::iterator found;
396254522Stheraven	if ((name == string()) ||
397254522Stheraven	    ((found = defines->find(name)) == defines->end()))
398254522Stheraven	{
399254522Stheraven		input.parse_error("Undefined property name\n");
400254522Stheraven		valid = false;
401254522Stheraven		return;
402254522Stheraven	}
403254522Stheraven	values.push_back((*found).second->values[0]);
404254522Stheraven}
405254522Stheraven
406254522Stheravenproperty::property(input_buffer &input,
407254522Stheraven                   string k,
408254522Stheraven                   string l,
409254522Stheraven                   bool semicolonTerminated,
410254522Stheraven                   define_map *defines) : key(k), label(l), valid(true)
411254522Stheraven{
412245803Stheraven	do {
413245803Stheraven		input.next_token();
414245803Stheraven		switch (input[0])
415245803Stheraven		{
416254522Stheraven			case '$':
417254522Stheraven			{
418254522Stheraven				parse_define(input, defines);
419254522Stheraven				if (valid)
420254522Stheraven				{
421254522Stheraven					break;
422254522Stheraven				}
423254522Stheraven			}
424245803Stheraven			default:
425245803Stheraven				input.parse_error("Invalid property value.");
426245803Stheraven				valid = false;
427245803Stheraven				return;
428245803Stheraven			case '"':
429245803Stheraven				parse_string(input);
430245803Stheraven				break;
431245803Stheraven			case '<':
432245803Stheraven				parse_cells(input);
433245803Stheraven				break;
434245803Stheraven			case '[':
435245803Stheraven				parse_bytes(input);
436245803Stheraven				break;
437245803Stheraven			case '&':
438245803Stheraven				parse_reference(input);
439245803Stheraven				break;
440245803Stheraven			case ';':
441245803Stheraven			{
442245803Stheraven				break;
443245803Stheraven			}
444245803Stheraven		}
445245803Stheraven		input.next_token();
446245803Stheraven	} while (input.consume(','));
447254522Stheraven	if (semicolonTerminated && !input.consume(';'))
448245803Stheraven	{
449245803Stheraven		input.parse_error("Expected ; at end of property");
450245803Stheraven		valid = false;
451245803Stheraven	}
452245803Stheraven}
453245803Stheraven
454245803Stheravenproperty*
455245803Stheravenproperty::parse_dtb(input_buffer &structs, input_buffer &strings)
456245803Stheraven{
457245803Stheraven	property *p = new property(structs, strings);
458245803Stheraven	if (!p->valid)
459245803Stheraven	{
460245803Stheraven		delete p;
461245803Stheraven		p = 0;
462245803Stheraven	}
463245803Stheraven	return p;
464245803Stheraven}
465245803Stheraven
466245803Stheravenproperty*
467254522Stheravenproperty::parse(input_buffer &input, string key, string label,
468254522Stheraven                bool semicolonTerminated, define_map *defines)
469245803Stheraven{
470254522Stheraven	property *p = new property(input, key, label, semicolonTerminated, defines);
471245803Stheraven	if (!p->valid)
472245803Stheraven	{
473245803Stheraven		delete p;
474245803Stheraven		p = 0;
475245803Stheraven	}
476245803Stheraven	return p;
477245803Stheraven}
478245803Stheraven
479245803Stheravenvoid
480245803Stheravenproperty::write(dtb::output_writer &writer, dtb::string_table &strings)
481245803Stheraven{
482245803Stheraven	writer.write_token(dtb::FDT_PROP);
483245803Stheraven	byte_buffer value_buffer;
484245803Stheraven	for (value_iterator i=begin(), e=end() ; i!=e ; ++i)
485245803Stheraven	{
486245803Stheraven		i->push_to_buffer(value_buffer);
487245803Stheraven	}
488245803Stheraven	writer.write_data((uint32_t)value_buffer.size());
489245803Stheraven	writer.write_comment(key);
490245803Stheraven	writer.write_data(strings.add_string(key));
491245803Stheraven	writer.write_data(value_buffer);
492245803Stheraven}
493245803Stheraven
494245803Stheravenvoid
495245803Stheravenproperty::write_dts(FILE *file, int indent)
496245803Stheraven{
497245803Stheraven	for (int i=0 ; i<indent ; i++)
498245803Stheraven	{
499245803Stheraven		putc('\t', file);
500245803Stheraven	}
501245803Stheraven	if (label != string())
502245803Stheraven	{
503245803Stheraven		label.print(file);
504245803Stheraven		fputs(": ", file);
505245803Stheraven	}
506245803Stheraven	if (key != string())
507245803Stheraven	{
508245803Stheraven		key.print(file);
509245803Stheraven	}
510245803Stheraven	if (!values.empty())
511245803Stheraven	{
512245803Stheraven		fputs(" = ", file);
513245803Stheraven		for (value_iterator i=begin(), e=end() ; i!=e ; ++i)
514245803Stheraven		{
515245803Stheraven			i->write_dts(file);
516245803Stheraven			if (i+1 != e)
517245803Stheraven			{
518245803Stheraven				putc(',', file);
519245803Stheraven				putc(' ', file);
520245803Stheraven			}
521245803Stheraven		}
522245803Stheraven	}
523245803Stheraven	fputs(";\n", file);
524245803Stheraven}
525245803Stheraven
526245803Stheravenstring
527245803Stheravennode::parse_name(input_buffer &input, bool &is_property, const char *error)
528245803Stheraven{
529245803Stheraven	if (!valid)
530245803Stheraven	{
531245803Stheraven		return string();
532245803Stheraven	}
533245803Stheraven	input.next_token();
534245803Stheraven	if (is_property)
535245803Stheraven	{
536245803Stheraven		return string::parse_property_name(input);
537245803Stheraven	}
538245803Stheraven	string n = string::parse_node_or_property_name(input, is_property);
539245803Stheraven	if (n.empty())
540245803Stheraven	{
541245803Stheraven		if (n.empty())
542245803Stheraven		{
543245803Stheraven			input.parse_error(error);
544245803Stheraven			valid = false;
545245803Stheraven		}
546245803Stheraven	}
547245803Stheraven	return n;
548245803Stheraven}
549245803Stheraven
550245803Stheravennode::node(input_buffer &structs, input_buffer &strings) : valid(true)
551245803Stheraven{
552245803Stheraven	const char *name_start = (const char*)structs;
553245803Stheraven	int name_length = 0;
554245803Stheraven	while (structs[0] != '\0' && structs[0] != '@')
555245803Stheraven	{
556245803Stheraven		name_length++;
557245803Stheraven		++structs;
558245803Stheraven	}
559245803Stheraven	name = string(name_start, name_length);
560245803Stheraven	if (structs[0] == '@')
561245803Stheraven	{
562245803Stheraven		++structs;
563245803Stheraven		name_start = (const char*)structs;
564245803Stheraven		name_length = 0;
565245803Stheraven		while (structs[0] != '\0')
566245803Stheraven		{
567245803Stheraven			name_length++;
568245803Stheraven			++structs;
569245803Stheraven		}
570245803Stheraven		unit_address = string(name_start, name_length);
571245803Stheraven	}
572245803Stheraven	++structs;
573245803Stheraven	uint32_t token;
574245803Stheraven	while (structs.consume_binary(token))
575245803Stheraven	{
576245803Stheraven		switch (token)
577245803Stheraven		{
578245803Stheraven			default:
579245803Stheraven				fprintf(stderr, "Unexpected token 0x%" PRIx32
580245803Stheraven					" while parsing node.\n", token);
581245803Stheraven				valid = false;
582245803Stheraven				return;
583245803Stheraven			// Child node, parse it.
584245803Stheraven			case dtb::FDT_BEGIN_NODE:
585245803Stheraven			{
586245803Stheraven				node *child = node::parse_dtb(structs, strings);
587245803Stheraven				if (child == 0)
588245803Stheraven				{
589245803Stheraven					valid = false;
590245803Stheraven					return;
591245803Stheraven				}
592245803Stheraven				children.push_back(child);
593245803Stheraven				break;
594245803Stheraven			}
595245803Stheraven			// End of this node, no errors.
596245803Stheraven			case dtb::FDT_END_NODE:
597245803Stheraven				return;
598245803Stheraven			// Property, parse it.
599245803Stheraven			case dtb::FDT_PROP:
600245803Stheraven			{
601245803Stheraven				property *prop = property::parse_dtb(structs, strings);
602245803Stheraven				if (prop == 0)
603245803Stheraven				{
604245803Stheraven					valid = false;
605245803Stheraven					return;
606245803Stheraven				}
607245803Stheraven				properties.push_back(prop);
608245803Stheraven				break;
609245803Stheraven			}
610245803Stheraven				break;
611245803Stheraven			// End of structs table.  Should appear after
612245803Stheraven			// the end of the last node.
613245803Stheraven			case dtb::FDT_END:
614245803Stheraven				fprintf(stderr, "Unexpected FDT_END token while parsing node.\n");
615245803Stheraven				valid = false;
616245803Stheraven				return;
617245803Stheraven			// NOPs are padding.  Ignore them.
618245803Stheraven			case dtb::FDT_NOP:
619245803Stheraven				break;
620245803Stheraven		}
621245803Stheraven	}
622245803Stheraven	fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
623245803Stheraven	valid = false;
624245803Stheraven	return;
625245803Stheraven}
626245803Stheraven
627254522Stheravennode::node(input_buffer &input, string n, string l, string a, define_map *defines) :
628245803Stheraven	label(l), name(n), unit_address(a), valid(true)
629245803Stheraven{
630245803Stheraven	if (!input.consume('{'))
631245803Stheraven	{
632245803Stheraven		input.parse_error("Expected { to start new device tree node.\n");
633245803Stheraven	}
634245803Stheraven	input.next_token();
635245803Stheraven	while (valid && !input.consume('}'))
636245803Stheraven	{
637245803Stheraven		// flag set if we find any characters that are only in
638245803Stheraven		// the property name character set, not the node
639245803Stheraven		bool is_property = false;
640245803Stheraven		string child_name, child_label, child_address;
641245803Stheraven		child_name = parse_name(input, is_property,
642245803Stheraven				"Expected property or node name");
643245803Stheraven		if (input.consume(':'))
644245803Stheraven		{
645245803Stheraven			// Node labels can contain any characters?  The
646245803Stheraven			// spec doesn't say, so we guess so...
647245803Stheraven			is_property = false;
648245803Stheraven			child_label = child_name;
649245803Stheraven			child_name = parse_name(input, is_property, "Expected property or node name");
650245803Stheraven		}
651245803Stheraven		if (input.consume('@'))
652245803Stheraven		{
653245803Stheraven			child_address = parse_name(input, is_property, "Expected unit address");
654245803Stheraven		}
655245803Stheraven		if (!valid)
656245803Stheraven		{
657245803Stheraven			return;
658245803Stheraven		}
659245803Stheraven		input.next_token();
660245803Stheraven		// If we're parsing a property, then we must actually do that.
661245803Stheraven		if (input.consume('='))
662245803Stheraven		{
663245803Stheraven			property *p= property::parse(input, child_name,
664254522Stheraven					child_label, true, defines);
665245803Stheraven			if (p == 0)
666245803Stheraven			{
667245803Stheraven				valid = false;
668245803Stheraven			}
669245803Stheraven			else
670245803Stheraven			{
671245803Stheraven				properties.push_back(p);
672245803Stheraven			}
673245803Stheraven		}
674245803Stheraven		else if (!is_property && input[0] == ('{'))
675245803Stheraven		{
676245803Stheraven			node *child = node::parse(input, child_name,
677254522Stheraven					child_label, child_address, defines);
678245803Stheraven			if (child)
679245803Stheraven			{
680245803Stheraven				children.push_back(child);
681245803Stheraven			}
682245803Stheraven			else
683245803Stheraven			{
684245803Stheraven				valid = false;
685245803Stheraven			}
686245803Stheraven		}
687245803Stheraven		else if (input.consume(';'))
688245803Stheraven		{
689245803Stheraven			properties.push_back(new property(child_name, child_label));
690245803Stheraven		}
691245803Stheraven		else
692245803Stheraven		{
693245803Stheraven			input.parse_error("Error parsing property.");
694245803Stheraven			valid = false;
695245803Stheraven		}
696245803Stheraven		input.next_token();
697245803Stheraven	}
698245803Stheraven	input.consume(';');
699245803Stheraven}
700245803Stheraven
701245803Stheravenbool
702245803Stheravennode::cmp_properties(property *p1, property *p2)
703245803Stheraven{
704245803Stheraven	return p1->get_key() < p2->get_key();
705245803Stheraven}
706245803Stheraven
707245803Stheravenbool
708245803Stheravennode::cmp_children(node *c1, node *c2)
709245803Stheraven{
710245803Stheraven	if (c1->name == c2->name)
711245803Stheraven	{
712245803Stheraven		return c1->unit_address < c2->unit_address;
713245803Stheraven	}
714245803Stheraven	return c1->name < c2->name;
715245803Stheraven}
716245803Stheraven
717245803Stheravenvoid
718245803Stheravennode::sort()
719245803Stheraven{
720245803Stheraven	std::sort(property_begin(), property_end(), cmp_properties);
721245803Stheraven	std::sort(child_begin(), child_end(), cmp_children);
722245803Stheraven	for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i)
723245803Stheraven	{
724245803Stheraven		(*i)->sort();
725245803Stheraven	}
726245803Stheraven}
727245803Stheraven
728245803Stheravennode*
729254522Stheravennode::parse(input_buffer &input,
730254522Stheraven            string name,
731254522Stheraven            string label,
732254522Stheraven            string address,
733254522Stheraven            define_map *defines)
734245803Stheraven{
735254522Stheraven	node *n = new node(input, name, label, address, defines);
736245803Stheraven	if (!n->valid)
737245803Stheraven	{
738245803Stheraven		delete n;
739245803Stheraven		n = 0;
740245803Stheraven	}
741245803Stheraven	return n;
742245803Stheraven}
743245803Stheraven
744245803Stheravennode*
745245803Stheravennode::parse_dtb(input_buffer &structs, input_buffer &strings)
746245803Stheraven{
747245803Stheraven	node *n = new node(structs, strings);
748245803Stheraven	if (!n->valid)
749245803Stheraven	{
750245803Stheraven		delete n;
751245803Stheraven		n = 0;
752245803Stheraven	}
753245803Stheraven	return n;
754245803Stheraven}
755245803Stheraven
756245803Stheravennode::~node()
757245803Stheraven{
758245803Stheraven	while (!children.empty())
759245803Stheraven	{
760245803Stheraven		delete children.back();
761245803Stheraven		children.pop_back();
762245803Stheraven	}
763245803Stheraven	while (!properties.empty())
764245803Stheraven	{
765245803Stheraven		delete properties.back();
766245803Stheraven		properties.pop_back();
767245803Stheraven	}
768245803Stheraven}
769245803Stheraven
770245803Stheravenproperty*
771245803Stheravennode::get_property(string key)
772245803Stheraven{
773245803Stheraven	for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i)
774245803Stheraven	{
775245803Stheraven		if ((*i)->get_key() == key)
776245803Stheraven		{
777245803Stheraven			return *i;
778245803Stheraven		}
779245803Stheraven	}
780245803Stheraven	return 0;
781245803Stheraven}
782245803Stheraven
783245803Stheravenvoid
784245803Stheravennode::merge_node(node *other)
785245803Stheraven{
786245803Stheraven	if (!other->label.empty())
787245803Stheraven	{
788245803Stheraven		label = other->label;
789245803Stheraven	}
790245803Stheraven	// Note: this is an O(n*m) operation.  It might be sensible to
791245803Stheraven	// optimise this if we find that there are nodes with very
792245803Stheraven	// large numbers of properties, but for typical usage the
793245803Stheraven	// entire vector will fit (easily) into cache, so iterating
794245803Stheraven	// over it repeatedly isn't that expensive.
795245803Stheraven	while (!other->properties.empty())
796245803Stheraven	{
797245803Stheraven		property *p = other->properties.front();
798245803Stheraven		for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i)
799245803Stheraven		{
800245803Stheraven			if ((*i)->get_key() == p->get_key())
801245803Stheraven			{
802245803Stheraven				delete *i;
803245803Stheraven				properties.erase(i);
804245803Stheraven				break;
805245803Stheraven			}
806245803Stheraven		}
807245803Stheraven		add_property(p);
808245803Stheraven		other->properties.erase(other->properties.begin());
809245803Stheraven	}
810245803Stheraven	while (!other->children.empty())
811245803Stheraven	{
812245803Stheraven		node *c = other->children.front();
813245803Stheraven		bool found = false;
814245803Stheraven		for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i)
815245803Stheraven		{
816245803Stheraven			if ((*i)->name == c->name && (*i)->unit_address == c->unit_address)
817245803Stheraven			{
818245803Stheraven				(*i)->merge_node(c);
819245803Stheraven				delete c;
820245803Stheraven				found = true;
821245803Stheraven				break;
822245803Stheraven			}
823245803Stheraven		}
824245803Stheraven		if (!found)
825245803Stheraven		{
826245803Stheraven			children.push_back(c);
827245803Stheraven		}
828245803Stheraven		other->children.erase(other->children.begin());
829245803Stheraven	}
830245803Stheraven}
831245803Stheraven
832245803Stheravenvoid
833245803Stheravennode::write(dtb::output_writer &writer, dtb::string_table &strings)
834245803Stheraven{
835245803Stheraven	writer.write_token(dtb::FDT_BEGIN_NODE);
836245803Stheraven	byte_buffer name_buffer;
837245803Stheraven	name.push_to_buffer(name_buffer);
838245803Stheraven	if (unit_address != string())
839245803Stheraven	{
840245803Stheraven		name_buffer.push_back('@');
841245803Stheraven		unit_address.push_to_buffer(name_buffer);
842245803Stheraven	}
843245803Stheraven	writer.write_comment(name);
844245803Stheraven	writer.write_data(name_buffer);
845245803Stheraven	writer.write_data((uint8_t)0);
846245803Stheraven	for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i)
847245803Stheraven	{
848245803Stheraven		(*i)->write(writer, strings);
849245803Stheraven	}
850245803Stheraven	for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i)
851245803Stheraven	{
852245803Stheraven		(*i)->write(writer, strings);
853245803Stheraven	}
854245803Stheraven	writer.write_token(dtb::FDT_END_NODE);
855245803Stheraven}
856245803Stheraven
857245803Stheravenvoid
858245803Stheravennode::write_dts(FILE *file, int indent)
859245803Stheraven{
860245803Stheraven	for (int i=0 ; i<indent ; i++)
861245803Stheraven	{
862245803Stheraven		putc('\t', file);
863245803Stheraven	}
864245803Stheraven	if (label != string())
865245803Stheraven	{
866245803Stheraven		label.print(file);
867245803Stheraven		fputs(": ", file);
868245803Stheraven	}
869245803Stheraven	if (name != string())
870245803Stheraven	{
871245803Stheraven		name.print(file);
872245803Stheraven	}
873245803Stheraven	if (unit_address != string())
874245803Stheraven	{
875245803Stheraven		putc('@', file);
876245803Stheraven		unit_address.print(file);
877245803Stheraven	}
878245803Stheraven	fputs(" {\n\n", file);
879245803Stheraven	for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i)
880245803Stheraven	{
881245803Stheraven		(*i)->write_dts(file, indent+1);
882245803Stheraven	}
883245803Stheraven	for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i)
884245803Stheraven	{
885245803Stheraven		(*i)->write_dts(file, indent+1);
886245803Stheraven	}
887245803Stheraven	for (int i=0 ; i<indent ; i++)
888245803Stheraven	{
889245803Stheraven		putc('\t', file);
890245803Stheraven	}
891245803Stheraven	fputs("};\n", file);
892245803Stheraven}
893245803Stheraven
894245803Stheravenvoid
895245803Stheravendevice_tree::collect_names_recursive(node* n, node_path &path)
896245803Stheraven{
897245803Stheraven	string name = n->label;
898245803Stheraven	path.push_back(std::make_pair(n->name, n->unit_address));
899245803Stheraven	if (name != string())
900245803Stheraven	{
901245803Stheraven		if (node_names.find(name) == node_names.end())
902245803Stheraven		{
903245803Stheraven			node_names.insert(std::make_pair(name, n));
904245803Stheraven			node_paths.insert(std::make_pair(name, path));
905245803Stheraven		}
906245803Stheraven		else
907245803Stheraven		{
908245803Stheraven			node_names[name] = (node*)-1;
909245803Stheraven			std::map<string, node_path>::iterator i = node_paths.find(name);
910245803Stheraven			if (i != node_paths.end())
911245803Stheraven			{
912245803Stheraven				node_paths.erase(name);
913245803Stheraven			}
914245803Stheraven			fprintf(stderr, "Label not unique: ");
915245803Stheraven			name.dump();
916245803Stheraven			fprintf(stderr, ".  References to this label will not be resolved.");
917245803Stheraven		}
918245803Stheraven	}
919245803Stheraven	for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ; ++i)
920245803Stheraven	{
921245803Stheraven		collect_names_recursive(*i, path);
922245803Stheraven	}
923245803Stheraven	path.pop_back();
924245803Stheraven	// Now we collect the phandles and properties that reference
925245803Stheraven	// other nodes.
926245803Stheraven	for (node::property_iterator i=n->property_begin(), e=n->property_end() ; i!=e ; ++i)
927245803Stheraven	{
928245803Stheraven		for (property::value_iterator p=(*i)->begin(),pe=(*i)->end() ; p!=pe ; ++p)
929245803Stheraven		{
930245803Stheraven			if (p->is_phandle())
931245803Stheraven			{
932245803Stheraven				phandles.push_back(&*p);
933245803Stheraven			}
934245803Stheraven			if (p->is_cross_reference())
935245803Stheraven			{
936245803Stheraven				cross_references.push_back(&*p);
937245803Stheraven			}
938245803Stheraven		}
939245803Stheraven		if ((*i)->get_key() == string("phandle") ||
940245803Stheraven		    (*i)->get_key() == string("linux,phandle"))
941245803Stheraven		{
942245803Stheraven			if ((*i)->begin()->byte_data.size() != 4)
943245803Stheraven			{
944245803Stheraven				fprintf(stderr, "Invalid phandle value for node ");
945245803Stheraven				n->name.dump();
946245803Stheraven				fprintf(stderr, ".  Should be a 4-byte value.\n");
947245803Stheraven				valid = false;
948245803Stheraven			}
949245803Stheraven			else
950245803Stheraven			{
951245803Stheraven				uint32_t phandle = (*i)->begin()->get_as_uint32();
952245803Stheraven				used_phandles.insert(std::make_pair(phandle, n));
953245803Stheraven			}
954245803Stheraven		}
955245803Stheraven	}
956245803Stheraven}
957245803Stheraven
958245803Stheravenvoid
959245803Stheravendevice_tree::collect_names()
960245803Stheraven{
961245803Stheraven	node_path p;
962245803Stheraven	collect_names_recursive(root, p);
963245803Stheraven}
964245803Stheraven
965245803Stheravenvoid
966245803Stheravendevice_tree::resolve_cross_references()
967245803Stheraven{
968245803Stheraven	for (std::vector<property_value*>::iterator i=cross_references.begin(), e=cross_references.end() ; i!=e ; ++i)
969245803Stheraven	{
970245803Stheraven		property_value* pv = *i;
971245803Stheraven		node_path path = node_paths[pv->string_data];
972245803Stheraven		// Skip the first name in the path.  It's always "", and implicitly /
973245803Stheraven		for (node_path::iterator p=path.begin()+1, pe=path.end() ; p!=pe ; ++p)
974245803Stheraven		{
975245803Stheraven			pv->byte_data.push_back('/');
976245803Stheraven			p->first.push_to_buffer(pv->byte_data);
977245803Stheraven			if (!(p->second.empty()))
978245803Stheraven			{
979245803Stheraven				pv->byte_data.push_back('@');
980245803Stheraven				p->second.push_to_buffer(pv->byte_data);
981245803Stheraven			}
982245803Stheraven		}
983245803Stheraven		pv->byte_data.push_back(0);
984245803Stheraven	}
985245803Stheraven	uint32_t phandle = 1;
986245803Stheraven	for (std::vector<property_value*>::iterator i=phandles.begin(), e=phandles.end() ; i!=e ; ++i)
987245803Stheraven	{
988245803Stheraven		string target_name = (*i)->string_data;
989245803Stheraven		node *target = node_names[target_name];
990245803Stheraven		if (target == 0)
991245803Stheraven		{
992245803Stheraven			fprintf(stderr, "Failed to find node with label:");
993245803Stheraven			target_name.dump();
994245803Stheraven			fprintf(stderr, "\n");
995245803Stheraven			valid = 0;
996245803Stheraven			return;
997245803Stheraven		}
998245803Stheraven		// If there is an existing phandle, use it
999245803Stheraven		property *p = target->get_property("phandle");
1000245803Stheraven		if (p == 0)
1001245803Stheraven		{
1002245803Stheraven			p = target->get_property("linux,phandle");
1003245803Stheraven		}
1004245803Stheraven		if (p == 0)
1005245803Stheraven		{
1006245803Stheraven			// Otherwise insert a new phandle node
1007245803Stheraven			property_value v;
1008245803Stheraven			while (used_phandles.find(phandle) != used_phandles.end())
1009245803Stheraven			{
1010245803Stheraven				// Note that we only don't need to
1011245803Stheraven				// store this phandle in the set,
1012245803Stheraven				// because we are monotonically
1013245803Stheraven				// increasing the value of phandle and
1014245803Stheraven				// so will only ever revisit this value
1015245803Stheraven				// if we have used 2^32 phandles, at
1016245803Stheraven				// which point our blob won't fit in
1017245803Stheraven				// any 32-bit system and we've done
1018245803Stheraven				// something badly wrong elsewhere
1019245803Stheraven				// already.
1020245803Stheraven				phandle++;
1021245803Stheraven			}
1022245803Stheraven			push_big_endian(v.byte_data, phandle++);
1023245803Stheraven			if (phandle_node_name == BOTH || phandle_node_name == LINUX)
1024245803Stheraven			{
1025245803Stheraven				p = new property(string("linux,phandle"));
1026245803Stheraven				p->add_value(v);
1027245803Stheraven				target->add_property(p);
1028245803Stheraven			}
1029245803Stheraven			if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1030245803Stheraven			{
1031245803Stheraven				p = new property(string("phandle"));
1032245803Stheraven				p->add_value(v);
1033245803Stheraven				target->add_property(p);
1034245803Stheraven			}
1035245803Stheraven		}
1036245803Stheraven		p->begin()->push_to_buffer((*i)->byte_data);
1037245803Stheraven		assert((*i)->byte_data.size() == 4);
1038245803Stheraven	}
1039245803Stheraven}
1040245803Stheraven
1041245803Stheravenvoid
1042245803Stheravendevice_tree::parse_roots(input_buffer &input, std::vector<node*> &roots)
1043245803Stheraven{
1044245803Stheraven	input.next_token();
1045245803Stheraven	while (valid && input.consume('/'))
1046245803Stheraven	{
1047245803Stheraven		input.next_token();
1048254522Stheraven		node *n = node::parse(input, string("", 1), string(), string(), &defines);
1049245803Stheraven		if (n)
1050245803Stheraven		{
1051245803Stheraven			roots.push_back(n);
1052245803Stheraven		}
1053245803Stheraven		else
1054245803Stheraven		{
1055245803Stheraven			valid = false;
1056245803Stheraven		}
1057266202Sian		input.next_token();
1058245803Stheraven	}
1059245803Stheraven}
1060245803Stheraven
1061245803Stheraveninput_buffer*
1062245803Stheravendevice_tree::buffer_for_file(const char *path)
1063245803Stheraven{
1064245803Stheraven	if (string(path) == string("-"))
1065245803Stheraven	{
1066245803Stheraven		input_buffer *b = new stream_input_buffer();
1067245803Stheraven		buffers.push_back(b);
1068245803Stheraven		return b;
1069245803Stheraven	}
1070245803Stheraven	int source = open(path, O_RDONLY);
1071245803Stheraven	if (source == -1)
1072245803Stheraven	{
1073245803Stheraven		fprintf(stderr, "Unable to open file %s\n", path);
1074245803Stheraven		return 0;
1075245803Stheraven	}
1076245803Stheraven	input_buffer *b = new mmap_input_buffer(source);
1077245803Stheraven	// Keep the buffer that owns the memory around for the lifetime
1078245803Stheraven	// of this FDT.  Ones simply referring to it may have shorter
1079245803Stheraven	// lifetimes.
1080245803Stheraven	buffers.push_back(b);
1081245803Stheraven	close(source);
1082245803Stheraven	return b;
1083245803Stheraven}
1084245803Stheraven
1085245803Stheraventemplate<class writer> void
1086245803Stheravendevice_tree::write(int fd)
1087245803Stheraven{
1088245803Stheraven	dtb::string_table st;
1089245803Stheraven	dtb::header head;
1090245803Stheraven	writer head_writer;
1091245803Stheraven	writer reservation_writer;
1092245803Stheraven	writer struct_writer;
1093245803Stheraven	writer strings_writer;
1094245803Stheraven
1095245803Stheraven	// Build the reservation table
1096245803Stheraven	reservation_writer.write_comment(string("Memory reservations"));
1097245803Stheraven	reservation_writer.write_label(string("dt_reserve_map"));
1098245803Stheraven	for (std::vector<reservation>::iterator i=reservations.begin(),
1099245803Stheraven	     e=reservations.end() ; i!=e ; ++i)
1100245803Stheraven	{
1101245803Stheraven		reservation_writer.write_comment(string("Reservation start"));
1102245803Stheraven		reservation_writer.write_data(i->first);
1103245803Stheraven		reservation_writer.write_comment(string("Reservation length"));
1104245803Stheraven		reservation_writer.write_data(i->first);
1105245803Stheraven	}
1106245803Stheraven	// Write n spare reserve map entries, plus the trailing 0.
1107245803Stheraven	for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++)
1108245803Stheraven	{
1109245803Stheraven		reservation_writer.write_data((uint64_t)0);
1110245803Stheraven		reservation_writer.write_data((uint64_t)0);
1111245803Stheraven	}
1112245803Stheraven
1113245803Stheraven
1114245803Stheraven	struct_writer.write_comment(string("Device tree"));
1115245803Stheraven	struct_writer.write_label(string("dt_struct_start"));
1116245803Stheraven	root->write(struct_writer, st);
1117245803Stheraven	struct_writer.write_token(dtb::FDT_END);
1118245803Stheraven	struct_writer.write_label(string("dt_struct_end"));
1119245803Stheraven
1120245803Stheraven	st.write(strings_writer);
1121245803Stheraven	// Find the strings size before we stick padding on the end.
1122245803Stheraven	// Note: We should possibly use a new writer for the padding.
1123245803Stheraven	head.size_dt_strings = strings_writer.size();
1124245803Stheraven
1125245803Stheraven	// Stick the padding in the strings writer, but after the
1126245803Stheraven	// marker indicating that it's the end.
1127245803Stheraven	// Note: We probably should add a padding call to the writer so
1128245803Stheraven	// that the asm back end can write padding directives instead
1129245803Stheraven	// of a load of 0 bytes.
1130245803Stheraven	for (uint32_t i=0 ; i<blob_padding ; i++)
1131245803Stheraven	{
1132245803Stheraven		strings_writer.write_data((uint8_t)0);
1133245803Stheraven	}
1134245803Stheraven	head.totalsize = sizeof(head) + strings_writer.size() +
1135245803Stheraven		struct_writer.size() + reservation_writer.size();
1136245803Stheraven	while (head.totalsize < minimum_blob_size)
1137245803Stheraven	{
1138245803Stheraven		head.totalsize++;
1139245803Stheraven		strings_writer.write_data((uint8_t)0);
1140245803Stheraven	}
1141245803Stheraven	head.off_dt_struct = sizeof(head) + reservation_writer.size();;
1142245803Stheraven	head.off_dt_strings = head.off_dt_struct + struct_writer.size();
1143245803Stheraven	head.off_mem_rsvmap = sizeof(head);
1144245803Stheraven	head.boot_cpuid_phys = boot_cpu;
1145245803Stheraven	head.size_dt_struct = struct_writer.size();
1146245803Stheraven	head.write(head_writer);
1147245803Stheraven
1148245803Stheraven	head_writer.write_to_file(fd);
1149245803Stheraven	reservation_writer.write_to_file(fd);
1150245803Stheraven	struct_writer.write_to_file(fd);
1151245803Stheraven	strings_writer.write_label(string("dt_blob_end"));
1152245803Stheraven	strings_writer.write_to_file(fd);
1153245803Stheraven}
1154245803Stheraven
1155245803Stheravennode*
1156245803Stheravendevice_tree::referenced_node(property_value &v)
1157245803Stheraven{
1158245803Stheraven	if (v.is_phandle())
1159245803Stheraven	{
1160245803Stheraven		return node_names[v.string_data];
1161245803Stheraven	}
1162245803Stheraven	if (v.is_binary())
1163245803Stheraven	{
1164245803Stheraven		return used_phandles[v.get_as_uint32()];
1165245803Stheraven	}
1166245803Stheraven	return 0;
1167245803Stheraven}
1168245803Stheraven
1169245803Stheravenvoid
1170245803Stheravendevice_tree::write_binary(int fd)
1171245803Stheraven{
1172245803Stheraven	write<dtb::binary_writer>(fd);
1173245803Stheraven}
1174245803Stheraven
1175245803Stheravenvoid
1176245803Stheravendevice_tree::write_asm(int fd)
1177245803Stheraven{
1178245803Stheraven	write<dtb::asm_writer>(fd);
1179245803Stheraven}
1180245803Stheraven
1181245803Stheravenvoid
1182245803Stheravendevice_tree::write_dts(int fd)
1183245803Stheraven{
1184245803Stheraven	FILE *file = fdopen(fd, "w");
1185245803Stheraven	fputs("/dtc-v1/;\n\n", file);
1186245803Stheraven
1187245803Stheraven	if (!reservations.empty())
1188245803Stheraven	{
1189245803Stheraven		const char msg[] = "/memreserve/";
1190245803Stheraven		fwrite(msg, sizeof(msg), 1, file);
1191245803Stheraven		for (std::vector<reservation>::iterator i=reservations.begin(),
1192245803Stheraven		     e=reservations.end() ; i!=e ; ++i)
1193245803Stheraven		{
1194245803Stheraven			fprintf(stderr, " %" PRIx64 " %" PRIx64, i->first, i->second);
1195245803Stheraven		}
1196245803Stheraven		fputs(";\n\n", file);
1197245803Stheraven	}
1198245803Stheraven	putc('/', file);
1199245803Stheraven	putc(' ', file);
1200245803Stheraven	root->write_dts(file, 0);
1201245803Stheraven	fclose(file);
1202245803Stheraven}
1203245803Stheraven
1204245803Stheravenvoid
1205245803Stheravendevice_tree::parse_dtb(const char *fn, FILE *depfile)
1206245803Stheraven{
1207245803Stheraven	input_buffer *in = buffer_for_file(fn);
1208245803Stheraven	if (in == 0)
1209245803Stheraven	{
1210245803Stheraven		valid = false;
1211245803Stheraven		return;
1212245803Stheraven	}
1213245803Stheraven	input_buffer &input = *in;
1214245803Stheraven	dtb::header h;
1215245803Stheraven	valid = h.read_dtb(input);
1216245803Stheraven	boot_cpu = h.boot_cpuid_phys;
1217245803Stheraven	if (h.last_comp_version > 17)
1218245803Stheraven	{
1219245803Stheraven		fprintf(stderr, "Don't know how to read this version of the device tree blob");
1220245803Stheraven		valid = false;
1221245803Stheraven	}
1222245803Stheraven	if (!valid)
1223245803Stheraven	{
1224245803Stheraven		return;
1225245803Stheraven	}
1226245803Stheraven	input_buffer reservation_map =
1227245803Stheraven		input.buffer_from_offset(h.off_mem_rsvmap, 0);
1228245803Stheraven	uint64_t start, length;
1229245803Stheraven	do
1230245803Stheraven	{
1231245803Stheraven		if (!(reservation_map.consume_binary(start) &&
1232245803Stheraven		      reservation_map.consume_binary(length)))
1233245803Stheraven		{
1234245803Stheraven			fprintf(stderr, "Failed to read memory reservation table\n");
1235245803Stheraven			valid = false;
1236245803Stheraven			return;
1237245803Stheraven		}
1238245803Stheraven	} while (!((start == 0) && (length == 0)));
1239245803Stheraven	input_buffer struct_table =
1240245803Stheraven		input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct);
1241245803Stheraven	input_buffer strings_table =
1242245803Stheraven		input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings);
1243245803Stheraven	uint32_t token;
1244245803Stheraven	if (!(struct_table.consume_binary(token) &&
1245245803Stheraven		(token == dtb::FDT_BEGIN_NODE)))
1246245803Stheraven	{
1247245803Stheraven		fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n");
1248245803Stheraven		valid = false;
1249245803Stheraven		return;
1250245803Stheraven	}
1251245803Stheraven	root = node::parse_dtb(struct_table, strings_table);
1252245803Stheraven	if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END)))
1253245803Stheraven	{
1254245803Stheraven		fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1255245803Stheraven		valid = false;
1256245803Stheraven		return;
1257245803Stheraven	}
1258245803Stheraven	valid = (root != 0);
1259245803Stheraven}
1260245803Stheraven
1261245803Stheravenvoid
1262245803Stheravendevice_tree::parse_dts(const char *fn, FILE *depfile)
1263245803Stheraven{
1264245803Stheraven	input_buffer *in = buffer_for_file(fn);
1265245803Stheraven	if (in == 0)
1266245803Stheraven	{
1267245803Stheraven		valid = false;
1268245803Stheraven		return;
1269245803Stheraven	}
1270245803Stheraven	std::vector<node*> roots;
1271245803Stheraven	input_buffer &input = *in;
1272245803Stheraven	input.next_token();
1273245803Stheraven	bool read_header = false;
1274245803Stheraven	// Read the header
1275245803Stheraven	if (input.consume("/dts-v1/;"))
1276245803Stheraven	{
1277245803Stheraven		read_header = true;
1278245803Stheraven	}
1279245803Stheraven	input.next_token();
1280245803Stheraven	while(input.consume("/include/"))
1281245803Stheraven	{
1282254522Stheraven		bool reallyInclude = true;
1283254522Stheraven		if (input.consume("if "))
1284254522Stheraven		{
1285254522Stheraven			input.next_token();
1286254522Stheraven			string name = string::parse_property_name(input);
1287254522Stheraven			// XXX: Error handling
1288254522Stheraven			if (defines.find(name) == defines.end())
1289254522Stheraven			{
1290254522Stheraven				reallyInclude = false;
1291254522Stheraven			}
1292254522Stheraven			input.consume('/');
1293254522Stheraven		}
1294245803Stheraven		input.next_token();
1295245803Stheraven		if (!input.consume('"'))
1296245803Stheraven		{
1297245803Stheraven			input.parse_error("Expected quoted filename");
1298245803Stheraven			valid = false;
1299245803Stheraven			return;
1300245803Stheraven		}
1301245803Stheraven		int length = 0;
1302245803Stheraven		while (input[length] != '"') length++;
1303245803Stheraven
1304245803Stheraven		const char *file = (const char*)input;
1305245803Stheraven		const char *dir = dirname(fn);
1306245803Stheraven		int dir_length = strlen(dir);
1307245803Stheraven		char *include_file = (char*)malloc(strlen(dir) + length + 2);
1308245803Stheraven		memcpy(include_file, dir, dir_length);
1309245803Stheraven		include_file[dir_length] = '/';
1310245803Stheraven		memcpy(include_file+dir_length+1, file, length);
1311245803Stheraven		include_file[dir_length+length+1] = 0;
1312254522Stheraven
1313254522Stheraven		input.consume(include_file+dir_length+1);
1314254522Stheraven		input.consume('"');
1315254522Stheraven		if (!reallyInclude)
1316254522Stheraven		{
1317254522Stheraven			continue;
1318254522Stheraven		}
1319254522Stheraven
1320245803Stheraven		input_buffer *include_buffer = buffer_for_file(include_file);
1321245803Stheraven
1322245803Stheraven		if (include_buffer == 0)
1323245803Stheraven		{
1324245803Stheraven			for (std::vector<const char*>::iterator i=include_paths.begin(), e=include_paths.end() ; e!=i ; ++i)
1325245803Stheraven			{
1326245803Stheraven				free(include_file);
1327245803Stheraven				dir = *i;
1328245803Stheraven				dir_length = strlen(dir);
1329245803Stheraven				include_file = (char*)malloc(strlen(dir) +
1330245803Stheraven						length + 2);
1331245803Stheraven				memcpy(include_file, dir, dir_length);
1332245803Stheraven				include_file[dir_length] = '/';
1333245803Stheraven				memcpy(include_file+dir_length+1, file, length);
1334245803Stheraven				include_file[dir_length+length+1] = 0;
1335245803Stheraven				include_buffer = buffer_for_file(include_file);
1336245803Stheraven				if (include_buffer != 0)
1337245803Stheraven				{
1338245803Stheraven					break;
1339245803Stheraven				}
1340245803Stheraven			}
1341245803Stheraven		}
1342245803Stheraven		if (depfile != 0)
1343245803Stheraven		{
1344245803Stheraven			putc(' ', depfile);
1345245803Stheraven			fputs(include_file, depfile);
1346245803Stheraven		}
1347245803Stheraven		if (include_buffer == 0)
1348245803Stheraven		{
1349245803Stheraven			valid = false;
1350245803Stheraven			return;
1351245803Stheraven		}
1352245803Stheraven		input_buffer &include = *include_buffer;
1353245803Stheraven		free((void*)include_file);
1354245803Stheraven
1355245803Stheraven		if (!read_header)
1356245803Stheraven		{
1357245803Stheraven			include.next_token();
1358245803Stheraven			read_header = include.consume("/dts-v1/;");
1359245803Stheraven		}
1360245803Stheraven		parse_roots(include, roots);
1361245803Stheraven	}
1362245803Stheraven	input.next_token();
1363245803Stheraven	if (!read_header)
1364245803Stheraven	{
1365245803Stheraven		input.parse_error("Expected /dts-v1/; version string");
1366245803Stheraven	}
1367245803Stheraven	// Read any memory reservations
1368245803Stheraven	while(input.consume("/memreserve/"))
1369245803Stheraven	{
1370245803Stheraven		long long start, len;
1371245803Stheraven		input.next_token();
1372245803Stheraven		// Read the start and length.
1373245803Stheraven		if (!(input.consume_integer(start) &&
1374245803Stheraven		    (input.next_token(),
1375245803Stheraven		    input.consume_integer(len))))
1376245803Stheraven		{
1377266313Sian			input.parse_error("Expected size on /memreserve/ node.");
1378245803Stheraven		}
1379245803Stheraven		input.next_token();
1380245803Stheraven		input.consume(';');
1381245803Stheraven		reservations.push_back(reservation(start, len));
1382245803Stheraven	}
1383245803Stheraven	parse_roots(input, roots);
1384245803Stheraven	switch (roots.size())
1385245803Stheraven	{
1386245803Stheraven		case 0:
1387245803Stheraven			valid = false;
1388245803Stheraven			input.parse_error("Failed to find root node /.");
1389245803Stheraven			return;
1390245803Stheraven		case 1:
1391245803Stheraven			root = roots[0];
1392245803Stheraven			break;
1393245803Stheraven		default:
1394245803Stheraven		{
1395245803Stheraven			root = roots[0];
1396245803Stheraven			for (std::vector<node*>::iterator i=roots.begin()+1,
1397245803Stheraven			     e=roots.end() ; i!=e ; ++i)
1398245803Stheraven			{
1399245803Stheraven				root->merge_node(*i);
1400245803Stheraven				delete *i;
1401245803Stheraven			}
1402245803Stheraven			roots.resize(1);
1403245803Stheraven		}
1404245803Stheraven	}
1405245803Stheraven	collect_names();
1406245803Stheraven	resolve_cross_references();
1407245803Stheraven}
1408245803Stheraven
1409245803Stheravendevice_tree::~device_tree()
1410245803Stheraven{
1411245803Stheraven	if (root != 0)
1412245803Stheraven	{
1413245803Stheraven		delete root;
1414245803Stheraven	}
1415245803Stheraven	while (!buffers.empty())
1416245803Stheraven	{
1417245803Stheraven		delete buffers.back();
1418245803Stheraven		buffers.pop_back();
1419245803Stheraven	}
1420254522Stheraven	for (define_map::iterator i=defines.begin(), e=defines.end() ;
1421254522Stheraven	     i!=e ; ++i)
1422254522Stheraven	{
1423254522Stheraven		delete i->second;
1424254522Stheraven	}
1425245803Stheraven}
1426245803Stheraven
1427254522Stheravenbool device_tree::parse_define(const char *def)
1428254522Stheraven{
1429254522Stheraven	char *val = strchr(def, '=');
1430254522Stheraven	if (!val)
1431254522Stheraven	{
1432254522Stheraven		if (strlen(def) != 0)
1433254522Stheraven		{
1434254522Stheraven			string name(def);
1435254522Stheraven			defines[name];
1436254522Stheraven			return true;
1437254522Stheraven		}
1438254522Stheraven		return false;
1439254522Stheraven	}
1440254522Stheraven	string name(def, val-def);
1441254522Stheraven	val++;
1442254522Stheraven	input_buffer in = input_buffer(val, strlen(val));
1443254522Stheraven	property *p = property::parse(in, name, string(), false);
1444254522Stheraven	if (p)
1445254522Stheraven		defines[name] = p;
1446254522Stheraven	return p;
1447254522Stheraven}
1448254522Stheraven
1449245803Stheraven} // namespace fdt
1450245803Stheraven
1451245803Stheraven} // namespace dtc
1452245803Stheraven
1453