fdt.cc revision 330449
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2013 David Chisnall
5 * All rights reserved.
6 *
7 * This software was developed by SRI International and the University of
8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9 * ("CTSRD"), as part of the DARPA CRASH research programme.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: stable/11/usr.bin/dtc/fdt.cc 330449 2018-03-05 07:26:05Z eadler $
33 */
34
35#define __STDC_LIMIT_MACROS 1
36
37#include "fdt.hh"
38#include "dtb.hh"
39
40#include <algorithm>
41#include <sstream>
42
43#include <ctype.h>
44#include <fcntl.h>
45#include <inttypes.h>
46#include <libgen.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <unistd.h>
50#include <sys/types.h>
51#include <sys/stat.h>
52#include <errno.h>
53
54using std::string;
55
56namespace dtc
57{
58
59namespace fdt
60{
61
62uint32_t
63property_value::get_as_uint32()
64{
65	if (byte_data.size() != 4)
66	{
67		return 0;
68	}
69	uint32_t v = 0;
70	v &= byte_data[0] << 24;
71	v &= byte_data[1] << 16;
72	v &= byte_data[2] << 8;
73	v &= byte_data[3] << 0;
74	return v;
75}
76
77void
78property_value::push_to_buffer(byte_buffer &buffer)
79{
80	if (!byte_data.empty())
81	{
82		buffer.insert(buffer.end(), byte_data.begin(), byte_data.end());
83	}
84	else
85	{
86		push_string(buffer, string_data, true);
87		// Trailing nul
88		buffer.push_back(0);
89	}
90}
91
92void
93property_value::write_dts(FILE *file)
94{
95	resolve_type();
96	switch (type)
97	{
98		default:
99			assert(0 && "Invalid type");
100		case STRING:
101		case STRING_LIST:
102		case CROSS_REFERENCE:
103			write_as_string(file);
104			break;
105		case PHANDLE:
106			write_as_cells(file);
107			break;
108		case BINARY:
109			if (byte_data.size() % 4 == 0)
110			{
111				write_as_cells(file);
112				break;
113			}
114			write_as_bytes(file);
115			break;
116	}
117}
118
119void
120property_value::resolve_type()
121{
122	if (type != UNKNOWN)
123	{
124		return;
125	}
126	if (byte_data.empty())
127	{
128		type = STRING;
129		return;
130	}
131	if (byte_data.back() == 0)
132	{
133		bool is_all_printable = true;
134		int nuls = 0;
135		int bytes = 0;
136		bool lastWasNull = false;
137		for (auto i : byte_data)
138		{
139			bytes++;
140			is_all_printable &= (i == '\0') || isprint(i);
141			if (i == '\0')
142			{
143				// If there are two nulls in a row, then we're probably binary.
144				if (lastWasNull)
145				{
146					type = BINARY;
147					return;
148				}
149				nuls++;
150				lastWasNull = true;
151			}
152			else
153			{
154				lastWasNull = false;
155			}
156			if (!is_all_printable)
157			{
158				break;
159			}
160		}
161		if ((is_all_printable && (bytes > nuls)) || bytes == 0)
162		{
163			type = STRING;
164			if (nuls > 1)
165			{
166				type = STRING_LIST;
167			}
168			return;
169		}
170	}
171	type = BINARY;
172}
173
174size_t
175property_value::size()
176{
177	if (!byte_data.empty())
178	{
179		return byte_data.size();
180	}
181	return string_data.size() + 1;
182}
183
184void
185property_value::write_as_string(FILE *file)
186{
187	putc('"', file);
188	if (byte_data.empty())
189	{
190		fputs(string_data.c_str(), file);
191	}
192	else
193	{
194		bool hasNull = (byte_data.back() == '\0');
195		// Remove trailing null bytes from the string before printing as dts.
196		if (hasNull)
197		{
198			byte_data.pop_back();
199		}
200		for (auto i : byte_data)
201		{
202			// FIXME Escape tabs, newlines, and so on.
203			if (i == '\0')
204			{
205				fputs("\", \"", file);
206				continue;
207			}
208			putc(i, file);
209		}
210		if (hasNull)
211		{
212			byte_data.push_back('\0');
213		}
214	}
215	putc('"', file);
216}
217
218void
219property_value::write_as_cells(FILE *file)
220{
221	putc('<', file);
222	assert((byte_data.size() % 4) == 0);
223	for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i)
224	{
225		uint32_t v = 0;
226		v = (v << 8) | *i;
227		++i;
228		v = (v << 8) | *i;
229		++i;
230		v = (v << 8) | *i;
231		++i;
232		v = (v << 8) | *i;
233		fprintf(file, "0x%" PRIx32, v);
234		if (i+1 != e)
235		{
236			putc(' ', file);
237		}
238	}
239	putc('>', file);
240}
241
242void
243property_value::write_as_bytes(FILE *file)
244{
245	putc('[', file);
246	for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; i++)
247	{
248		fprintf(file, "%02hhx", *i);
249		if (i+1 != e)
250		{
251			putc(' ', file);
252		}
253	}
254	putc(']', file);
255}
256
257void
258property::parse_string(text_input_buffer &input)
259{
260	property_value v;
261	assert(*input == '"');
262	++input;
263	std::vector<char> bytes;
264	bool isEscaped = false;
265	while (char c = *input)
266	{
267		if (c == '"' && !isEscaped)
268		{
269			input.consume('"');
270			break;
271		}
272		isEscaped = (c == '\\');
273		bytes.push_back(c);
274		++input;
275	}
276	v.string_data = string(bytes.begin(), bytes.end());
277	values.push_back(v);
278}
279
280void
281property::parse_cells(text_input_buffer &input, int cell_size)
282{
283	assert(*input == '<');
284	++input;
285	property_value v;
286	input.next_token();
287	while (!input.consume('>'))
288	{
289		input.next_token();
290		// If this is a phandle then we need to get the name of the
291		// referenced node
292		if (input.consume('&'))
293		{
294			if (cell_size != 32)
295			{
296				input.parse_error("reference only permitted in 32-bit arrays");
297				valid = false;
298				return;
299			}
300			input.next_token();
301			string referenced;
302			if (!input.consume('{'))
303			{
304				referenced = input.parse_node_name();
305			}
306			else
307			{
308				referenced = input.parse_to('}');
309				input.consume('}');
310			}
311			if (referenced.empty())
312			{
313				input.parse_error("Expected node name");
314				valid = false;
315				return;
316			}
317			input.next_token();
318			// If we already have some bytes, make the phandle a
319			// separate component.
320			if (!v.byte_data.empty())
321			{
322				values.push_back(v);
323				v = property_value();
324			}
325			v.string_data = referenced;
326			v.type = property_value::PHANDLE;
327			values.push_back(v);
328			v = property_value();
329		}
330		else
331		{
332			//FIXME: We should support labels in the middle
333			//of these, but we don't.
334			unsigned long long val;
335			if (!input.consume_integer_expression(val))
336			{
337				input.parse_error("Expected numbers in array of cells");
338				valid = false;
339				return;
340			}
341			switch (cell_size)
342			{
343				case 8:
344					v.byte_data.push_back(val);
345					break;
346				case 16:
347					push_big_endian(v.byte_data, (uint16_t)val);
348					break;
349				case 32:
350					push_big_endian(v.byte_data, (uint32_t)val);
351					break;
352				case 64:
353					push_big_endian(v.byte_data, (uint64_t)val);
354					break;
355				default:
356					assert(0 && "Invalid cell size!");
357			}
358			input.next_token();
359		}
360	}
361	// Don't store an empty string value here.
362	if (v.byte_data.size() > 0)
363	{
364		values.push_back(v);
365	}
366}
367
368void
369property::parse_bytes(text_input_buffer &input)
370{
371	assert(*input == '[');
372	++input;
373	property_value v;
374	input.next_token();
375	while (!input.consume(']'))
376	{
377		{
378			//FIXME: We should support
379			//labels in the middle of
380			//these, but we don't.
381			uint8_t val;
382			if (!input.consume_hex_byte(val))
383			{
384				input.parse_error("Expected hex bytes in array of bytes");
385				valid = false;
386				return;
387			}
388			v.byte_data.push_back(val);
389			input.next_token();
390		}
391	}
392	values.push_back(v);
393}
394
395void
396property::parse_reference(text_input_buffer &input)
397{
398	assert(*input == '&');
399	++input;
400	input.next_token();
401	property_value v;
402	v.string_data = input.parse_node_name();
403	if (v.string_data.empty())
404	{
405		input.parse_error("Expected node name");
406		valid = false;
407		return;
408	}
409	v.type = property_value::CROSS_REFERENCE;
410	values.push_back(v);
411}
412
413property::property(input_buffer &structs, input_buffer &strings)
414{
415	uint32_t name_offset;
416	uint32_t length;
417	valid = structs.consume_binary(length) &&
418		structs.consume_binary(name_offset);
419	if (!valid)
420	{
421		fprintf(stderr, "Failed to read property\n");
422		return;
423	}
424	// Find the name
425	input_buffer name_buffer = strings.buffer_from_offset(name_offset);
426	if (name_buffer.finished())
427	{
428		fprintf(stderr, "Property name offset %" PRIu32
429			" is past the end of the strings table\n",
430			name_offset);
431		valid = false;
432		return;
433	}
434	key = name_buffer.parse_to(0);
435
436	// If we're empty, do not push anything as value.
437	if (!length)
438		return;
439
440	// Read the value
441	uint8_t byte;
442	property_value v;
443	for (uint32_t i=0 ; i<length ; i++)
444	{
445		if (!(valid = structs.consume_binary(byte)))
446		{
447			fprintf(stderr, "Failed to read property value\n");
448			return;
449		}
450		v.byte_data.push_back(byte);
451	}
452	values.push_back(v);
453}
454
455void property::parse_define(text_input_buffer &input, define_map *defines)
456{
457	input.consume('$');
458	if (!defines)
459	{
460		input.parse_error("No predefined properties to match name\n");
461		valid = false;
462		return;
463	}
464	string name = input.parse_property_name();
465	define_map::iterator found;
466	if ((name == string()) ||
467	    ((found = defines->find(name)) == defines->end()))
468	{
469		input.parse_error("Undefined property name\n");
470		valid = false;
471		return;
472	}
473	values.push_back((*found).second->values[0]);
474}
475
476property::property(text_input_buffer &input,
477                   string &&k,
478                   string_set &&l,
479                   bool semicolonTerminated,
480                   define_map *defines) : key(k), labels(l), valid(true)
481{
482	do {
483		input.next_token();
484		switch (*input)
485		{
486			case '$':
487			{
488				parse_define(input, defines);
489				if (valid)
490				{
491					break;
492				}
493			}
494			default:
495				input.parse_error("Invalid property value.");
496				valid = false;
497				return;
498			case '/':
499			{
500				if (input.consume("/incbin/(\""))
501				{
502					auto loc = input.location();
503					std::string filename = input.parse_to('"');
504					if (!(valid = input.consume('"')))
505					{
506						loc.report_error("Syntax error, expected '\"' to terminate /incbin/(");
507						return;
508					}
509					property_value v;
510					if (!(valid = input.read_binary_file(filename, v.byte_data)))
511					{
512						input.parse_error("Cannot open binary include file");
513						return;
514					}
515					if (!(valid &= input.consume(')')))
516					{
517						input.parse_error("Syntax error, expected ')' to terminate /incbin/(");
518						return;
519					}
520					values.push_back(v);
521					break;
522				}
523				unsigned long long bits = 0;
524				valid = input.consume("/bits/");
525				input.next_token();
526				valid &= input.consume_integer(bits);
527				if ((bits != 8) &&
528				    (bits != 16) &&
529				    (bits != 32) &&
530				    (bits != 64)) {
531					input.parse_error("Invalid size for elements");
532					valid = false;
533				}
534				if (!valid) return;
535				input.next_token();
536				if (*input != '<')
537				{
538					input.parse_error("/bits/ directive is only valid on arrays");
539					valid = false;
540					return;
541				}
542				parse_cells(input, bits);
543				break;
544			}
545			case '"':
546				parse_string(input);
547				break;
548			case '<':
549				parse_cells(input, 32);
550				break;
551			case '[':
552				parse_bytes(input);
553				break;
554			case '&':
555				parse_reference(input);
556				break;
557			case ';':
558			{
559				break;
560			}
561		}
562		input.next_token();
563	} while (input.consume(','));
564	if (semicolonTerminated && !input.consume(';'))
565	{
566		input.parse_error("Expected ; at end of property");
567		valid = false;
568	}
569}
570
571property_ptr
572property::parse_dtb(input_buffer &structs, input_buffer &strings)
573{
574	property_ptr p(new property(structs, strings));
575	if (!p->valid)
576	{
577		p = nullptr;
578	}
579	return p;
580}
581
582property_ptr
583property::parse(text_input_buffer &input, string &&key, string_set &&label,
584                bool semicolonTerminated, define_map *defines)
585{
586	property_ptr p(new property(input,
587	                            std::move(key),
588	                            std::move(label),
589	                            semicolonTerminated,
590	                            defines));
591	if (!p->valid)
592	{
593		p = nullptr;
594	}
595	return p;
596}
597
598void
599property::write(dtb::output_writer &writer, dtb::string_table &strings)
600{
601	writer.write_token(dtb::FDT_PROP);
602	byte_buffer value_buffer;
603	for (value_iterator i=begin(), e=end() ; i!=e ; ++i)
604	{
605		i->push_to_buffer(value_buffer);
606	}
607	writer.write_data((uint32_t)value_buffer.size());
608	writer.write_comment(key);
609	writer.write_data(strings.add_string(key));
610	writer.write_data(value_buffer);
611}
612
613bool
614property_value::try_to_merge(property_value &other)
615{
616	resolve_type();
617	switch (type)
618	{
619		case UNKNOWN:
620			__builtin_unreachable();
621			assert(0);
622			return false;
623		case EMPTY:
624			*this = other;
625		case STRING:
626		case STRING_LIST:
627		case CROSS_REFERENCE:
628			return false;
629		case PHANDLE:
630		case BINARY:
631			if (other.type == PHANDLE || other.type == BINARY)
632			{
633				type = BINARY;
634				byte_data.insert(byte_data.end(), other.byte_data.begin(),
635				                 other.byte_data.end());
636				return true;
637			}
638	}
639	return false;
640}
641
642void
643property::write_dts(FILE *file, int indent)
644{
645	for (int i=0 ; i<indent ; i++)
646	{
647		putc('\t', file);
648	}
649#ifdef PRINT_LABELS
650	for (auto &l : labels)
651	{
652		fputs(l.c_str(), file);
653		fputs(": ", file);
654	}
655#endif
656	if (key != string())
657	{
658		fputs(key.c_str(), file);
659	}
660	if (!values.empty())
661	{
662		std::vector<property_value> *vals = &values;
663		std::vector<property_value> v;
664		// If we've got multiple values then try to merge them all together.
665		if (values.size() > 1)
666		{
667			vals = &v;
668			v.push_back(values.front());
669			for (auto i=(++begin()), e=end() ; i!=e ; ++i)
670			{
671				if (!v.back().try_to_merge(*i))
672				{
673					v.push_back(*i);
674				}
675			}
676		}
677		fputs(" = ", file);
678		for (auto i=vals->begin(), e=vals->end() ; i!=e ; ++i)
679		{
680			i->write_dts(file);
681			if (i+1 != e)
682			{
683				putc(',', file);
684				putc(' ', file);
685			}
686		}
687	}
688	fputs(";\n", file);
689}
690
691size_t
692property::offset_of_value(property_value &val)
693{
694	size_t off = 0;
695	for (auto &v : values)
696	{
697		if (&v == &val)
698		{
699			return off;
700		}
701		off += v.size();
702	}
703	return -1;
704}
705
706string
707node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
708{
709	if (!valid)
710	{
711		return string();
712	}
713	input.next_token();
714	if (is_property)
715	{
716		return input.parse_property_name();
717	}
718	string n = input.parse_node_or_property_name(is_property);
719	if (n.empty())
720	{
721		if (n.empty())
722		{
723			input.parse_error(error);
724			valid = false;
725		}
726	}
727	return n;
728}
729
730void
731node::visit(std::function<void(node&)> fn)
732{
733	fn(*this);
734	for (auto &&c : children)
735	{
736		c->visit(fn);
737	}
738}
739
740node::node(input_buffer &structs, input_buffer &strings) : valid(true)
741{
742	std::vector<char> bytes;
743	while (structs[0] != '\0' && structs[0] != '@')
744	{
745		bytes.push_back(structs[0]);
746		++structs;
747	}
748	name = string(bytes.begin(), bytes.end());
749	bytes.clear();
750	if (structs[0] == '@')
751	{
752		++structs;
753		while (structs[0] != '\0')
754		{
755			bytes.push_back(structs[0]);
756			++structs;
757		}
758		unit_address = string(bytes.begin(), bytes.end());
759	}
760	++structs;
761	uint32_t token;
762	while (structs.consume_binary(token))
763	{
764		switch (token)
765		{
766			default:
767				fprintf(stderr, "Unexpected token 0x%" PRIx32
768					" while parsing node.\n", token);
769				valid = false;
770				return;
771			// Child node, parse it.
772			case dtb::FDT_BEGIN_NODE:
773			{
774				node_ptr child = node::parse_dtb(structs, strings);
775				if (child == 0)
776				{
777					valid = false;
778					return;
779				}
780				children.push_back(std::move(child));
781				break;
782			}
783			// End of this node, no errors.
784			case dtb::FDT_END_NODE:
785				return;
786			// Property, parse it.
787			case dtb::FDT_PROP:
788			{
789				property_ptr prop = property::parse_dtb(structs, strings);
790				if (prop == 0)
791				{
792					valid = false;
793					return;
794				}
795				props.push_back(prop);
796				break;
797			}
798				break;
799			// End of structs table.  Should appear after
800			// the end of the last node.
801			case dtb::FDT_END:
802				fprintf(stderr, "Unexpected FDT_END token while parsing node.\n");
803				valid = false;
804				return;
805			// NOPs are padding.  Ignore them.
806			case dtb::FDT_NOP:
807				break;
808		}
809	}
810	fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
811	valid = false;
812	return;
813}
814
815
816node::node(const string &n,
817           const std::vector<property_ptr> &p)
818	: name(n)
819{
820	props.insert(props.begin(), p.begin(), p.end());
821}
822
823node_ptr node::create_special_node(const string &name,
824                                   const std::vector<property_ptr> &props)
825{
826	node_ptr n(new node(name, props));
827	return n;
828}
829
830node::node(text_input_buffer &input,
831           string &&n,
832           std::unordered_set<string> &&l,
833           string &&a,
834           define_map *defines)
835	: labels(l), name(n), unit_address(a), valid(true)
836{
837	if (!input.consume('{'))
838	{
839		input.parse_error("Expected { to start new device tree node.\n");
840	}
841	input.next_token();
842	while (valid && !input.consume('}'))
843	{
844		// flag set if we find any characters that are only in
845		// the property name character set, not the node
846		bool is_property = false;
847		string child_name, child_address;
848		std::unordered_set<string> child_labels;
849		auto parse_delete = [&](const char *expected, bool at)
850		{
851			if (child_name == string())
852			{
853				input.parse_error(expected);
854				valid = false;
855				return;
856			}
857			input.next_token();
858			if (at && input.consume('@'))
859			{
860				child_name += '@';
861				child_name += parse_name(input, is_property, "Expected unit address");
862			}
863			if (!input.consume(';'))
864			{
865				input.parse_error("Expected semicolon");
866				valid = false;
867				return;
868			}
869			input.next_token();
870		};
871		if (input.consume("/delete-node/"))
872		{
873			input.next_token();
874			child_name = input.parse_node_name();
875			parse_delete("Expected node name", true);
876			if (valid)
877			{
878				deleted_children.insert(child_name);
879			}
880			continue;
881		}
882		if (input.consume("/delete-property/"))
883		{
884			input.next_token();
885			child_name = input.parse_property_name();
886			parse_delete("Expected property name", false);
887			if (valid)
888			{
889				deleted_props.insert(child_name);
890			}
891			continue;
892		}
893		child_name = parse_name(input, is_property,
894				"Expected property or node name");
895		while (input.consume(':'))
896		{
897			// Node labels can contain any characters?  The
898			// spec doesn't say, so we guess so...
899			is_property = false;
900			child_labels.insert(std::move(child_name));
901			child_name = parse_name(input, is_property, "Expected property or node name");
902		}
903		if (input.consume('@'))
904		{
905			child_address = parse_name(input, is_property, "Expected unit address");
906		}
907		if (!valid)
908		{
909			return;
910		}
911		input.next_token();
912		// If we're parsing a property, then we must actually do that.
913		if (input.consume('='))
914		{
915			property_ptr p = property::parse(input, std::move(child_name),
916					std::move(child_labels), true, defines);
917			if (p == 0)
918			{
919				valid = false;
920			}
921			else
922			{
923				props.push_back(p);
924			}
925		}
926		else if (!is_property && *input == ('{'))
927		{
928			node_ptr child = node::parse(input, std::move(child_name),
929					std::move(child_labels), std::move(child_address), defines);
930			if (child)
931			{
932				children.push_back(std::move(child));
933			}
934			else
935			{
936				valid = false;
937			}
938		}
939		else if (input.consume(';'))
940		{
941			props.push_back(property_ptr(new property(std::move(child_name), std::move(child_labels))));
942		}
943		else
944		{
945			input.parse_error("Error parsing property.  Expected property value");
946			valid = false;
947		}
948		input.next_token();
949	}
950	input.next_token();
951	input.consume(';');
952}
953
954bool
955node::cmp_properties(property_ptr &p1, property_ptr &p2)
956{
957	return p1->get_key() < p2->get_key();
958}
959
960bool
961node::cmp_children(node_ptr &c1, node_ptr &c2)
962{
963	if (c1->name == c2->name)
964	{
965		return c1->unit_address < c2->unit_address;
966	}
967	return c1->name < c2->name;
968}
969
970void
971node::sort()
972{
973	std::sort(property_begin(), property_end(), cmp_properties);
974	std::sort(child_begin(), child_end(), cmp_children);
975	for (auto &c : child_nodes())
976	{
977		c->sort();
978	}
979}
980
981node_ptr
982node::parse(text_input_buffer &input,
983            string &&name,
984            string_set &&label,
985            string &&address,
986            define_map *defines)
987{
988	node_ptr n(new node(input,
989	                    std::move(name),
990	                    std::move(label),
991	                    std::move(address),
992	                    defines));
993	if (!n->valid)
994	{
995		n = 0;
996	}
997	return n;
998}
999
1000node_ptr
1001node::parse_dtb(input_buffer &structs, input_buffer &strings)
1002{
1003	node_ptr n(new node(structs, strings));
1004	if (!n->valid)
1005	{
1006		n = 0;
1007	}
1008	return n;
1009}
1010
1011property_ptr
1012node::get_property(const string &key)
1013{
1014	for (auto &i : props)
1015	{
1016		if (i->get_key() == key)
1017		{
1018			return i;
1019		}
1020	}
1021	return 0;
1022}
1023
1024void
1025node::merge_node(node_ptr &other)
1026{
1027	for (auto &l : other->labels)
1028	{
1029		labels.insert(l);
1030	}
1031	// Note: this is an O(n*m) operation.  It might be sensible to
1032	// optimise this if we find that there are nodes with very
1033	// large numbers of properties, but for typical usage the
1034	// entire vector will fit (easily) into cache, so iterating
1035	// over it repeatedly isn't that expensive.
1036	for (auto &p : other->properties())
1037	{
1038		bool found = false;
1039		for (auto &mp : properties())
1040		{
1041			if (mp->get_key() == p->get_key())
1042			{
1043				mp = p;
1044				found = true;
1045				break;
1046			}
1047		}
1048		if (!found)
1049		{
1050			add_property(p);
1051		}
1052	}
1053	for (auto &c : other->children)
1054	{
1055		bool found = false;
1056		for (auto &i : children)
1057		{
1058			if (i->name == c->name && i->unit_address == c->unit_address)
1059			{
1060				i->merge_node(c);
1061				found = true;
1062				break;
1063			}
1064		}
1065		if (!found)
1066		{
1067			children.push_back(std::move(c));
1068		}
1069	}
1070	children.erase(std::remove_if(children.begin(), children.end(),
1071			[&](const node_ptr &p) {
1072				string full_name = p->name;
1073				if (p->unit_address != string())
1074				{
1075					full_name += '@';
1076					full_name += p->unit_address;
1077				}
1078				if (other->deleted_children.count(full_name) > 0)
1079				{
1080					other->deleted_children.erase(full_name);
1081					return true;
1082				}
1083				return false;
1084			}), children.end());
1085	props.erase(std::remove_if(props.begin(), props.end(),
1086			[&](const property_ptr &p) {
1087				if (other->deleted_props.count(p->get_key()) > 0)
1088				{
1089					other->deleted_props.erase(p->get_key());
1090					return true;
1091				}
1092				return false;
1093			}), props.end());
1094}
1095
1096void
1097node::write(dtb::output_writer &writer, dtb::string_table &strings)
1098{
1099	writer.write_token(dtb::FDT_BEGIN_NODE);
1100	byte_buffer name_buffer;
1101	push_string(name_buffer, name);
1102	if (unit_address != string())
1103	{
1104		name_buffer.push_back('@');
1105		push_string(name_buffer, unit_address);
1106	}
1107	writer.write_comment(name);
1108	writer.write_data(name_buffer);
1109	writer.write_data((uint8_t)0);
1110	for (auto p : properties())
1111	{
1112		p->write(writer, strings);
1113	}
1114	for (auto &c : child_nodes())
1115	{
1116		c->write(writer, strings);
1117	}
1118	writer.write_token(dtb::FDT_END_NODE);
1119}
1120
1121void
1122node::write_dts(FILE *file, int indent)
1123{
1124	for (int i=0 ; i<indent ; i++)
1125	{
1126		putc('\t', file);
1127	}
1128#ifdef PRINT_LABELS
1129	for (auto &label : labels)
1130	{
1131		fprintf(file, "%s: ", label.c_str());
1132	}
1133#endif
1134	if (name != string())
1135	{
1136		fputs(name.c_str(), file);
1137	}
1138	if (unit_address != string())
1139	{
1140		putc('@', file);
1141		fputs(unit_address.c_str(), file);
1142	}
1143	fputs(" {\n\n", file);
1144	for (auto p : properties())
1145	{
1146		p->write_dts(file, indent+1);
1147	}
1148	for (auto &c : child_nodes())
1149	{
1150		c->write_dts(file, indent+1);
1151	}
1152	for (int i=0 ; i<indent ; i++)
1153	{
1154		putc('\t', file);
1155	}
1156	fputs("};\n", file);
1157}
1158
1159void
1160device_tree::collect_names_recursive(node_ptr &n, node_path &path)
1161{
1162	path.push_back(std::make_pair(n->name, n->unit_address));
1163	for (const string &name : n->labels)
1164	{
1165		if (name != string())
1166		{
1167			auto iter = node_names.find(name);
1168			if (iter == node_names.end())
1169			{
1170				node_names.insert(std::make_pair(name, n.get()));
1171				node_paths.insert(std::make_pair(name, path));
1172			}
1173			else
1174			{
1175				node_names.erase(iter);
1176				auto i = node_paths.find(name);
1177				if (i != node_paths.end())
1178				{
1179					node_paths.erase(name);
1180				}
1181				fprintf(stderr, "Label not unique: %s.  References to this label will not be resolved.\n", name.c_str());
1182			}
1183		}
1184	}
1185	for (auto &c : n->child_nodes())
1186	{
1187		collect_names_recursive(c, path);
1188	}
1189	// Now we collect the phandles and properties that reference
1190	// other nodes.
1191	for (auto &p : n->properties())
1192	{
1193		for (auto &v : *p)
1194		{
1195			if (v.is_phandle())
1196			{
1197				fixups.push_back({path, p, v});
1198			}
1199			if (v.is_cross_reference())
1200			{
1201				cross_references.push_back(&v);
1202			}
1203		}
1204		if ((p->get_key() == "phandle") ||
1205		    (p->get_key() == "linux,phandle"))
1206		{
1207			if (p->begin()->byte_data.size() != 4)
1208			{
1209				fprintf(stderr, "Invalid phandle value for node %s.  Should be a 4-byte value.\n", n->name.c_str());
1210				valid = false;
1211			}
1212			else
1213			{
1214				uint32_t phandle = p->begin()->get_as_uint32();
1215				used_phandles.insert(std::make_pair(phandle, n.get()));
1216			}
1217		}
1218	}
1219	path.pop_back();
1220}
1221
1222void
1223device_tree::collect_names()
1224{
1225	node_path p;
1226	node_names.clear();
1227	node_paths.clear();
1228	cross_references.clear();
1229	fixups.clear();
1230	collect_names_recursive(root, p);
1231}
1232
1233property_ptr
1234device_tree::assign_phandle(node *n, uint32_t &phandle)
1235{
1236	// If there is an existing phandle, use it
1237	property_ptr p = n->get_property("phandle");
1238	if (p == 0)
1239	{
1240		p = n->get_property("linux,phandle");
1241	}
1242	if (p == 0)
1243	{
1244		// Otherwise insert a new phandle node
1245		property_value v;
1246		while (used_phandles.find(phandle) != used_phandles.end())
1247		{
1248			// Note that we only don't need to
1249			// store this phandle in the set,
1250			// because we are monotonically
1251			// increasing the value of phandle and
1252			// so will only ever revisit this value
1253			// if we have used 2^32 phandles, at
1254			// which point our blob won't fit in
1255			// any 32-bit system and we've done
1256			// something badly wrong elsewhere
1257			// already.
1258			phandle++;
1259		}
1260		push_big_endian(v.byte_data, phandle++);
1261		if (phandle_node_name == BOTH || phandle_node_name == LINUX)
1262		{
1263			p.reset(new property("linux,phandle"));
1264			p->add_value(v);
1265			n->add_property(p);
1266		}
1267		if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1268		{
1269			p.reset(new property("phandle"));
1270			p->add_value(v);
1271			n->add_property(p);
1272		}
1273	}
1274
1275	return (p);
1276}
1277
1278void
1279device_tree::assign_phandles(node_ptr &n, uint32_t &next)
1280{
1281	if (!n->labels.empty())
1282	{
1283		assign_phandle(n.get(), next);
1284	}
1285
1286	for (auto &c : n->child_nodes())
1287	{
1288		assign_phandles(c, next);
1289	}
1290}
1291
1292void
1293device_tree::resolve_cross_references(uint32_t &phandle)
1294{
1295	for (auto *pv : cross_references)
1296	{
1297		node_path path = node_paths[pv->string_data];
1298		auto p = path.begin();
1299		auto pe = path.end();
1300		if (p != pe)
1301		{
1302			// Skip the first name in the path.  It's always "", and implicitly /
1303			for (++p ; p!=pe ; ++p)
1304			{
1305				pv->byte_data.push_back('/');
1306				push_string(pv->byte_data, p->first);
1307				if (!(p->second.empty()))
1308				{
1309					pv->byte_data.push_back('@');
1310					push_string(pv->byte_data, p->second);
1311				}
1312			}
1313			pv->byte_data.push_back(0);
1314		}
1315	}
1316	std::unordered_map<property_value*, fixup&> phandle_set;
1317	for (auto &i : fixups)
1318	{
1319		phandle_set.insert({&i.val, i});
1320	}
1321	std::vector<std::reference_wrapper<fixup>> sorted_phandles;
1322	root->visit([&](node &n) {
1323		for (auto &p : n.properties())
1324		{
1325			for (auto &v : *p)
1326			{
1327				auto i = phandle_set.find(&v);
1328				if (i != phandle_set.end())
1329				{
1330					sorted_phandles.push_back(i->second);
1331				}
1332			}
1333		}
1334	});
1335	assert(sorted_phandles.size() == fixups.size());
1336
1337	for (auto &i : sorted_phandles)
1338	{
1339		string target_name = i.get().val.string_data;
1340		node *target = nullptr;
1341		string possible;
1342		// If the node name is a path, then look it up by following the path,
1343		// otherwise jump directly to the named node.
1344		if (target_name[0] == '/')
1345		{
1346			string path;
1347			target = root.get();
1348			std::istringstream ss(target_name);
1349			string path_element;
1350			// Read the leading /
1351			std::getline(ss, path_element, '/');
1352			// Iterate over path elements
1353			while (!ss.eof())
1354			{
1355				path += '/';
1356				std::getline(ss, path_element, '/');
1357				std::istringstream nss(path_element);
1358				string node_name, node_address;
1359				std::getline(nss, node_name, '@');
1360				std::getline(nss, node_address, '@');
1361				node *next = nullptr;
1362				for (auto &c : target->child_nodes())
1363				{
1364					if (c->name == node_name)
1365					{
1366						if (c->unit_address == node_address)
1367						{
1368							next = c.get();
1369							break;
1370						}
1371						else
1372						{
1373							possible = path + c->name;
1374							if (c->unit_address != string())
1375							{
1376								possible += '@';
1377								possible += c->unit_address;
1378							}
1379						}
1380					}
1381				}
1382				path += node_name;
1383				if (node_address != string())
1384				{
1385					path += '@';
1386					path += node_address;
1387				}
1388				target = next;
1389				if (target == nullptr)
1390				{
1391					break;
1392				}
1393			}
1394		}
1395		else
1396		{
1397			target = node_names[target_name];
1398		}
1399		if (target == nullptr)
1400		{
1401			if (is_plugin)
1402			{
1403				unresolved_fixups.push_back(i);
1404				continue;
1405			}
1406			else
1407			{
1408				fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str());
1409				if (possible != string())
1410				{
1411					fprintf(stderr, "Possible intended match: %s\n", possible.c_str());
1412				}
1413				valid = 0;
1414				return;
1415			}
1416		}
1417		// If there is an existing phandle, use it
1418		property_ptr p = assign_phandle(target, phandle);
1419		p->begin()->push_to_buffer(i.get().val.byte_data);
1420		assert(i.get().val.byte_data.size() == 4);
1421	}
1422}
1423
1424
1425void
1426device_tree::parse_file(text_input_buffer &input,
1427                        std::vector<node_ptr> &roots,
1428                        bool &read_header)
1429{
1430	input.next_token();
1431	// Read the header
1432	if (input.consume("/dts-v1/;"))
1433	{
1434		read_header = true;
1435	}
1436	input.next_token();
1437	if (input.consume("/plugin/;"))
1438	{
1439		is_plugin = true;
1440	}
1441	input.next_token();
1442	if (!read_header)
1443	{
1444		input.parse_error("Expected /dts-v1/; version string");
1445	}
1446	// Read any memory reservations
1447	while (input.consume("/memreserve/"))
1448	{
1449		unsigned long long start, len;
1450		input.next_token();
1451		// Read the start and length.
1452		if (!(input.consume_integer_expression(start) &&
1453		    (input.next_token(),
1454		    input.consume_integer_expression(len))))
1455		{
1456			input.parse_error("Expected size on /memreserve/ node.");
1457		}
1458		input.next_token();
1459		input.consume(';');
1460		reservations.push_back(reservation(start, len));
1461		input.next_token();
1462	}
1463	while (valid && !input.finished())
1464	{
1465		node_ptr n;
1466		if (input.consume('/'))
1467		{
1468			input.next_token();
1469			n = node::parse(input, string(), string_set(), string(), &defines);
1470		}
1471		else if (input.consume('&'))
1472		{
1473			input.next_token();
1474			string name = input.parse_node_name();
1475			input.next_token();
1476			n = node::parse(input, std::move(name), string_set(), string(), &defines);
1477		}
1478		else
1479		{
1480			input.parse_error("Failed to find root node /.");
1481		}
1482		if (n)
1483		{
1484			roots.push_back(std::move(n));
1485		}
1486		else
1487		{
1488			valid = false;
1489		}
1490		input.next_token();
1491	}
1492}
1493
1494template<class writer> void
1495device_tree::write(int fd)
1496{
1497	dtb::string_table st;
1498	dtb::header head;
1499	writer head_writer;
1500	writer reservation_writer;
1501	writer struct_writer;
1502	writer strings_writer;
1503
1504	// Build the reservation table
1505	reservation_writer.write_comment(string("Memory reservations"));
1506	reservation_writer.write_label(string("dt_reserve_map"));
1507	for (auto &i : reservations)
1508	{
1509		reservation_writer.write_comment(string("Reservation start"));
1510		reservation_writer.write_data(i.first);
1511		reservation_writer.write_comment(string("Reservation length"));
1512		reservation_writer.write_data(i.first);
1513	}
1514	// Write n spare reserve map entries, plus the trailing 0.
1515	for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++)
1516	{
1517		reservation_writer.write_data((uint64_t)0);
1518		reservation_writer.write_data((uint64_t)0);
1519	}
1520
1521
1522	struct_writer.write_comment(string("Device tree"));
1523	struct_writer.write_label(string("dt_struct_start"));
1524	root->write(struct_writer, st);
1525	struct_writer.write_token(dtb::FDT_END);
1526	struct_writer.write_label(string("dt_struct_end"));
1527
1528	st.write(strings_writer);
1529	// Find the strings size before we stick padding on the end.
1530	// Note: We should possibly use a new writer for the padding.
1531	head.size_dt_strings = strings_writer.size();
1532
1533	// Stick the padding in the strings writer, but after the
1534	// marker indicating that it's the end.
1535	// Note: We probably should add a padding call to the writer so
1536	// that the asm back end can write padding directives instead
1537	// of a load of 0 bytes.
1538	for (uint32_t i=0 ; i<blob_padding ; i++)
1539	{
1540		strings_writer.write_data((uint8_t)0);
1541	}
1542	head.totalsize = sizeof(head) + strings_writer.size() +
1543		struct_writer.size() + reservation_writer.size();
1544	while (head.totalsize < minimum_blob_size)
1545	{
1546		head.totalsize++;
1547		strings_writer.write_data((uint8_t)0);
1548	}
1549	head.off_dt_struct = sizeof(head) + reservation_writer.size();;
1550	head.off_dt_strings = head.off_dt_struct + struct_writer.size();
1551	head.off_mem_rsvmap = sizeof(head);
1552	head.boot_cpuid_phys = boot_cpu;
1553	head.size_dt_struct = struct_writer.size();
1554	head.write(head_writer);
1555
1556	head_writer.write_to_file(fd);
1557	reservation_writer.write_to_file(fd);
1558	struct_writer.write_to_file(fd);
1559	strings_writer.write_label(string("dt_blob_end"));
1560	strings_writer.write_to_file(fd);
1561}
1562
1563node*
1564device_tree::referenced_node(property_value &v)
1565{
1566	if (v.is_phandle())
1567	{
1568		return node_names[v.string_data];
1569	}
1570	if (v.is_binary())
1571	{
1572		return used_phandles[v.get_as_uint32()];
1573	}
1574	return 0;
1575}
1576
1577void
1578device_tree::write_binary(int fd)
1579{
1580	write<dtb::binary_writer>(fd);
1581}
1582
1583void
1584device_tree::write_asm(int fd)
1585{
1586	write<dtb::asm_writer>(fd);
1587}
1588
1589void
1590device_tree::write_dts(int fd)
1591{
1592	FILE *file = fdopen(fd, "w");
1593	fputs("/dts-v1/;\n\n", file);
1594
1595	if (!reservations.empty())
1596	{
1597		const char msg[] = "/memreserve/";
1598		fwrite(msg, sizeof(msg), 1, file);
1599		for (auto &i : reservations)
1600		{
1601			fprintf(file, " %" PRIx64 " %" PRIx64, i.first, i.second);
1602		}
1603		fputs(";\n\n", file);
1604	}
1605	putc('/', file);
1606	putc(' ', file);
1607	root->write_dts(file, 0);
1608	fclose(file);
1609}
1610
1611void
1612device_tree::parse_dtb(const string &fn, FILE *)
1613{
1614	auto in = input_buffer::buffer_for_file(fn);
1615	if (in == 0)
1616	{
1617		valid = false;
1618		return;
1619	}
1620	input_buffer &input = *in;
1621	dtb::header h;
1622	valid = h.read_dtb(input);
1623	boot_cpu = h.boot_cpuid_phys;
1624	if (h.last_comp_version > 17)
1625	{
1626		fprintf(stderr, "Don't know how to read this version of the device tree blob");
1627		valid = false;
1628	}
1629	if (!valid)
1630	{
1631		return;
1632	}
1633	input_buffer reservation_map =
1634		input.buffer_from_offset(h.off_mem_rsvmap, 0);
1635	uint64_t start, length;
1636	do
1637	{
1638		if (!(reservation_map.consume_binary(start) &&
1639		      reservation_map.consume_binary(length)))
1640		{
1641			fprintf(stderr, "Failed to read memory reservation table\n");
1642			valid = false;
1643			return;
1644		}
1645	} while (!((start == 0) && (length == 0)));
1646	input_buffer struct_table =
1647		input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct);
1648	input_buffer strings_table =
1649		input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings);
1650	uint32_t token;
1651	if (!(struct_table.consume_binary(token) &&
1652		(token == dtb::FDT_BEGIN_NODE)))
1653	{
1654		fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n");
1655		valid = false;
1656		return;
1657	}
1658	root = node::parse_dtb(struct_table, strings_table);
1659	if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END)))
1660	{
1661		fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1662		valid = false;
1663		return;
1664	}
1665	valid = (root != 0);
1666}
1667
1668string
1669device_tree::node_path::to_string() const
1670{
1671	string path;
1672	auto p = begin();
1673	auto pe = end();
1674	if ((p == pe) || (p+1 == pe))
1675	{
1676		return string("/");
1677	}
1678	// Skip the first name in the path.  It's always "", and implicitly /
1679	for (++p ; p!=pe ; ++p)
1680	{
1681		path += '/';
1682		path += p->first;
1683		if (!(p->second.empty()))
1684		{
1685			path += '@';
1686			path += p->second;
1687		}
1688	}
1689	return path;
1690}
1691
1692node_ptr
1693device_tree::create_fragment_wrapper(node_ptr &node, int &fragnum)
1694{
1695	// In a plugin, we can massage these non-/ root nodes into into a fragment
1696	std::string fragment_address = "fragment@" + std::to_string(fragnum);
1697	++fragnum;
1698
1699	std::vector<property_ptr> symbols;
1700
1701	// Intentionally left empty
1702	node_ptr newroot = node::create_special_node("", symbols);
1703	node_ptr wrapper = node::create_special_node("__overlay__", symbols);
1704
1705	// Generate the fragment with target = <&name>
1706	property_value v;
1707	v.string_data = node->name;
1708	v.type = property_value::PHANDLE;
1709	auto prop = std::make_shared<property>(std::string("target"));
1710	prop->add_value(v);
1711	symbols.push_back(prop);
1712
1713	node_ptr fragment = node::create_special_node(fragment_address, symbols);
1714
1715	wrapper->merge_node(node);
1716	fragment->add_child(std::move(wrapper));
1717	newroot->add_child(std::move(fragment));
1718	return newroot;
1719}
1720
1721node_ptr
1722device_tree::generate_root(node_ptr &node, int &fragnum)
1723{
1724
1725	string name = node->name;
1726	if (name == string())
1727	{
1728		return std::move(node);
1729	}
1730	else if (!is_plugin)
1731	{
1732		return nullptr;
1733	}
1734
1735	return create_fragment_wrapper(node, fragnum);
1736}
1737
1738void
1739device_tree::reassign_fragment_numbers(node_ptr &node, int &delta)
1740{
1741
1742	for (auto &c : node->child_nodes())
1743	{
1744		if (c->name == std::string("fragment"))
1745		{
1746			int current_address = std::stoi(c->unit_address, nullptr, 16);
1747			std::ostringstream new_address;
1748			current_address += delta;
1749			// It's possible that we hopped more than one somewhere, so just reset
1750			// delta to the next in sequence.
1751			delta = current_address + 1;
1752			new_address << std::hex << current_address;
1753			c->unit_address = new_address.str();
1754		}
1755	}
1756}
1757
1758void
1759device_tree::parse_dts(const string &fn, FILE *depfile)
1760{
1761	auto in = input_buffer::buffer_for_file(fn);
1762	if (!in)
1763	{
1764		valid = false;
1765		return;
1766	}
1767	std::vector<node_ptr> roots;
1768	std::unordered_set<string> defnames;
1769	for (auto &i : defines)
1770	{
1771		defnames.insert(i.first);
1772	}
1773	text_input_buffer input(std::move(in),
1774	                        std::move(defnames),
1775	                        std::vector<string>(include_paths),
1776	                        dirname(fn),
1777	                        depfile);
1778	bool read_header = false;
1779	int fragnum = 0;
1780	parse_file(input, roots, read_header);
1781	switch (roots.size())
1782	{
1783		case 0:
1784			valid = false;
1785			input.parse_error("Failed to find root node /.");
1786			return;
1787		case 1:
1788			root = generate_root(roots[0], fragnum);
1789			if (!root)
1790			{
1791				valid = false;
1792				input.parse_error("Failed to find root node /.");
1793				return;
1794			}
1795			break;
1796		default:
1797		{
1798			root = generate_root(roots[0], fragnum);
1799			if (!root)
1800			{
1801				valid = false;
1802				input.parse_error("Failed to find root node /.");
1803				return;
1804			}
1805			for (auto i=++(roots.begin()), e=roots.end() ; i!=e ; ++i)
1806			{
1807				auto &node = *i;
1808				string name = node->name;
1809				if (name == string())
1810				{
1811					if (is_plugin)
1812					{
1813						// Re-assign any fragment numbers based on a delta of
1814						// fragnum before we merge it
1815						reassign_fragment_numbers(node, fragnum);
1816					}
1817					root->merge_node(node);
1818				}
1819				else
1820				{
1821					auto existing = node_names.find(name);
1822					if (existing == node_names.end())
1823					{
1824						collect_names();
1825						existing = node_names.find(name);
1826					}
1827					if (existing == node_names.end())
1828					{
1829						if (is_plugin)
1830						{
1831							auto fragment = create_fragment_wrapper(node, fragnum);
1832							root->merge_node(fragment);
1833						}
1834						else
1835						{
1836							fprintf(stderr, "Unable to merge node: %s\n", name.c_str());
1837						}
1838					}
1839					else
1840					{
1841						existing->second->merge_node(node);
1842					}
1843				}
1844			}
1845		}
1846	}
1847	collect_names();
1848	uint32_t phandle = 1;
1849	// If we're writing symbols, go ahead and assign phandles to the entire
1850	// tree. We'll do this before we resolve cross references, just to keep
1851	// order semi-predictable and stable.
1852	if (write_symbols)
1853	{
1854		assign_phandles(root, phandle);
1855	}
1856	resolve_cross_references(phandle);
1857	if (write_symbols)
1858	{
1859		std::vector<property_ptr> symbols;
1860		// Create a symbol table.  Each label  in this device tree may be
1861		// referenced by other plugins, so we create a __symbols__ node inside
1862		// the root that contains mappings (properties) from label names to
1863		// paths.
1864		for (auto &s : node_paths)
1865		{
1866			property_value v;
1867			v.string_data = s.second.to_string();
1868			v.type = property_value::STRING;
1869			string name = s.first;
1870			auto prop = std::make_shared<property>(std::move(name));
1871			prop->add_value(v);
1872			symbols.push_back(prop);
1873		}
1874		root->add_child(node::create_special_node("__symbols__", symbols));
1875		// If this is a plugin, then we also need to create two extra nodes.
1876		// Internal phandles will need to be renumbered to avoid conflicts with
1877		// already-loaded nodes and external references will need to be
1878		// resolved.
1879		if (is_plugin)
1880		{
1881			// Create the fixups entry.  This is of the form:
1882			// {target} = {path}:{property name}:{offset}
1883			auto create_fixup_entry = [&](fixup &i, string target)
1884				{
1885					string value = i.path.to_string();
1886					value += ':';
1887					value += i.prop->get_key();
1888					value += ':';
1889					value += std::to_string(i.prop->offset_of_value(i.val));
1890					property_value v;
1891					v.string_data = value;
1892					v.type = property_value::STRING;
1893					auto prop = std::make_shared<property>(std::move(target));
1894					prop->add_value(v);
1895					return prop;
1896				};
1897			// If we have any unresolved phandle references in this plugin,
1898			// then we must update them to 0xdeadbeef and leave a property in
1899			// the /__fixups__ node whose key is the label and whose value is
1900			// as described above.
1901			if (!unresolved_fixups.empty())
1902			{
1903				symbols.clear();
1904				for (auto &i : unresolved_fixups)
1905				{
1906					auto &val = i.get().val;
1907					symbols.push_back(create_fixup_entry(i, val.string_data));
1908					val.byte_data.push_back(0xde);
1909					val.byte_data.push_back(0xad);
1910					val.byte_data.push_back(0xbe);
1911					val.byte_data.push_back(0xef);
1912					val.type = property_value::BINARY;
1913				}
1914				root->add_child(node::create_special_node("__fixups__", symbols));
1915			}
1916			symbols.clear();
1917			// If we have any resolved phandle references in this plugin, then
1918			// we must create a child in the __local_fixups__ node whose path
1919			// matches the node path from the root and whose value contains the
1920			// location of the reference within a property.
1921
1922			// Create a local_fixups node that is initially empty.
1923			node_ptr local_fixups = node::create_special_node("__local_fixups__", symbols);
1924			for (auto &i : fixups)
1925			{
1926				if (!i.val.is_phandle())
1927				{
1928					continue;
1929				}
1930				node *n = local_fixups.get();
1931				for (auto &p : i.path)
1932				{
1933					// Skip the implicit root
1934					if (p.first.empty())
1935					{
1936						continue;
1937					}
1938					bool found = false;
1939					for (auto &c : n->child_nodes())
1940					{
1941						if (c->name == p.first)
1942						{
1943							n = c.get();
1944							found = true;
1945							break;
1946						}
1947					}
1948					if (!found)
1949					{
1950						n->add_child(node::create_special_node(p.first, symbols));
1951						n = (--n->child_end())->get();
1952					}
1953				}
1954				assert(n);
1955				property_value pv;
1956				push_big_endian(pv.byte_data, static_cast<uint32_t>(i.prop->offset_of_value(i.val)));
1957				pv.type = property_value::BINARY;
1958				auto key = i.prop->get_key();
1959				property_ptr prop = n->get_property(key);
1960				// If we don't have an existing property then create one and
1961				// use this property value
1962				if (!prop)
1963				{
1964					prop = std::make_shared<property>(std::move(key));
1965					n->add_property(prop);
1966					prop->add_value(pv);
1967				}
1968				else
1969				{
1970					// If we do have an existing property value, try to append
1971					// this value.
1972					property_value &old_val = *(--prop->end());
1973					if (!old_val.try_to_merge(pv))
1974					{
1975						prop->add_value(pv);
1976					}
1977				}
1978			}
1979			// We've iterated over all fixups, but only emit the
1980			// __local_fixups__ if we found some that were resolved internally.
1981			if (local_fixups->child_begin() != local_fixups->child_end())
1982			{
1983				root->add_child(std::move(local_fixups));
1984			}
1985		}
1986	}
1987}
1988
1989bool device_tree::parse_define(const char *def)
1990{
1991	const char *val = strchr(def, '=');
1992	if (!val)
1993	{
1994		if (strlen(def) != 0)
1995		{
1996			string name(def);
1997			defines[name];
1998			return true;
1999		}
2000		return false;
2001	}
2002	string name(def, val-def);
2003	string name_copy = name;
2004	val++;
2005	std::unique_ptr<input_buffer> raw(new input_buffer(val, strlen(val)));
2006	text_input_buffer in(std::move(raw),
2007	                     std::unordered_set<string>(),
2008	                     std::vector<string>(),
2009	                     string(),
2010	                     nullptr);
2011	property_ptr p = property::parse(in, std::move(name_copy), string_set(), false);
2012	if (p)
2013		defines[name] = p;
2014	return (bool)p;
2015}
2016
2017} // namespace fdt
2018
2019} // namespace dtc
2020
2021