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