xref: /freebsd/usr.bin/dtc/fdt.cc (revision 29a55fd09b0a3cc4c888f7a630fde41694699343)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 
33 #define __STDC_LIMIT_MACROS 1
34 
35 #include "fdt.hh"
36 #include "dtb.hh"
37 
38 #include <algorithm>
39 #include <limits>
40 #include <sstream>
41 
42 #include <ctype.h>
43 #include <fcntl.h>
44 #include <inttypes.h>
45 #include <libgen.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <errno.h>
53 
54 using std::string;
55 
56 namespace dtc
57 {
58 
59 namespace fdt
60 {
61 
62 uint32_t
get_as_uint32()63 property_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 
77 void
push_to_buffer(byte_buffer & buffer)78 property_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 
92 void
write_dts(FILE * file)93 property_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 
119 void
resolve_type()120 property_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 
174 size_t
size()175 property_value::size()
176 {
177 	if (!byte_data.empty())
178 	{
179 		return byte_data.size();
180 	}
181 	return string_data.size() + 1;
182 }
183 
184 void
write_as_string(FILE * file)185 property_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 
218 void
write_as_cells(FILE * file)219 property_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 
242 void
write_as_bytes(FILE * file)243 property_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 
257 void
parse_string(text_input_buffer & input)258 property::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 
280 void
parse_cells(text_input_buffer & input,int cell_size)281 property::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 				// FIXME: Distinguish invalid syntax from a
338 				// number that cannot be represented in an
339 				// unsigned long long.
340 				input.parse_error("Expected numbers in array of cells");
341 				valid = false;
342 				return;
343 			}
344 			// FIXME: No sign information available, so cannot
345 			// distinguish small negative values from large
346 			// positive ones, and thus we have to conservatively
347 			// permit anything that looks like a sign-extended
348 			// negative integer.
349 			if (cell_size < 64 && val >= (1ull << cell_size) &&
350 			    (val | ((1ull << (cell_size - 1)) - 1)) !=
351 			    std::numeric_limits<unsigned long long>::max())
352 			{
353 				std::string msg = "Value does not fit in a " +
354 					std::to_string(cell_size) + "-bit cell";
355 				input.parse_error(msg.c_str());
356 				valid = false;
357 				return;
358 			}
359 			switch (cell_size)
360 			{
361 				case 8:
362 					v.byte_data.push_back(val);
363 					break;
364 				case 16:
365 					push_big_endian(v.byte_data, (uint16_t)val);
366 					break;
367 				case 32:
368 					push_big_endian(v.byte_data, (uint32_t)val);
369 					break;
370 				case 64:
371 					push_big_endian(v.byte_data, (uint64_t)val);
372 					break;
373 				default:
374 					assert(0 && "Invalid cell size!");
375 			}
376 			input.next_token();
377 		}
378 	}
379 	// Don't store an empty string value here.
380 	if (v.byte_data.size() > 0)
381 	{
382 		values.push_back(v);
383 	}
384 }
385 
386 void
parse_bytes(text_input_buffer & input)387 property::parse_bytes(text_input_buffer &input)
388 {
389 	assert(*input == '[');
390 	++input;
391 	property_value v;
392 	input.next_token();
393 	while (!input.consume(']'))
394 	{
395 		{
396 			//FIXME: We should support
397 			//labels in the middle of
398 			//these, but we don't.
399 			uint8_t val;
400 			if (!input.consume_hex_byte(val))
401 			{
402 				input.parse_error("Expected hex bytes in array of bytes");
403 				valid = false;
404 				return;
405 			}
406 			v.byte_data.push_back(val);
407 			input.next_token();
408 		}
409 	}
410 	values.push_back(v);
411 }
412 
413 void
parse_reference(text_input_buffer & input)414 property::parse_reference(text_input_buffer &input)
415 {
416 	assert(*input == '&');
417 	++input;
418 	input.next_token();
419 	property_value v;
420 	v.string_data = input.parse_node_name();
421 	if (v.string_data.empty())
422 	{
423 		input.parse_error("Expected node name");
424 		valid = false;
425 		return;
426 	}
427 	v.type = property_value::CROSS_REFERENCE;
428 	values.push_back(v);
429 }
430 
property(input_buffer & structs,input_buffer & strings)431 property::property(input_buffer &structs, input_buffer &strings)
432 {
433 	uint32_t name_offset;
434 	uint32_t length;
435 	valid = structs.consume_binary(length) &&
436 		structs.consume_binary(name_offset);
437 	if (!valid)
438 	{
439 		fprintf(stderr, "Failed to read property\n");
440 		return;
441 	}
442 	// Find the name
443 	input_buffer name_buffer = strings.buffer_from_offset(name_offset);
444 	if (name_buffer.finished())
445 	{
446 		fprintf(stderr, "Property name offset %" PRIu32
447 			" is past the end of the strings table\n",
448 			name_offset);
449 		valid = false;
450 		return;
451 	}
452 	key = name_buffer.parse_to(0);
453 
454 	// If we're empty, do not push anything as value.
455 	if (!length)
456 		return;
457 
458 	// Read the value
459 	uint8_t byte;
460 	property_value v;
461 	for (uint32_t i=0 ; i<length ; i++)
462 	{
463 		if (!(valid = structs.consume_binary(byte)))
464 		{
465 			fprintf(stderr, "Failed to read property value\n");
466 			return;
467 		}
468 		v.byte_data.push_back(byte);
469 	}
470 	values.push_back(v);
471 }
472 
parse_define(text_input_buffer & input,define_map * defines)473 void property::parse_define(text_input_buffer &input, define_map *defines)
474 {
475 	input.consume('$');
476 	if (!defines)
477 	{
478 		input.parse_error("No predefined properties to match name\n");
479 		valid = false;
480 		return;
481 	}
482 	string name = input.parse_property_name();
483 	define_map::iterator found;
484 	if ((name == string()) ||
485 	    ((found = defines->find(name)) == defines->end()))
486 	{
487 		input.parse_error("Undefined property name\n");
488 		valid = false;
489 		return;
490 	}
491 	values.push_back((*found).second->values[0]);
492 }
493 
property(text_input_buffer & input,string && k,string_set && l,bool semicolonTerminated,define_map * defines)494 property::property(text_input_buffer &input,
495                    string &&k,
496                    string_set &&l,
497                    bool semicolonTerminated,
498                    define_map *defines) : key(k), labels(l), valid(true)
499 {
500 	do {
501 		input.next_token();
502 		switch (*input)
503 		{
504 			case '$':
505 			{
506 				parse_define(input, defines);
507 				if (valid)
508 				{
509 					break;
510 				}
511 			}
512 			[[fallthrough]];
513 			default:
514 				input.parse_error("Invalid property value.");
515 				valid = false;
516 				return;
517 			case '/':
518 			{
519 				if (input.consume("/incbin/(\""))
520 				{
521 					auto loc = input.location();
522 					std::string filename = input.parse_to('"');
523 					if (!(valid = input.consume('"')))
524 					{
525 						loc.report_error("Syntax error, expected '\"' to terminate /incbin/(");
526 						return;
527 					}
528 					property_value v;
529 					if (!(valid = input.read_binary_file(filename, v.byte_data)))
530 					{
531 						input.parse_error("Cannot open binary include file");
532 						return;
533 					}
534 					if (!(valid &= input.consume(')')))
535 					{
536 						input.parse_error("Syntax error, expected ')' to terminate /incbin/(");
537 						return;
538 					}
539 					values.push_back(v);
540 					break;
541 				}
542 				unsigned long long bits = 0;
543 				valid = input.consume("/bits/");
544 				input.next_token();
545 				valid &= input.consume_integer(bits);
546 				if ((bits != 8) &&
547 				    (bits != 16) &&
548 				    (bits != 32) &&
549 				    (bits != 64)) {
550 					input.parse_error("Invalid size for elements");
551 					valid = false;
552 				}
553 				if (!valid) return;
554 				input.next_token();
555 				if (*input != '<')
556 				{
557 					input.parse_error("/bits/ directive is only valid on arrays");
558 					valid = false;
559 					return;
560 				}
561 				parse_cells(input, bits);
562 				break;
563 			}
564 			case '"':
565 				parse_string(input);
566 				break;
567 			case '<':
568 				parse_cells(input, 32);
569 				break;
570 			case '[':
571 				parse_bytes(input);
572 				break;
573 			case '&':
574 				parse_reference(input);
575 				break;
576 			case ';':
577 			{
578 				break;
579 			}
580 		}
581 		input.next_token();
582 	} while (input.consume(','));
583 	if (semicolonTerminated && !input.consume(';'))
584 	{
585 		input.parse_error("Expected ; at end of property");
586 		valid = false;
587 	}
588 }
589 
590 property_ptr
parse_dtb(input_buffer & structs,input_buffer & strings)591 property::parse_dtb(input_buffer &structs, input_buffer &strings)
592 {
593 	property_ptr p(new property(structs, strings));
594 	if (!p->valid)
595 	{
596 		p = nullptr;
597 	}
598 	return p;
599 }
600 
601 property_ptr
parse(text_input_buffer & input,string && key,string_set && label,bool semicolonTerminated,define_map * defines)602 property::parse(text_input_buffer &input, string &&key, string_set &&label,
603                 bool semicolonTerminated, define_map *defines)
604 {
605 	property_ptr p(new property(input,
606 	                            std::move(key),
607 	                            std::move(label),
608 	                            semicolonTerminated,
609 	                            defines));
610 	if (!p->valid)
611 	{
612 		p = nullptr;
613 	}
614 	return p;
615 }
616 
617 void
write(dtb::output_writer & writer,dtb::string_table & strings)618 property::write(dtb::output_writer &writer, dtb::string_table &strings)
619 {
620 	writer.write_token(dtb::FDT_PROP);
621 	byte_buffer value_buffer;
622 	for (value_iterator i=begin(), e=end() ; i!=e ; ++i)
623 	{
624 		i->push_to_buffer(value_buffer);
625 	}
626 	writer.write_data((uint32_t)value_buffer.size());
627 	writer.write_comment(key);
628 	writer.write_data(strings.add_string(key));
629 	writer.write_data(value_buffer);
630 }
631 
632 bool
try_to_merge(property_value & other)633 property_value::try_to_merge(property_value &other)
634 {
635 	resolve_type();
636 	switch (type)
637 	{
638 		case UNKNOWN:
639 			__builtin_unreachable();
640 			assert(0);
641 			return false;
642 		case EMPTY:
643 			*this = other;
644 			[[fallthrough]];
645 		case STRING:
646 		case STRING_LIST:
647 		case CROSS_REFERENCE:
648 			return false;
649 		case PHANDLE:
650 		case BINARY:
651 			if (other.type == PHANDLE || other.type == BINARY)
652 			{
653 				type = BINARY;
654 				byte_data.insert(byte_data.end(), other.byte_data.begin(),
655 				                 other.byte_data.end());
656 				return true;
657 			}
658 	}
659 	return false;
660 }
661 
662 void
write_dts(FILE * file,int indent)663 property::write_dts(FILE *file, int indent)
664 {
665 	for (int i=0 ; i<indent ; i++)
666 	{
667 		putc('\t', file);
668 	}
669 #ifdef PRINT_LABELS
670 	for (auto &l : labels)
671 	{
672 		fputs(l.c_str(), file);
673 		fputs(": ", file);
674 	}
675 #endif
676 	if (key != string())
677 	{
678 		fputs(key.c_str(), file);
679 	}
680 	if (!values.empty())
681 	{
682 		std::vector<property_value> *vals = &values;
683 		std::vector<property_value> v;
684 		// If we've got multiple values then try to merge them all together.
685 		if (values.size() > 1)
686 		{
687 			vals = &v;
688 			v.push_back(values.front());
689 			for (auto i=(++begin()), e=end() ; i!=e ; ++i)
690 			{
691 				if (!v.back().try_to_merge(*i))
692 				{
693 					v.push_back(*i);
694 				}
695 			}
696 		}
697 		fputs(" = ", file);
698 		for (auto i=vals->begin(), e=vals->end() ; i!=e ; ++i)
699 		{
700 			i->write_dts(file);
701 			if (i+1 != e)
702 			{
703 				putc(',', file);
704 				putc(' ', file);
705 			}
706 		}
707 	}
708 	fputs(";\n", file);
709 }
710 
711 size_t
offset_of_value(property_value & val)712 property::offset_of_value(property_value &val)
713 {
714 	size_t off = 0;
715 	for (auto &v : values)
716 	{
717 		if (&v == &val)
718 		{
719 			return off;
720 		}
721 		off += v.size();
722 	}
723 	return -1;
724 }
725 
726 string
parse_name(text_input_buffer & input,bool & is_property,const char * error)727 node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
728 {
729 	if (!valid)
730 	{
731 		return string();
732 	}
733 	input.next_token();
734 	if (is_property)
735 	{
736 		return input.parse_property_name();
737 	}
738 	string n = input.parse_node_or_property_name(is_property);
739 	if (n.empty())
740 	{
741 		if (n.empty())
742 		{
743 			input.parse_error(error);
744 			valid = false;
745 		}
746 	}
747 	return n;
748 }
749 
750 node::visit_behavior
visit(std::function<visit_behavior (node &,node *)> fn,node * parent)751 node::visit(std::function<visit_behavior(node&, node*)> fn, node *parent)
752 {
753 	visit_behavior behavior;
754 	behavior = fn(*this, parent);
755 	if (behavior == VISIT_BREAK)
756 	{
757 		return VISIT_BREAK;
758 	}
759 	else if (behavior != VISIT_CONTINUE)
760 	{
761 		for (auto &&c : children)
762 		{
763 			behavior = c->visit(fn, this);
764 			// Any status other than VISIT_RECURSE stops our execution and
765 			// bubbles up to our caller.  The caller may then either continue
766 			// visiting nodes that are siblings to this one or completely halt
767 			// visiting.
768 			if (behavior != VISIT_RECURSE)
769 			{
770 				return behavior;
771 			}
772 		}
773 	}
774 	// Continue recursion by default
775 	return VISIT_RECURSE;
776 }
777 
node(input_buffer & structs,input_buffer & strings)778 node::node(input_buffer &structs, input_buffer &strings) : valid(true)
779 {
780 	std::vector<char> bytes;
781 	while (structs[0] != '\0' && structs[0] != '@')
782 	{
783 		bytes.push_back(structs[0]);
784 		++structs;
785 	}
786 	name = string(bytes.begin(), bytes.end());
787 	bytes.clear();
788 	if (structs[0] == '@')
789 	{
790 		++structs;
791 		while (structs[0] != '\0')
792 		{
793 			bytes.push_back(structs[0]);
794 			++structs;
795 		}
796 		unit_address = string(bytes.begin(), bytes.end());
797 	}
798 	++structs;
799 	uint32_t token;
800 	while (structs.consume_binary(token))
801 	{
802 		switch (token)
803 		{
804 			default:
805 				fprintf(stderr, "Unexpected token 0x%" PRIx32
806 					" while parsing node.\n", token);
807 				valid = false;
808 				return;
809 			// Child node, parse it.
810 			case dtb::FDT_BEGIN_NODE:
811 			{
812 				node_ptr child = node::parse_dtb(structs, strings);
813 				if (child == 0)
814 				{
815 					valid = false;
816 					return;
817 				}
818 				children.push_back(std::move(child));
819 				break;
820 			}
821 			// End of this node, no errors.
822 			case dtb::FDT_END_NODE:
823 				return;
824 			// Property, parse it.
825 			case dtb::FDT_PROP:
826 			{
827 				property_ptr prop = property::parse_dtb(structs, strings);
828 				if (prop == 0)
829 				{
830 					valid = false;
831 					return;
832 				}
833 				props.push_back(prop);
834 				break;
835 			}
836 				break;
837 			// End of structs table.  Should appear after
838 			// the end of the last node.
839 			case dtb::FDT_END:
840 				fprintf(stderr, "Unexpected FDT_END token while parsing node.\n");
841 				valid = false;
842 				return;
843 			// NOPs are padding.  Ignore them.
844 			case dtb::FDT_NOP:
845 				break;
846 		}
847 	}
848 	fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
849 	valid = false;
850 	return;
851 }
852 
853 
node(const string & n,const std::vector<property_ptr> & p)854 node::node(const string &n,
855            const std::vector<property_ptr> &p)
856 	: name(n)
857 {
858 	props.insert(props.begin(), p.begin(), p.end());
859 }
860 
create_special_node(const string & name,const std::vector<property_ptr> & props)861 node_ptr node::create_special_node(const string &name,
862                                    const std::vector<property_ptr> &props)
863 {
864 	// Work around for the fact that we can't call make_shared on something
865 	// with a private constructor.  Instead create a subclass with a public
866 	// constructor that is visible only in this function and construct that
867 	// instead.
868 	struct constructable_node : public node
869 	{
870 		constructable_node(const string &n, const std::vector<property_ptr> &p) : node(n, p) {}
871 	};
872 	node_ptr n{std::make_shared<constructable_node>(name, props)};
873 	return n;
874 }
875 
node(text_input_buffer & input,device_tree & tree,string && n,std::unordered_set<string> && l,string && a,define_map * defines)876 node::node(text_input_buffer &input,
877            device_tree &tree,
878            string &&n,
879            std::unordered_set<string> &&l,
880            string &&a,
881            define_map *defines)
882 	: labels(l), name(n), unit_address(a), valid(true)
883 {
884 	if (!input.consume('{'))
885 	{
886 		input.parse_error("Expected { to start new device tree node.\n");
887 	}
888 	input.next_token();
889 	while (valid && !input.consume('}'))
890 	{
891 		// flag set if we find any characters that are only in
892 		// the property name character set, not the node
893 		bool is_property = false;
894 		// flag set if our node is marked as /omit-if-no-ref/ to be
895 		// garbage collected later if nothing references it
896 		bool marked_omit_if_no_ref = false;
897 		string child_name, child_address;
898 		std::unordered_set<string> child_labels;
899 		auto parse_delete = [&](const char *expected, bool at)
900 		{
901 			if (child_name == string())
902 			{
903 				input.parse_error(expected);
904 				valid = false;
905 				return;
906 			}
907 			input.next_token();
908 			if (at && input.consume('@'))
909 			{
910 				child_name += '@';
911 				child_name += parse_name(input, is_property, "Expected unit address");
912 			}
913 			if (!input.consume(';'))
914 			{
915 				input.parse_error("Expected semicolon");
916 				valid = false;
917 				return;
918 			}
919 			input.next_token();
920 		};
921 		if (input.consume("/delete-node/"))
922 		{
923 			input.next_token();
924 			child_name = input.parse_node_name();
925 			parse_delete("Expected node name", true);
926 			if (valid)
927 			{
928 				deleted_children.insert(child_name);
929 			}
930 			continue;
931 		}
932 		if (input.consume("/delete-property/"))
933 		{
934 			input.next_token();
935 			child_name = input.parse_property_name();
936 			parse_delete("Expected property name", false);
937 			if (valid)
938 			{
939 				deleted_props.insert(child_name);
940 			}
941 			continue;
942 		}
943 		if (input.consume("/omit-if-no-ref/"))
944 		{
945 			input.next_token();
946 			marked_omit_if_no_ref = true;
947 			tree.set_needs_garbage_collection();
948 		}
949 		child_name = parse_name(input, is_property,
950 				"Expected property or node name");
951 		while (input.consume(':'))
952 		{
953 			// Node labels can contain any characters?  The
954 			// spec doesn't say, so we guess so...
955 			is_property = false;
956 			child_labels.insert(std::move(child_name));
957 			child_name = parse_name(input, is_property, "Expected property or node name");
958 		}
959 		if (input.consume('@'))
960 		{
961 			child_address = parse_name(input, is_property, "Expected unit address");
962 		}
963 		if (!valid)
964 		{
965 			return;
966 		}
967 		input.next_token();
968 		// If we're parsing a property, then we must actually do that.
969 		if (input.consume('='))
970 		{
971 			property_ptr p = property::parse(input, std::move(child_name),
972 					std::move(child_labels), true, defines);
973 			if (p == 0)
974 			{
975 				valid = false;
976 			}
977 			else
978 			{
979 				props.push_back(p);
980 			}
981 		}
982 		else if (!is_property && *input == ('{'))
983 		{
984 			node_ptr child = node::parse(input, tree, std::move(child_name),
985 					std::move(child_labels), std::move(child_address), defines);
986 			if (child)
987 			{
988 				child->omit_if_no_ref = marked_omit_if_no_ref;
989 				children.push_back(std::move(child));
990 			}
991 			else
992 			{
993 				valid = false;
994 			}
995 		}
996 		else if (input.consume(';'))
997 		{
998 			props.push_back(property_ptr(new property(std::move(child_name), std::move(child_labels))));
999 		}
1000 		else
1001 		{
1002 			input.parse_error("Error parsing property.  Expected property value");
1003 			valid = false;
1004 		}
1005 		input.next_token();
1006 	}
1007 	input.next_token();
1008 	input.consume(';');
1009 }
1010 
1011 bool
cmp_properties(property_ptr & p1,property_ptr & p2)1012 node::cmp_properties(property_ptr &p1, property_ptr &p2)
1013 {
1014 	return p1->get_key() < p2->get_key();
1015 }
1016 
1017 bool
cmp_children(node_ptr & c1,node_ptr & c2)1018 node::cmp_children(node_ptr &c1, node_ptr &c2)
1019 {
1020 	if (c1->name == c2->name)
1021 	{
1022 		return c1->unit_address < c2->unit_address;
1023 	}
1024 	return c1->name < c2->name;
1025 }
1026 
1027 void
sort()1028 node::sort()
1029 {
1030 	std::sort(property_begin(), property_end(), cmp_properties);
1031 	std::sort(child_begin(), child_end(), cmp_children);
1032 	for (auto &c : child_nodes())
1033 	{
1034 		c->sort();
1035 	}
1036 }
1037 
1038 node_ptr
parse(text_input_buffer & input,device_tree & tree,string && name,string_set && label,string && address,define_map * defines)1039 node::parse(text_input_buffer &input,
1040             device_tree &tree,
1041             string &&name,
1042             string_set &&label,
1043             string &&address,
1044             define_map *defines)
1045 {
1046 	// Work around for the fact that we can't call make_shared on something
1047 	// with a private constructor.  Instead create a subclass with a public
1048 	// constructor that is visible only in this function and construct that
1049 	// instead.
1050 	struct constructable_node : public node
1051 	{
1052 		constructable_node(text_input_buffer &input,
1053 	                       device_tree &tree,
1054 	                       std::string &&n,
1055 	                       std::unordered_set<std::string> &&l,
1056 	                       std::string &&a,
1057 	                       define_map*m) : node(input,
1058 	                                            tree,
1059 	                                            std::move(n),
1060 	                                            std::move(l),
1061 	                                            std::move(a),
1062 	                                            m)
1063 		{}
1064 	};
1065 	node_ptr n{std::make_shared<constructable_node>(input,
1066 	                                                tree,
1067 	                                                std::move(name),
1068 	                                                std::move(label),
1069 	                                                std::move(address),
1070 	                                                defines)};
1071 	if (!n->valid)
1072 	{
1073 		n = 0;
1074 	}
1075 	return n;
1076 }
1077 
1078 node_ptr
parse_dtb(input_buffer & structs,input_buffer & strings)1079 node::parse_dtb(input_buffer &structs, input_buffer &strings)
1080 {
1081 	node_ptr n(new node(structs, strings));
1082 	if (!n->valid)
1083 	{
1084 		n = 0;
1085 	}
1086 	return n;
1087 }
1088 
1089 property_ptr
get_property(const string & key)1090 node::get_property(const string &key)
1091 {
1092 	for (auto &i : props)
1093 	{
1094 		if (i->get_key() == key)
1095 		{
1096 			return i;
1097 		}
1098 	}
1099 	return 0;
1100 }
1101 
1102 void
merge_node(node_ptr & other)1103 node::merge_node(node_ptr &other)
1104 {
1105 	for (auto &l : other->labels)
1106 	{
1107 		labels.insert(l);
1108 	}
1109 	children.erase(std::remove_if(children.begin(), children.end(),
1110 			[&](const node_ptr &p) {
1111 				string full_name = p->name;
1112 				if (p->unit_address != string())
1113 				{
1114 					full_name += '@';
1115 					full_name += p->unit_address;
1116 				}
1117 				if (other->deleted_children.count(full_name) > 0)
1118 				{
1119 					other->deleted_children.erase(full_name);
1120 					return true;
1121 				}
1122 				return false;
1123 			}), children.end());
1124 	props.erase(std::remove_if(props.begin(), props.end(),
1125 			[&](const property_ptr &p) {
1126 				if (other->deleted_props.count(p->get_key()) > 0)
1127 				{
1128 					other->deleted_props.erase(p->get_key());
1129 					return true;
1130 				}
1131 				return false;
1132 			}), props.end());
1133 	// Note: this is an O(n*m) operation.  It might be sensible to
1134 	// optimise this if we find that there are nodes with very
1135 	// large numbers of properties, but for typical usage the
1136 	// entire vector will fit (easily) into cache, so iterating
1137 	// over it repeatedly isn't that expensive.
1138 	for (auto &p : other->properties())
1139 	{
1140 		bool found = false;
1141 		for (auto &mp : properties())
1142 		{
1143 			if (mp->get_key() == p->get_key())
1144 			{
1145 				mp = p;
1146 				found = true;
1147 				break;
1148 			}
1149 		}
1150 		if (!found)
1151 		{
1152 			add_property(p);
1153 		}
1154 	}
1155 	for (auto &c : other->children)
1156 	{
1157 		bool found = false;
1158 		for (auto &i : children)
1159 		{
1160 			if (i->name == c->name && i->unit_address == c->unit_address)
1161 			{
1162 				i->merge_node(c);
1163 				found = true;
1164 				break;
1165 			}
1166 		}
1167 		if (!found)
1168 		{
1169 			children.push_back(std::move(c));
1170 		}
1171 	}
1172 }
1173 
1174 void
write(dtb::output_writer & writer,dtb::string_table & strings)1175 node::write(dtb::output_writer &writer, dtb::string_table &strings)
1176 {
1177 	writer.write_token(dtb::FDT_BEGIN_NODE);
1178 	byte_buffer name_buffer;
1179 	push_string(name_buffer, name);
1180 	if (unit_address != string())
1181 	{
1182 		name_buffer.push_back('@');
1183 		push_string(name_buffer, unit_address);
1184 	}
1185 	writer.write_comment(name);
1186 	writer.write_data(name_buffer);
1187 	writer.write_data((uint8_t)0);
1188 	for (auto p : properties())
1189 	{
1190 		p->write(writer, strings);
1191 	}
1192 	for (auto &c : child_nodes())
1193 	{
1194 		c->write(writer, strings);
1195 	}
1196 	writer.write_token(dtb::FDT_END_NODE);
1197 }
1198 
1199 void
write_dts(FILE * file,int indent)1200 node::write_dts(FILE *file, int indent)
1201 {
1202 	for (int i=0 ; i<indent ; i++)
1203 	{
1204 		putc('\t', file);
1205 	}
1206 #ifdef PRINT_LABELS
1207 	for (auto &label : labels)
1208 	{
1209 		fprintf(file, "%s: ", label.c_str());
1210 	}
1211 #endif
1212 	if (name != string())
1213 	{
1214 		fputs(name.c_str(), file);
1215 	}
1216 	if (unit_address != string())
1217 	{
1218 		putc('@', file);
1219 		fputs(unit_address.c_str(), file);
1220 	}
1221 	fputs(" {\n\n", file);
1222 	for (auto p : properties())
1223 	{
1224 		p->write_dts(file, indent+1);
1225 	}
1226 	for (auto &c : child_nodes())
1227 	{
1228 		c->write_dts(file, indent+1);
1229 	}
1230 	for (int i=0 ; i<indent ; i++)
1231 	{
1232 		putc('\t', file);
1233 	}
1234 	fputs("};\n", file);
1235 }
1236 
1237 void
collect_names_recursive(node_ptr parent,node_ptr n,node_path & path)1238 device_tree::collect_names_recursive(node_ptr parent, node_ptr n, node_path &path)
1239 {
1240 	path.push_back(std::make_pair(n->name, n->unit_address));
1241 	for (const string &name : n->labels)
1242 	{
1243 		if (name != string())
1244 		{
1245 			auto iter = node_names.find(name);
1246 			if (iter == node_names.end())
1247 			{
1248 				node_names.insert(std::make_pair(name, n));
1249 				node_paths.insert(std::make_pair(name, path));
1250 				ordered_node_paths.push_back({name, path});
1251 				if (parent)
1252 				{
1253 					node_name_parents.insert({name, parent});
1254 				}
1255 			}
1256 			else
1257 			{
1258 				node_names.erase(iter);
1259 				auto i = node_paths.find(name);
1260 				if (i != node_paths.end())
1261 				{
1262 					node_paths.erase(name);
1263 				}
1264 				fprintf(stderr, "Label not unique: %s.  References to this label will not be resolved.\n", name.c_str());
1265 			}
1266 		}
1267 	}
1268 	for (auto &c : n->child_nodes())
1269 	{
1270 		collect_names_recursive(n, c, path);
1271 	}
1272 	// Now we collect the phandles and properties that reference
1273 	// other nodes.
1274 	for (auto &p : n->properties())
1275 	{
1276 		for (auto &v : *p)
1277 		{
1278 			if (v.is_phandle())
1279 			{
1280 				fixups.push_back({path, p, v});
1281 			}
1282 			if (v.is_cross_reference())
1283 			{
1284 				cross_references.push_back(&v);
1285 			}
1286 		}
1287 		if ((p->get_key() == "phandle") ||
1288 		    (p->get_key() == "linux,phandle"))
1289 		{
1290 			if (p->begin()->byte_data.size() != 4)
1291 			{
1292 				fprintf(stderr, "Invalid phandle value for node %s.  Should be a 4-byte value.\n", n->name.c_str());
1293 				valid = false;
1294 			}
1295 			else
1296 			{
1297 				uint32_t phandle = p->begin()->get_as_uint32();
1298 				used_phandles.insert(std::make_pair(phandle, n));
1299 			}
1300 		}
1301 	}
1302 	path.pop_back();
1303 }
1304 
1305 void
collect_names()1306 device_tree::collect_names()
1307 {
1308 	node_path p;
1309 	node_names.clear();
1310 	node_paths.clear();
1311 	ordered_node_paths.clear();
1312 	cross_references.clear();
1313 	fixups.clear();
1314 	collect_names_recursive(nullptr, root, p);
1315 }
1316 
1317 property_ptr
assign_phandle(node_ptr n,uint32_t & phandle)1318 device_tree::assign_phandle(node_ptr n, uint32_t &phandle)
1319 {
1320 	// If there is an existing phandle, use it
1321 	property_ptr p = n->get_property("phandle");
1322 	if (p == 0)
1323 	{
1324 		p = n->get_property("linux,phandle");
1325 	}
1326 	if (p == 0)
1327 	{
1328 		// Otherwise insert a new phandle node
1329 		property_value v;
1330 		while (used_phandles.find(phandle) != used_phandles.end())
1331 		{
1332 			// Note that we only don't need to
1333 			// store this phandle in the set,
1334 			// because we are monotonically
1335 			// increasing the value of phandle and
1336 			// so will only ever revisit this value
1337 			// if we have used 2^32 phandles, at
1338 			// which point our blob won't fit in
1339 			// any 32-bit system and we've done
1340 			// something badly wrong elsewhere
1341 			// already.
1342 			phandle++;
1343 		}
1344 		push_big_endian(v.byte_data, phandle++);
1345 		if (phandle_node_name == BOTH || phandle_node_name == LINUX)
1346 		{
1347 			p.reset(new property("linux,phandle"));
1348 			p->add_value(v);
1349 			n->add_property(p);
1350 		}
1351 		if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1352 		{
1353 			p.reset(new property("phandle"));
1354 			p->add_value(v);
1355 			n->add_property(p);
1356 		}
1357 	}
1358 
1359 	return (p);
1360 }
1361 
1362 void
assign_phandles(node_ptr n,uint32_t & next)1363 device_tree::assign_phandles(node_ptr n, uint32_t &next)
1364 {
1365 	if (!n->labels.empty())
1366 	{
1367 		assign_phandle(n, next);
1368 	}
1369 
1370 	for (auto &c : n->child_nodes())
1371 	{
1372 		assign_phandles(c, next);
1373 	}
1374 }
1375 
1376 void
resolve_cross_references(uint32_t & phandle)1377 device_tree::resolve_cross_references(uint32_t &phandle)
1378 {
1379 	for (auto *pv : cross_references)
1380 	{
1381 		node_path path = node_paths[pv->string_data];
1382 		auto p = path.begin();
1383 		auto pe = path.end();
1384 		if (p != pe)
1385 		{
1386 			// Skip the first name in the path.  It's always "", and implicitly /
1387 			for (++p ; p!=pe ; ++p)
1388 			{
1389 				pv->byte_data.push_back('/');
1390 				push_string(pv->byte_data, p->first);
1391 				if (!(p->second.empty()))
1392 				{
1393 					pv->byte_data.push_back('@');
1394 					push_string(pv->byte_data, p->second);
1395 				}
1396 			}
1397 			pv->byte_data.push_back(0);
1398 		}
1399 	}
1400 	std::unordered_map<property_value*, fixup&> phandle_set;
1401 	for (auto &i : fixups)
1402 	{
1403 		phandle_set.insert({&i.val, i});
1404 	}
1405 	std::vector<std::reference_wrapper<fixup>> sorted_phandles;
1406 	root->visit([&](node &n, node *) {
1407 		for (auto &p : n.properties())
1408 		{
1409 			for (auto &v : *p)
1410 			{
1411 				auto i = phandle_set.find(&v);
1412 				if (i != phandle_set.end())
1413 				{
1414 					sorted_phandles.push_back(i->second);
1415 				}
1416 			}
1417 		}
1418 		// Allow recursion
1419 		return node::VISIT_RECURSE;
1420 	}, nullptr);
1421 	assert(sorted_phandles.size() == fixups.size());
1422 	for (auto &i : sorted_phandles)
1423 	{
1424 		string target_name = i.get().val.string_data;
1425 		node_ptr target;
1426 		string possible;
1427 		// If the node name is a path, then look it up by following the path,
1428 		// otherwise jump directly to the named node.
1429 		if (target_name[0] == '/')
1430 		{
1431 			string path;
1432 			target = root;
1433 			std::istringstream ss(target_name);
1434 			string path_element;
1435 			// Read the leading /
1436 			std::getline(ss, path_element, '/');
1437 			// Iterate over path elements
1438 			while (!ss.eof())
1439 			{
1440 				path += '/';
1441 				std::getline(ss, path_element, '/');
1442 				std::istringstream nss(path_element);
1443 				string node_name, node_address;
1444 				std::getline(nss, node_name, '@');
1445 				std::getline(nss, node_address, '@');
1446 				node_ptr next;
1447 				for (auto &c : target->child_nodes())
1448 				{
1449 					if (c->name == node_name)
1450 					{
1451 						if (c->unit_address == node_address)
1452 						{
1453 							next = c;
1454 							break;
1455 						}
1456 						else
1457 						{
1458 							possible = path + c->name;
1459 							if (c->unit_address != string())
1460 							{
1461 								possible += '@';
1462 								possible += c->unit_address;
1463 							}
1464 						}
1465 					}
1466 				}
1467 				path += node_name;
1468 				if (node_address != string())
1469 				{
1470 					path += '@';
1471 					path += node_address;
1472 				}
1473 				target = next;
1474 				if (target == nullptr)
1475 				{
1476 					break;
1477 				}
1478 			}
1479 		}
1480 		else
1481 		{
1482 			target = node_names[target_name];
1483 		}
1484 		if (target == nullptr)
1485 		{
1486 			if (is_plugin)
1487 			{
1488 				unresolved_fixups.push_back(i);
1489 				continue;
1490 			}
1491 			else
1492 			{
1493 				fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str());
1494 				if (possible != string())
1495 				{
1496 					fprintf(stderr, "Possible intended match: %s\n", possible.c_str());
1497 				}
1498 				valid = 0;
1499 				return;
1500 			}
1501 		}
1502 		// If there is an existing phandle, use it
1503 		property_ptr p = assign_phandle(target, phandle);
1504 		p->begin()->push_to_buffer(i.get().val.byte_data);
1505 		assert(i.get().val.byte_data.size() == 4);
1506 	}
1507 }
1508 
1509 bool
garbage_collect_marked_nodes()1510 device_tree::garbage_collect_marked_nodes()
1511 {
1512 	std::unordered_set<node_ptr> previously_referenced_nodes;
1513 	std::unordered_set<node_ptr> newly_referenced_nodes;
1514 
1515 	auto mark_referenced_nodes_used = [&](node &n)
1516 	{
1517 		for (auto &p : n.properties())
1518 		{
1519 			for (auto &v : *p)
1520 			{
1521 				if (v.is_phandle())
1522 				{
1523 					node_ptr nx = node_names[v.string_data];
1524 					if (nx == nullptr)
1525 					{
1526 						// Try it again, but as a path
1527 						for (auto &s : node_paths)
1528 						{
1529 							if (v.string_data == s.second.to_string())
1530 							{
1531 								nx = node_names[s.first];
1532 								break;
1533 							}
1534 						}
1535 					}
1536 					if (nx == nullptr)
1537 					{
1538 						// Couldn't resolve this one?
1539 						continue;
1540 					}
1541 					// Only mark those currently unmarked
1542 					if (!nx->used)
1543 					{
1544 							nx->used = 1;
1545 							newly_referenced_nodes.insert(nx);
1546 					}
1547 				}
1548 			}
1549 		}
1550 	};
1551 
1552 	// Seed our referenced nodes with those that have been seen by a node that
1553 	// either will not be omitted if it's unreferenced or has a symbol.
1554 	// Nodes with symbols are explicitly not garbage collected because they may
1555 	// be expected for referencing by an overlay, and we do not want surprises
1556 	// there.
1557 	root->visit([&](node &n, node *) {
1558 		if (!n.omit_if_no_ref || (write_symbols && !n.labels.empty()))
1559 		{
1560 			mark_referenced_nodes_used(n);
1561 		}
1562 		// Recurse as normal
1563 		return node::VISIT_RECURSE;
1564 	}, nullptr);
1565 
1566 	while (!newly_referenced_nodes.empty())
1567 	{
1568 			previously_referenced_nodes = newly_referenced_nodes;
1569 			newly_referenced_nodes.clear();
1570 			for (auto &n : previously_referenced_nodes)
1571 			{
1572 				mark_referenced_nodes_used(*n);
1573 			}
1574 	}
1575 
1576 	previously_referenced_nodes.clear();
1577 	bool children_deleted = false;
1578 
1579 	// Delete
1580 	root->visit([&](node &n, node *) {
1581 		bool gc_children = false;
1582 
1583 		for (auto &cn : n.child_nodes())
1584 		{
1585 				if (cn->omit_if_no_ref && !cn->used)
1586 				{
1587 					gc_children = true;
1588 					break;
1589 				}
1590 		}
1591 
1592 		if (gc_children)
1593 		{
1594 			children_deleted = true;
1595 			n.delete_children_if([](node_ptr &nx) {
1596 				return (nx->omit_if_no_ref && !nx->used);
1597 			});
1598 
1599 			return node::VISIT_CONTINUE;
1600 		}
1601 
1602 		return node::VISIT_RECURSE;
1603 	}, nullptr);
1604 
1605 	return children_deleted;
1606 }
1607 
1608 void
parse_file(text_input_buffer & input,std::vector<node_ptr> & roots,bool & read_header)1609 device_tree::parse_file(text_input_buffer &input,
1610                         std::vector<node_ptr> &roots,
1611                         bool &read_header)
1612 {
1613 	input.next_token();
1614 	// Read the header
1615 	while (input.consume("/dts-v1/;"))
1616 	{
1617 		read_header = true;
1618 		input.next_token();
1619 	}
1620 	if (input.consume("/plugin/;"))
1621 	{
1622 		is_plugin = true;
1623 	}
1624 	input.next_token();
1625 	if (!read_header)
1626 	{
1627 		input.parse_error("Expected /dts-v1/; version string");
1628 	}
1629 	// Read any memory reservations
1630 	while (input.consume("/memreserve/"))
1631 	{
1632 		unsigned long long start, len;
1633 		input.next_token();
1634 		// Read the start and length.
1635 		if (!(input.consume_integer_expression(start) &&
1636 		    (input.next_token(),
1637 		    input.consume_integer_expression(len))))
1638 		{
1639 			input.parse_error("Expected size on /memreserve/ node.");
1640 		}
1641 		else
1642 		{
1643 			reservations.push_back(reservation(start, len));
1644 		}
1645 		input.next_token();
1646 		input.consume(';');
1647 		input.next_token();
1648 	}
1649 	while (valid && !input.finished())
1650 	{
1651 		node_ptr n;
1652 		if (input.consume("/delete-node/"))
1653 		{
1654 			// Top-level /delete-node/ directives refer to references that must
1655 			// be deleted later.
1656 			input.next_token();
1657 			auto expect = [&](auto token, const char *msg)
1658 			{
1659 				if (!input.consume(token))
1660 				{
1661 					input.parse_error(msg);
1662 					valid = false;
1663 				}
1664 				input.next_token();
1665 				return valid;
1666 			};
1667 			if (expect('&', "Expected reference after top-level /delete-node/."))
1668 			{
1669 				string ref = input.parse_node_name();
1670 				if (ref == string())
1671 				{
1672 					input.parse_error("Expected label name for top-level /delete-node/.");
1673 					valid = false;
1674 				}
1675 				else
1676 				{
1677 					deletions.push_back(std::move(ref));
1678 				}
1679 				expect(';', "Missing semicolon.");
1680 			}
1681 			continue;
1682 		}
1683 		else if (input.consume('/'))
1684 		{
1685 			input.next_token();
1686 			n = node::parse(input, *this, string(), string_set(), string(), &defines);
1687 		}
1688 		else if (input.consume('&'))
1689 		{
1690 			input.next_token();
1691 			string name;
1692 			bool name_is_path_reference = false;
1693 			// This is to deal with names intended as path references, e.g. &{/path}.
1694 			// While it may make sense in a non-plugin context, we don't support such
1695 			// usage at this time.
1696 			if (input.consume('{') && is_plugin)
1697 			{
1698 				name = input.parse_to('}');
1699 				input.consume('}');
1700 				name_is_path_reference = true;
1701 			}
1702 			else
1703 			{
1704 				name = input.parse_node_name();
1705 			}
1706 			input.next_token();
1707 			n = node::parse(input, *this, std::move(name), string_set(), string(), &defines);
1708 			if (n)
1709 			{
1710 				n->name_is_path_reference = name_is_path_reference;
1711 			}
1712 		}
1713 		else
1714 		{
1715 			input.parse_error("Failed to find root node /.");
1716 		}
1717 		if (n)
1718 		{
1719 			roots.push_back(std::move(n));
1720 		}
1721 		else
1722 		{
1723 			valid = false;
1724 		}
1725 		input.next_token();
1726 	}
1727 }
1728 
1729 template<class writer> void
write(int fd)1730 device_tree::write(int fd)
1731 {
1732 	dtb::string_table st;
1733 	dtb::header head;
1734 	writer head_writer;
1735 	writer reservation_writer;
1736 	writer struct_writer;
1737 	writer strings_writer;
1738 
1739 	// Build the reservation table
1740 	reservation_writer.write_comment(string("Memory reservations"));
1741 	reservation_writer.write_label(string("dt_reserve_map"));
1742 	for (auto &i : reservations)
1743 	{
1744 		reservation_writer.write_comment(string("Reservation start"));
1745 		reservation_writer.write_data(i.first);
1746 		reservation_writer.write_comment(string("Reservation length"));
1747 		reservation_writer.write_data(i.second);
1748 	}
1749 	// Write n spare reserve map entries, plus the trailing 0.
1750 	for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++)
1751 	{
1752 		reservation_writer.write_data((uint64_t)0);
1753 		reservation_writer.write_data((uint64_t)0);
1754 	}
1755 
1756 
1757 	struct_writer.write_comment(string("Device tree"));
1758 	struct_writer.write_label(string("dt_struct_start"));
1759 	root->write(struct_writer, st);
1760 	struct_writer.write_token(dtb::FDT_END);
1761 	struct_writer.write_label(string("dt_struct_end"));
1762 
1763 	st.write(strings_writer);
1764 	// Find the strings size before we stick padding on the end.
1765 	// Note: We should possibly use a new writer for the padding.
1766 	head.size_dt_strings = strings_writer.size();
1767 
1768 	// Stick the padding in the strings writer, but after the
1769 	// marker indicating that it's the end.
1770 	// Note: We probably should add a padding call to the writer so
1771 	// that the asm back end can write padding directives instead
1772 	// of a load of 0 bytes.
1773 	for (uint32_t i=0 ; i<blob_padding ; i++)
1774 	{
1775 		strings_writer.write_data((uint8_t)0);
1776 	}
1777 	head.totalsize = sizeof(head) + strings_writer.size() +
1778 		struct_writer.size() + reservation_writer.size();
1779 	while (head.totalsize < minimum_blob_size)
1780 	{
1781 		head.totalsize++;
1782 		strings_writer.write_data((uint8_t)0);
1783 	}
1784 	head.off_dt_struct = sizeof(head) + reservation_writer.size();;
1785 	head.off_dt_strings = head.off_dt_struct + struct_writer.size();
1786 	head.off_mem_rsvmap = sizeof(head);
1787 	head.boot_cpuid_phys = boot_cpu;
1788 	head.size_dt_struct = struct_writer.size();
1789 	head.write(head_writer);
1790 
1791 	head_writer.write_to_file(fd);
1792 	reservation_writer.write_to_file(fd);
1793 	struct_writer.write_to_file(fd);
1794 	strings_writer.write_label(string("dt_blob_end"));
1795 	strings_writer.write_to_file(fd);
1796 }
1797 
1798 node_ptr
referenced_node(property_value & v)1799 device_tree::referenced_node(property_value &v)
1800 {
1801 	if (v.is_phandle())
1802 	{
1803 		return node_names[v.string_data];
1804 	}
1805 	if (v.is_binary())
1806 	{
1807 		return used_phandles[v.get_as_uint32()];
1808 	}
1809 	return 0;
1810 }
1811 
1812 void
write_binary(int fd)1813 device_tree::write_binary(int fd)
1814 {
1815 	write<dtb::binary_writer>(fd);
1816 }
1817 
1818 void
write_asm(int fd)1819 device_tree::write_asm(int fd)
1820 {
1821 	write<dtb::asm_writer>(fd);
1822 }
1823 
1824 void
write_dts(int fd)1825 device_tree::write_dts(int fd)
1826 {
1827 	FILE *file = fdopen(fd, "w");
1828 	fputs("/dts-v1/;\n\n", file);
1829 
1830 	if (!reservations.empty())
1831 	{
1832 		const char msg[] = "/memreserve/";
1833 		// Exclude the null byte when we're writing it out to the file.
1834 		fwrite(msg, sizeof(msg) - 1, 1, file);
1835 		for (auto &i : reservations)
1836 		{
1837 			fprintf(file, " 0x%" PRIx64 " 0x%" PRIx64, i.first, i.second);
1838 		}
1839 		fputs(";\n\n", file);
1840 	}
1841 	putc('/', file);
1842 	putc(' ', file);
1843 	root->write_dts(file, 0);
1844 	fclose(file);
1845 }
1846 
1847 void
parse_dtb(const string & fn,FILE *)1848 device_tree::parse_dtb(const string &fn, FILE *)
1849 {
1850 	auto in = input_buffer::buffer_for_file(fn);
1851 	if (in == 0)
1852 	{
1853 		valid = false;
1854 		return;
1855 	}
1856 	input_buffer &input = *in;
1857 	dtb::header h;
1858 	valid = h.read_dtb(input);
1859 	boot_cpu = h.boot_cpuid_phys;
1860 	if (h.last_comp_version > 17)
1861 	{
1862 		fprintf(stderr, "Don't know how to read this version of the device tree blob");
1863 		valid = false;
1864 	}
1865 	if (!valid)
1866 	{
1867 		return;
1868 	}
1869 	input_buffer reservation_map =
1870 		input.buffer_from_offset(h.off_mem_rsvmap, 0);
1871 	uint64_t start, length;
1872 	do
1873 	{
1874 		if (!(reservation_map.consume_binary(start) &&
1875 		      reservation_map.consume_binary(length)))
1876 		{
1877 			fprintf(stderr, "Failed to read memory reservation table\n");
1878 			valid = false;
1879 			return;
1880 		}
1881 		if (start != 0 || length != 0)
1882 		{
1883 			reservations.push_back(reservation(start, length));
1884 		}
1885 	} while (!((start == 0) && (length == 0)));
1886 	input_buffer struct_table =
1887 		input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct);
1888 	input_buffer strings_table =
1889 		input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings);
1890 	uint32_t token;
1891 	if (!(struct_table.consume_binary(token) &&
1892 		(token == dtb::FDT_BEGIN_NODE)))
1893 	{
1894 		fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n");
1895 		valid = false;
1896 		return;
1897 	}
1898 	root = node::parse_dtb(struct_table, strings_table);
1899 	if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END)))
1900 	{
1901 		fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1902 		valid = false;
1903 		return;
1904 	}
1905 	valid = (root != 0);
1906 }
1907 
1908 string
to_string() const1909 device_tree::node_path::to_string() const
1910 {
1911 	string path;
1912 	auto p = begin();
1913 	auto pe = end();
1914 	if ((p == pe) || (p+1 == pe))
1915 	{
1916 		return string("/");
1917 	}
1918 	// Skip the first name in the path.  It's always "", and implicitly /
1919 	for (++p ; p!=pe ; ++p)
1920 	{
1921 		path += '/';
1922 		path += p->first;
1923 		if (!(p->second.empty()))
1924 		{
1925 			path += '@';
1926 			path += p->second;
1927 		}
1928 	}
1929 	return path;
1930 }
1931 
1932 node_ptr
create_fragment_wrapper(node_ptr & node,int & fragnum)1933 device_tree::create_fragment_wrapper(node_ptr &node, int &fragnum)
1934 {
1935 	// In a plugin, we can massage these non-/ root nodes into into a fragment
1936 	std::string fragment_address = "fragment@" + std::to_string(fragnum);
1937 	++fragnum;
1938 
1939 	std::vector<property_ptr> symbols;
1940 
1941 	// Intentionally left empty
1942 	node_ptr newroot = node::create_special_node("", symbols);
1943 	node_ptr wrapper = node::create_special_node("__overlay__", symbols);
1944 
1945 	// Generate the fragment with $propname = <&name>
1946 	property_value v;
1947 	std::string propname;
1948 	v.string_data = node->name;
1949 	if (!node->name_is_path_reference)
1950 	{
1951 		propname = "target";
1952 		v.type = property_value::PHANDLE;
1953 	}
1954 	else
1955 	{
1956 		propname = "target-path";
1957 		v.type = property_value::STRING;
1958 	}
1959 	auto prop = std::make_shared<property>(std::string(propname));
1960 	prop->add_value(v);
1961 	symbols.push_back(prop);
1962 
1963 	node_ptr fragment = node::create_special_node(fragment_address, symbols);
1964 
1965 	wrapper->merge_node(node);
1966 	fragment->add_child(std::move(wrapper));
1967 	newroot->add_child(std::move(fragment));
1968 	return newroot;
1969 }
1970 
1971 node_ptr
generate_root(node_ptr & node,int & fragnum)1972 device_tree::generate_root(node_ptr &node, int &fragnum)
1973 {
1974 
1975 	string name = node->name;
1976 	if (name == string())
1977 	{
1978 		return std::move(node);
1979 	}
1980 	else if (!is_plugin)
1981 	{
1982 		return nullptr;
1983 	}
1984 
1985 	return create_fragment_wrapper(node, fragnum);
1986 }
1987 
1988 void
reassign_fragment_numbers(node_ptr & node,int & delta)1989 device_tree::reassign_fragment_numbers(node_ptr &node, int &delta)
1990 {
1991 
1992 	for (auto &c : node->child_nodes())
1993 	{
1994 		if (c->name == std::string("fragment"))
1995 		{
1996 			int current_address = std::stoi(c->unit_address, nullptr, 16);
1997 			std::ostringstream new_address;
1998 			current_address += delta;
1999 			// It's possible that we hopped more than one somewhere, so just reset
2000 			// delta to the next in sequence.
2001 			delta = current_address + 1;
2002 			new_address << std::hex << current_address;
2003 			c->unit_address = new_address.str();
2004 		}
2005 	}
2006 }
2007 
2008 void
parse_dts(const string & fn,FILE * depfile)2009 device_tree::parse_dts(const string &fn, FILE *depfile)
2010 {
2011 	auto in = input_buffer::buffer_for_file(fn);
2012 	if (!in)
2013 	{
2014 		valid = false;
2015 		return;
2016 	}
2017 	std::vector<node_ptr> roots;
2018 	std::unordered_set<string> defnames;
2019 	for (auto &i : defines)
2020 	{
2021 		defnames.insert(i.first);
2022 	}
2023 	text_input_buffer input(std::move(in),
2024 	                        std::move(defnames),
2025 	                        std::vector<string>(include_paths),
2026 	                        dirname(fn),
2027 	                        depfile);
2028 	bool read_header = false;
2029 	int fragnum = 0;
2030 	parse_file(input, roots, read_header);
2031 	switch (roots.size())
2032 	{
2033 		case 0:
2034 			valid = false;
2035 			input.parse_error("Failed to find root node /.");
2036 			return;
2037 		case 1:
2038 			root = generate_root(roots[0], fragnum);
2039 			if (!root)
2040 			{
2041 				valid = false;
2042 				input.parse_error("Failed to find root node /.");
2043 				return;
2044 			}
2045 			break;
2046 		default:
2047 		{
2048 			root = generate_root(roots[0], fragnum);
2049 			if (!root)
2050 			{
2051 				valid = false;
2052 				input.parse_error("Failed to find root node /.");
2053 				return;
2054 			}
2055 			for (auto i=++(roots.begin()), e=roots.end() ; i!=e ; ++i)
2056 			{
2057 				auto &node = *i;
2058 				string name = node->name;
2059 				if (name == string())
2060 				{
2061 					if (is_plugin)
2062 					{
2063 						// Re-assign any fragment numbers based on a delta of
2064 						// fragnum before we merge it
2065 						reassign_fragment_numbers(node, fragnum);
2066 					}
2067 					root->merge_node(node);
2068 				}
2069 				else
2070 				{
2071 					auto existing = node_names.find(name);
2072 					if (existing == node_names.end())
2073 					{
2074 						collect_names();
2075 						existing = node_names.find(name);
2076 					}
2077 					if (existing == node_names.end())
2078 					{
2079 						if (is_plugin)
2080 						{
2081 							auto fragment = create_fragment_wrapper(node, fragnum);
2082 							root->merge_node(fragment);
2083 						}
2084 						else
2085 						{
2086 							fprintf(stderr, "Unable to merge node: %s\n", name.c_str());
2087 						}
2088 					}
2089 					else
2090 					{
2091 						existing->second->merge_node(node);
2092 					}
2093 				}
2094 			}
2095 		}
2096 	}
2097 	collect_names();
2098 	for (auto &ref : deletions)
2099 	{
2100 		auto parent = node_name_parents[ref];
2101 		auto node = node_names[ref];
2102 		if (!parent)
2103 		{
2104 			fprintf(stderr, "Top-level /delete-node/ directive refers to label %s, which is not found.\n", ref.c_str());
2105 		}
2106 		else
2107 		{
2108 			parent->delete_children_if([&](node_ptr &child) { return child == node; });
2109 		}
2110 	}
2111 	// Return value indicates whether we've dirtied the tree or not and need to
2112 	// recollect names
2113 	if (garbage_collect && garbage_collect_marked_nodes())
2114 	{
2115 		collect_names();
2116 	}
2117 	uint32_t phandle = 1;
2118 	// If we're writing symbols, go ahead and assign phandles to the entire
2119 	// tree. We'll do this before we resolve cross references, just to keep
2120 	// order semi-predictable and stable.
2121 	if (write_symbols)
2122 	{
2123 		assign_phandles(root, phandle);
2124 	}
2125 	resolve_cross_references(phandle);
2126 	if (write_symbols)
2127 	{
2128 		std::vector<property_ptr> symbols;
2129 		// Create a symbol table.  Each label  in this device tree may be
2130 		// referenced by other plugins, so we create a __symbols__ node inside
2131 		// the root that contains mappings (properties) from label names to
2132 		// paths.
2133 		for (auto i=ordered_node_paths.rbegin(), e=ordered_node_paths.rend() ; i!=e ; ++i)
2134 		{
2135 			auto &s = *i;
2136 			if (node_paths.find(s.first) == node_paths.end())
2137 			{
2138 				// Erased node, skip it.
2139 				continue;
2140 			}
2141 			property_value v;
2142 			v.string_data = s.second.to_string();
2143 			v.type = property_value::STRING;
2144 			string name = s.first;
2145 			auto prop = std::make_shared<property>(std::move(name));
2146 			prop->add_value(v);
2147 			symbols.push_back(prop);
2148 		}
2149 		root->add_child(node::create_special_node("__symbols__", symbols));
2150 	}
2151 	// If this is a plugin, then we also need to create two extra nodes.
2152 	// Internal phandles will need to be renumbered to avoid conflicts with
2153 	// already-loaded nodes and external references will need to be
2154 	// resolved.
2155 	if (is_plugin)
2156 	{
2157 		std::vector<property_ptr> symbols;
2158 		// Create the fixups entry.  This is of the form:
2159 		// {target} = {path}:{property name}:{offset}
2160 		auto create_fixup_entry = [&](fixup &i, string target)
2161 			{
2162 				string value = i.path.to_string();
2163 				value += ':';
2164 				value += i.prop->get_key();
2165 				value += ':';
2166 				value += std::to_string(i.prop->offset_of_value(i.val));
2167 				property_value v;
2168 				v.string_data = value;
2169 				v.type = property_value::STRING;
2170 				auto prop = std::make_shared<property>(std::move(target));
2171 				prop->add_value(v);
2172 				return prop;
2173 			};
2174 		// If we have any unresolved phandle references in this plugin,
2175 		// then we must update them to 0xdeadbeef and leave a property in
2176 		// the /__fixups__ node whose key is the label and whose value is
2177 		// as described above.
2178 		if (!unresolved_fixups.empty())
2179 		{
2180 			for (auto &i : unresolved_fixups)
2181 			{
2182 				auto &val = i.get().val;
2183 				symbols.push_back(create_fixup_entry(i, val.string_data));
2184 				val.byte_data.push_back(0xde);
2185 				val.byte_data.push_back(0xad);
2186 				val.byte_data.push_back(0xbe);
2187 				val.byte_data.push_back(0xef);
2188 				val.type = property_value::BINARY;
2189 			}
2190 			root->add_child(node::create_special_node("__fixups__", symbols));
2191 		}
2192 		symbols.clear();
2193 		// If we have any resolved phandle references in this plugin, then
2194 		// we must create a child in the __local_fixups__ node whose path
2195 		// matches the node path from the root and whose value contains the
2196 		// location of the reference within a property.
2197 
2198 		// Create a local_fixups node that is initially empty.
2199 		node_ptr local_fixups = node::create_special_node("__local_fixups__", symbols);
2200 		for (auto &i : fixups)
2201 		{
2202 			if (!i.val.is_phandle())
2203 			{
2204 				continue;
2205 			}
2206 			node_ptr n = local_fixups;
2207 			for (auto &p : i.path)
2208 			{
2209 				// Skip the implicit root
2210 				if (p.first.empty())
2211 				{
2212 					continue;
2213 				}
2214 				bool found = false;
2215 				for (auto &c : n->child_nodes())
2216 				{
2217 					if (c->name == p.first)
2218 					{
2219 						if (c->unit_address == p.second)
2220 						{
2221 							n = c;
2222 							found = true;
2223 							break;
2224 						}
2225 					}
2226 				}
2227 				if (!found)
2228 				{
2229 					string path = p.first;
2230 					if (!(p.second.empty()))
2231 					{
2232 						path += '@';
2233 						path += p.second;
2234 					}
2235 					n->add_child(node::create_special_node(path, symbols));
2236 					n = *(--(n->child_end()));
2237 				}
2238 			}
2239 			assert(n);
2240 			property_value pv;
2241 			push_big_endian(pv.byte_data, static_cast<uint32_t>(i.prop->offset_of_value(i.val)));
2242 			pv.type = property_value::BINARY;
2243 			auto key = i.prop->get_key();
2244 			property_ptr prop = n->get_property(key);
2245 			// If we don't have an existing property then create one and
2246 			// use this property value
2247 			if (!prop)
2248 			{
2249 				prop = std::make_shared<property>(std::move(key));
2250 				n->add_property(prop);
2251 				prop->add_value(pv);
2252 			}
2253 			else
2254 			{
2255 				// If we do have an existing property value, try to append
2256 				// this value.
2257 				property_value &old_val = *(--prop->end());
2258 				if (!old_val.try_to_merge(pv))
2259 				{
2260 					prop->add_value(pv);
2261 				}
2262 			}
2263 		}
2264 		// We've iterated over all fixups, but only emit the
2265 		// __local_fixups__ if we found some that were resolved internally.
2266 		if (local_fixups->child_begin() != local_fixups->child_end())
2267 		{
2268 			root->add_child(std::move(local_fixups));
2269 		}
2270 	}
2271 }
2272 
parse_define(const char * def)2273 bool device_tree::parse_define(const char *def)
2274 {
2275 	const char *val = strchr(def, '=');
2276 	if (!val)
2277 	{
2278 		if (strlen(def) != 0)
2279 		{
2280 			string name(def);
2281 			defines[name];
2282 			return true;
2283 		}
2284 		return false;
2285 	}
2286 	string name(def, val-def);
2287 	string name_copy = name;
2288 	val++;
2289 	std::unique_ptr<input_buffer> raw(new input_buffer(val, strlen(val)));
2290 	text_input_buffer in(std::move(raw),
2291 	                     std::unordered_set<string>(),
2292 	                     std::vector<string>(),
2293 	                     string(),
2294 	                     nullptr);
2295 	property_ptr p = property::parse(in, std::move(name_copy), string_set(), false);
2296 	if (p)
2297 		defines[name] = p;
2298 	return (bool)p;
2299 }
2300 
2301 } // namespace fdt
2302 
2303 } // namespace dtc
2304 
2305