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