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