iPXE
fdt.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <byteswap.h>
32 #include <ipxe/netdevice.h>
33 #include <ipxe/image.h>
34 #include <ipxe/uaccess.h>
35 #include <ipxe/umalloc.h>
36 #include <ipxe/fdt.h>
37 
38 /** @file
39  *
40  * Flattened Device Tree
41  *
42  */
43 
44 /** The system flattened device tree (if present) */
45 struct fdt sysfdt;
46 
47 /** The downloaded flattened device tree tag */
48 struct image_tag fdt_image __image_tag = {
49  .name = "FDT",
50 };
51 
52 /** Amount of free space to add whenever we have to reallocate a tree */
53 #define FDT_INSERT_PAD 1024
54 
55 /**
56  * Check if character is permitted in a name
57  *
58  * @v ch Character
59  * @ret is_permitted Character is permitted in a name
60  */
61 static int fdt_permitted ( char ch ) {
62  static const char permitted[] = ",._+?#-";
63 
64  return ( isalnum ( ch ) || strchr ( permitted, ch ) );
65 }
66 
67 /**
68  * Compare node name
69  *
70  * @v desc Token descriptor
71  * @v name Name (terminated by NUL or any non-permitted character)
72  * @ret is_match Name matches token descriptor
73  */
74 static int fdt_match ( const struct fdt_descriptor *desc, const char *name ) {
75  size_t len = strlen ( desc->name );
76 
77  /* Check name and terminator */
78  return ( ( memcmp ( desc->name, name, len ) == 0 ) &&
79  ( ! ( name[len] && fdt_permitted ( name[len] ) ) ) );
80 }
81 
82 /**
83  * Describe device tree token
84  *
85  * @v fdt Device tree
86  * @v offset Offset within structure block
87  * @v desc Token descriptor to fill in
88  * @ret rc Return status code
89  */
90 int fdt_describe ( struct fdt *fdt, unsigned int offset,
91  struct fdt_descriptor *desc ) {
92  const fdt_token_t *token;
93  const void *data;
94  const struct fdt_prop *prop;
95  unsigned int name_off;
96  size_t remaining;
97  size_t len;
98 
99  /* Sanity checks */
100  assert ( offset <= fdt->len );
101  assert ( ( offset & ( FDT_STRUCTURE_ALIGN - 1 ) ) == 0 );
102 
103  /* Initialise descriptor */
104  memset ( desc, 0, sizeof ( *desc ) );
105  desc->offset = offset;
106 
107  /* Locate token and calculate remaining space */
108  token = ( fdt->raw + fdt->structure + offset );
109  remaining = ( fdt->len - offset );
110  if ( remaining < sizeof ( *token ) ) {
111  DBGC ( fdt, "FDT truncated tree at +%#04x\n", offset );
112  return -EINVAL;
113  }
114  remaining -= sizeof ( *token );
115  data = ( ( ( const void * ) token ) + sizeof ( *token ) );
116  len = 0;
117 
118  /* Handle token */
119  switch ( *token ) {
120 
121  case cpu_to_be32 ( FDT_BEGIN_NODE ):
122 
123  /* Start of node */
124  desc->name = data;
125  len = ( strnlen ( desc->name, remaining ) + 1 /* NUL */ );
126  if ( remaining < len ) {
127  DBGC ( fdt, "FDT unterminated node name at +%#04x\n",
128  offset );
129  return -EINVAL;
130  }
131  desc->depth = +1;
132  break;
133 
134  case cpu_to_be32 ( FDT_END_NODE ):
135 
136  /* End of node */
137  desc->depth = -1;
138  break;
139 
140  case cpu_to_be32 ( FDT_PROP ):
141 
142  /* Property */
143  prop = data;
144  if ( remaining < sizeof ( *prop ) ) {
145  DBGC ( fdt, "FDT truncated property at +%#04x\n",
146  offset );
147  return -EINVAL;
148  }
149  desc->data = ( ( ( const void * ) prop ) + sizeof ( *prop ) );
150  desc->len = be32_to_cpu ( prop->len );
151  len = ( sizeof ( *prop ) + desc->len );
152  if ( remaining < len ) {
153  DBGC ( fdt, "FDT overlength property at +%#04x\n",
154  offset );
155  return -EINVAL;
156  }
157  name_off = be32_to_cpu ( prop->name_off );
158  if ( name_off > fdt->strings_len ) {
159  DBGC ( fdt, "FDT property name outside strings "
160  "block at +%#04x\n", offset );
161  return -EINVAL;
162  }
163  desc->name = ( fdt->raw + fdt->strings + name_off );
164  break;
165 
166  case cpu_to_be32 ( FDT_NOP ):
167 
168  /* Do nothing */
169  break;
170 
171  default:
172 
173  /* Unrecognised or unexpected token */
174  DBGC ( fdt, "FDT unexpected token %#08x at +%#04x\n",
175  be32_to_cpu ( *token ), offset );
176  return -EINVAL;
177  }
178 
179  /* Calculate offset to next token */
180  len = ( ( len + FDT_STRUCTURE_ALIGN - 1 ) &
181  ~( FDT_STRUCTURE_ALIGN - 1 ) );
182  offset += ( sizeof ( *token ) + len );
183  desc->next = offset;
184 
185  /* Sanity checks */
186  assert ( offset <= fdt->len );
187 
188  return 0;
189 }
190 
191 /**
192  * Describe next device tree token
193  *
194  * @v fdt Device tree
195  * @v desc Token descriptor to update
196  * @ret rc Return status code
197  */
198 static int fdt_next ( struct fdt *fdt, struct fdt_descriptor *desc ) {
199 
200  /* Describe next token */
201  return fdt_describe ( fdt, desc->next, desc );
202 }
203 
204 /**
205  * Enter node
206  *
207  * @v fdt Device tree
208  * @v offset Starting node offset
209  * @v desc Begin node descriptor to fill in
210  * @ret rc Return status code
211  */
212 static int fdt_enter ( struct fdt *fdt, unsigned int offset,
213  struct fdt_descriptor *desc ) {
214  int rc;
215 
216  /* Find begin node token */
217  for ( ; ; offset = desc->next ) {
218 
219  /* Describe token */
220  if ( ( rc = fdt_describe ( fdt, offset, desc ) ) != 0 ) {
221  DBGC ( fdt, "FDT +%#04x has malformed node: %s\n",
222  offset, strerror ( rc ) );
223  return rc;
224  }
225 
226  /* Check for begin node token */
227  if ( desc->depth > 0 )
228  return 0;
229 
230  /* Check for non-NOPs */
231  if ( desc->depth ) {
232  DBGC ( fdt, "FDT +%#04x has spurious node end at "
233  "+%#04x\n", offset, desc->offset );
234  return -EINVAL;
235  }
236  if ( desc->name ) {
237  DBGC ( fdt, "FDT +%#04x has spurious property at "
238  "+%#04x\n", offset, desc->offset );
239  return -EINVAL;
240  }
241  }
242 }
243 
244 /**
245  * Find node relative depth
246  *
247  * @v fdt Device tree
248  * @v offset Starting node offset
249  * @v target Target node offset
250  * @ret depth Depth, or negative error
251  */
252 static int fdt_depth ( struct fdt *fdt, unsigned int offset,
253  unsigned int target ) {
254  struct fdt_descriptor desc;
255  int depth;
256  int rc;
257 
258  /* Enter node */
259  if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 )
260  return rc;
261 
262  /* Find target node */
263  for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) {
264 
265  /* Describe token */
266  if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) {
267  DBGC ( fdt, "FDT +%#04x has malformed node: %s\n",
268  offset, strerror ( rc ) );
269  return rc;
270  }
271 
272  /* Check for target node */
273  if ( desc.offset == target ) {
274  DBGC2 ( fdt, "FDT +%#04x has descendant node +%#04x "
275  "at depth +%d\n", offset, target, depth );
276  return depth;
277  }
278  }
279 
280  DBGC ( fdt, "FDT +#%04x has no descendant node +%#04x\n",
281  offset, target );
282  return -ENOENT;
283 }
284 
285 /**
286  * Find parent node
287  *
288  * @v fdt Device tree
289  * @v offset Starting node offset
290  * @v parent Parent node offset to fill in
291  * @ret rc Return status code
292  */
293 int fdt_parent ( struct fdt *fdt, unsigned int offset, unsigned int *parent ) {
294  struct fdt_descriptor desc;
295  int pdepth;
296  int depth;
297  int rc;
298 
299  /* Find depth from root of tree */
300  depth = fdt_depth ( fdt, 0, offset );
301  if ( depth < 0 ) {
302  rc = depth;
303  return rc;
304  }
305  pdepth = ( depth - 1 );
306 
307  /* Enter root node */
308  if ( ( rc = fdt_enter ( fdt, 0, &desc ) ) != 0 )
309  return rc;
310  *parent = desc.offset;
311 
312  /* Find parent node */
313  for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) {
314 
315  /* Describe token */
316  if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) {
317  DBGC ( fdt, "FDT +%#04x has malformed node: %s\n",
318  offset, strerror ( rc ) );
319  return rc;
320  }
321 
322  /* Record possible parent node */
323  if ( ( depth == pdepth ) && desc.name && ( ! desc.data ) )
324  *parent = desc.offset;
325 
326  /* Check for target node */
327  if ( desc.offset == offset ) {
328  DBGC2 ( fdt, "FDT +%#04x has parent node at +%#04x\n",
329  offset, *parent );
330  return 0;
331  }
332  }
333 
334  DBGC ( fdt, "FDT +#%04x has no parent node\n", offset );
335  return -ENOENT;
336 }
337 
338 /**
339  * Find child node
340  *
341  * @v fdt Device tree
342  * @v offset Starting node offset
343  * @v name Node name
344  * @v child Child node offset to fill in
345  * @ret rc Return status code
346  */
347 static int fdt_child ( struct fdt *fdt, unsigned int offset, const char *name,
348  unsigned int *child ) {
349  struct fdt_descriptor desc;
350  int depth;
351  int rc;
352 
353  /* Enter node */
354  if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 )
355  return rc;
356 
357  /* Find child node */
358  for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) {
359 
360  /* Describe token */
361  if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) {
362  DBGC ( fdt, "FDT +%#04x has malformed node: %s\n",
363  offset, strerror ( rc ) );
364  return rc;
365  }
366 
367  /* Check for matching immediate child node */
368  if ( ( depth == 0 ) && desc.name && ( ! desc.data ) ) {
369  DBGC2 ( fdt, "FDT +%#04x has child node \"%s\" at "
370  "+%#04x\n", offset, desc.name, desc.offset );
371  assert ( desc.depth > 0 );
372  if ( fdt_match ( &desc, name ) ) {
373  *child = desc.offset;
374  return 0;
375  }
376  }
377  }
378 
379  DBGC2 ( fdt, "FDT +%#04x has no child node \"%s\"\n", offset, name );
380  return -ENOENT;
381 }
382 
383 /**
384  * Find end of node
385  *
386  * @v fdt Device tree
387  * @v offset Starting node offset
388  * @v end End of node offset to fill in
389  * @ret rc Return status code
390  */
391 static int fdt_end ( struct fdt *fdt, unsigned int offset,
392  unsigned int *end ) {
393  struct fdt_descriptor desc;
394  int depth;
395  int rc;
396 
397  /* Enter node */
398  if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 )
399  return rc;
400 
401  /* Find end of this node */
402  for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) {
403 
404  /* Describe token */
405  if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) {
406  DBGC ( fdt, "FDT +%#04x has malformed node: %s\n",
407  offset, strerror ( rc ) );
408  return rc;
409  }
410  }
411 
412  /* Record end offset */
413  *end = desc.offset;
414  DBGC2 ( fdt, "FDT +%#04x has end at +%#04x\n", offset, *end );
415  return 0;
416 }
417 
418 /**
419  * Find node by path
420  *
421  * @v fdt Device tree
422  * @v path Node path
423  * @v offset Offset to fill in
424  * @ret rc Return status code
425  */
426 int fdt_path ( struct fdt *fdt, const char *path, unsigned int *offset ) {
427  const char *tmp = path;
428  int rc;
429 
430  /* Initialise offset */
431  *offset = 0;
432 
433  /* Traverse tree one path segment at a time */
434  while ( 1 ) {
435 
436  /* Skip any leading '/' */
437  while ( *tmp == '/' )
438  tmp++;
439 
440  /* Terminate if there are no more path components */
441  if ( ! *tmp )
442  break;
443 
444  /* Find child */
445  if ( ( rc = fdt_child ( fdt, *offset, tmp, offset ) ) != 0 )
446  return rc;
447 
448  /* Move to next path component, if any */
449  tmp = strchr ( tmp, '/' );
450  if ( ! tmp )
451  break;
452  }
453 
454  DBGC2 ( fdt, "FDT found path \"%s\" at +%#04x\n", path, *offset );
455  return 0;
456 }
457 
458 /**
459  * Find node by alias
460  *
461  * @v fdt Device tree
462  * @v name Alias name
463  * @v offset Offset to fill in
464  * @ret rc Return status code
465  */
466 int fdt_alias ( struct fdt *fdt, const char *name, unsigned int *offset ) {
467  const char *alias;
468  int rc;
469 
470  /* Locate "/aliases" node */
471  if ( ( rc = fdt_child ( fdt, 0, "aliases", offset ) ) != 0 )
472  return rc;
473 
474  /* Locate alias property */
475  if ( ( alias = fdt_string ( fdt, *offset, name ) ) == NULL )
476  return -ENOENT;
477  DBGC ( fdt, "FDT alias \"%s\" is \"%s\"\n", name, alias );
478 
479  /* Locate aliased node */
480  if ( ( rc = fdt_path ( fdt, alias, offset ) ) != 0 )
481  return rc;
482 
483  return 0;
484 }
485 
486 /**
487  * Find property
488  *
489  * @v fdt Device tree
490  * @v offset Starting node offset
491  * @v name Property name
492  * @v desc Token descriptor to fill in
493  * @ret rc Return status code
494  */
495 static int fdt_property ( struct fdt *fdt, unsigned int offset,
496  const char *name, struct fdt_descriptor *desc ) {
497  int depth;
498  int rc;
499 
500  /* Enter node */
501  if ( ( rc = fdt_enter ( fdt, offset, desc ) ) != 0 )
502  return rc;
503 
504  /* Find property */
505  for ( depth = 0 ; depth == 0 ; depth += desc->depth ) {
506 
507  /* Describe token */
508  if ( ( rc = fdt_next ( fdt, desc ) ) != 0 ) {
509  DBGC ( fdt, "FDT +%#04x has malformed node: %s\n",
510  offset, strerror ( rc ) );
511  return rc;
512  }
513 
514  /* Check for matching immediate child property */
515  if ( desc->data ) {
516  DBGC2 ( fdt, "FDT +%#04x has property \"%s\" at "
517  "+%#04x len %#zx\n", offset, desc->name,
518  desc->offset, desc->len );
519  assert ( desc->depth == 0 );
520  if ( fdt_match ( desc, name ) ) {
521  DBGC2_HDA ( fdt, 0, desc->data, desc->len );
522  return 0;
523  }
524  }
525  }
526 
527  DBGC2 ( fdt, "FDT +%#04x has no property \"%s\"\n", offset, name );
528  return -ENOENT;
529 }
530 
531 /**
532  * Find strings property
533  *
534  * @v fdt Device tree
535  * @v offset Starting node offset
536  * @v name Property name
537  * @v count String count to fill in
538  * @ret string String property, or NULL on error
539  */
540 const char * fdt_strings ( struct fdt *fdt, unsigned int offset,
541  const char *name, unsigned int *count ) {
542  struct fdt_descriptor desc;
543  const char *data;
544  size_t len;
545  int rc;
546 
547  /* Return a zero count on error */
548  *count = 0;
549 
550  /* Find property */
551  if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) != 0 )
552  return NULL;
553 
554  /* Check NUL termination */
555  data = desc.data;
556  if ( desc.len && ( data[ desc.len - 1 ] != '\0' ) ) {
557  DBGC ( fdt, "FDT unterminated string property \"%s\"\n",
558  name );
559  return NULL;
560  }
561 
562  /* Count number of strings */
563  for ( len = desc.len ; len-- ; ) {
564  if ( data[len] == '\0' )
565  (*count)++;
566  }
567 
568  return data;
569 }
570 
571 /**
572  * Find string property
573  *
574  * @v fdt Device tree
575  * @v offset Starting node offset
576  * @v name Property name
577  * @ret string String property, or NULL on error
578  */
579 const char * fdt_string ( struct fdt *fdt, unsigned int offset,
580  const char *name ) {
581  unsigned int count;
582 
583  /* Find strings property */
584  return fdt_strings ( fdt, offset, name, &count );
585 }
586 
587 /**
588  * Get integer property
589  *
590  * @v fdt Device tree
591  * @v offset Starting node offset
592  * @v name Property name
593  * @v index Starting cell index
594  * @v count Number of cells (or 0 to read all remaining cells)
595  * @v value Integer value to fill in
596  * @ret rc Return status code
597  */
598 int fdt_cells ( struct fdt *fdt, unsigned int offset, const char *name,
599  unsigned int index, unsigned int count, uint64_t *value ) {
600  struct fdt_descriptor desc;
601  const uint32_t *cell;
602  unsigned int total;
603  int rc;
604 
605  /* Clear value */
606  *value = 0;
607 
608  /* Find property */
609  if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) != 0 )
610  return rc;
611  cell = desc.data;
612 
613  /* Determine number of cells */
614  total = ( desc.len / sizeof ( *cell ) );
615  if ( ( index > total ) || ( count > ( total - index ) ) ) {
616  DBGC ( fdt, "FDT truncated integer \"%s\"\n", name );
617  return -ERANGE;
618  }
619  if ( ! count )
620  count = ( total - index );
621  if ( count > ( sizeof ( *value ) / sizeof ( *cell ) ) ) {
622  DBGC ( fdt, "FDT overlength integer \"%s\"\n", name );
623  return -ERANGE;
624  }
625 
626  /* Read value */
627  for ( cell += index ; count ; cell++, count-- ) {
628  *value <<= 32;
629  *value |= be32_to_cpu ( *cell );
630  }
631 
632  return 0;
633 }
634 
635 /**
636  * Get 64-bit integer property
637  *
638  * @v fdt Device tree
639  * @v offset Starting node offset
640  * @v name Property name
641  * @v value Integer value to fill in
642  * @ret rc Return status code
643  */
644 int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name,
645  uint64_t *value ) {
646  int rc;
647 
648  /* Read value */
649  if ( ( rc = fdt_cells ( fdt, offset, name, 0, 0, value ) ) != 0 )
650  return rc;
651 
652  return 0;
653 }
654 
655 /**
656  * Get 32-bit integer property
657  *
658  * @v fdt Device tree
659  * @v offset Starting node offset
660  * @v name Property name
661  * @v value Integer value to fill in
662  * @ret rc Return status code
663  */
664 int fdt_u32 ( struct fdt *fdt, unsigned int offset, const char *name,
665  uint32_t *value ) {
666  uint64_t value64;
667  int rc;
668 
669  /* Read value */
670  if ( ( rc = fdt_u64 ( fdt, offset, name, &value64 ) ) != 0 )
671  return rc;
672 
673  /* Check range */
674  *value = value64;
675  if ( *value != value64 ) {
676  DBGC ( fdt, "FDT overlength 32-bit integer \"%s\"\n", name );
677  return -ERANGE;
678  }
679 
680  return 0;
681 }
682 
683 /**
684  * Get package handle (phandle) property
685  *
686  * @v fdt Device tree
687  * @v offset Starting node offset
688  * @ret phandle Package handle, or 0 on error
689  */
690 uint32_t fdt_phandle ( struct fdt *fdt, unsigned int offset ) {
691  uint32_t phandle;
692  int rc;
693 
694  /* Get "phandle" or "linux,phandle" property */
695  if ( ( ( rc = fdt_u32 ( fdt, offset, "phandle", &phandle ) ) == 0 ) ||
696  ( ( rc = fdt_u32 ( fdt, offset, "linux,phandle",
697  &phandle ) ) == 0 ) ) {
698  assert ( phandle != 0 );
699  return phandle;
700  }
701 
702  return 0;
703 }
704 
705 /**
706  * Get region cell size specification
707  *
708  * @v fdt Device tree
709  * @v offset Starting (parent) node offset
710  * @v regs Region cell size specification to fill in
711  *
712  * Note that #address-cells and #size-cells are defined on the
713  * immediate parent node, rather than on the node with the "reg"
714  * property itself.
715  */
716 void fdt_reg_cells ( struct fdt *fdt, unsigned int offset,
717  struct fdt_reg_cells *regs ) {
718  int rc;
719 
720  /* Read #address-cells, if present */
721  if ( ( rc = fdt_u32 ( fdt, offset, "#address-cells",
722  &regs->address_cells ) ) != 0 ) {
723  regs->address_cells = FDT_DEFAULT_ADDRESS_CELLS;
724  }
725 
726  /* Read #size-cells, if present */
727  if ( ( rc = fdt_u32 ( fdt, offset, "#size-cells",
728  &regs->size_cells ) ) != 0 ) {
729  regs->size_cells = FDT_DEFAULT_SIZE_CELLS;
730  }
731 
732  /* Calculate stride */
733  regs->stride = ( regs->address_cells + regs->size_cells );
734 }
735 
736 /**
737  * Get parent region cell size specification
738  *
739  * @v fdt Device tree
740  * @v offset Starting node offset
741  * @v regs Region cell size specification to fill in
742  * @ret rc Return status code
743  */
744 int fdt_parent_reg_cells ( struct fdt *fdt, unsigned int offset,
745  struct fdt_reg_cells *regs ) {
746  unsigned int parent;
747  int rc;
748 
749  /* Get parent node */
750  if ( ( rc = fdt_parent ( fdt, offset, &parent ) ) != 0 )
751  return rc;
752 
753  /* Read #address-cells and #size-cells, if present */
754  fdt_reg_cells ( fdt, parent, regs );
755 
756  return 0;
757 }
758 
759 /**
760  * Get number of regions
761  *
762  * @v fdt Device tree
763  * @v offset Starting node offset
764  * @v regs Region cell size specification
765  * @ret count Number of regions, or negative error
766  */
767 int fdt_reg_count ( struct fdt *fdt, unsigned int offset,
768  struct fdt_reg_cells *regs ) {
769  struct fdt_descriptor desc;
770  const uint32_t *cell;
771  unsigned int count;
772  int rc;
773 
774  /* Find property */
775  if ( ( rc = fdt_property ( fdt, offset, "reg", &desc ) ) != 0 )
776  return rc;
777 
778  /* Determine number of regions */
779  count = ( desc.len / ( regs->stride * sizeof ( *cell ) ) );
780  return count;
781 }
782 
783 /**
784  * Get region address
785  *
786  * @v fdt Device tree
787  * @v offset Starting node offset
788  * @v regs Region cell size specification
789  * @v index Region index
790  * @v address Region starting address to fill in
791  * @ret rc Return status code
792  */
793 int fdt_reg_address ( struct fdt *fdt, unsigned int offset,
794  struct fdt_reg_cells *regs, unsigned int index,
795  uint64_t *address ) {
796  unsigned int cell = ( index * regs->stride );
797  int rc;
798 
799  /* Read relevant portion of region array */
800  if ( ( rc = fdt_cells ( fdt, offset, "reg", cell, regs->address_cells,
801  address ) ) != 0 ) {
802  return rc;
803  }
804 
805  return 0;
806 }
807 
808 /**
809  * Get region size
810  *
811  * @v fdt Device tree
812  * @v offset Starting node offset
813  * @v regs Region cell size specification
814  * @v index Region index
815  * @v size Region size to fill in
816  * @ret rc Return status code
817  */
818 int fdt_reg_size ( struct fdt *fdt, unsigned int offset,
819  struct fdt_reg_cells *regs, unsigned int index,
820  uint64_t *size ) {
821  unsigned int cell = ( ( index * regs->stride ) + regs->address_cells );
822  int rc;
823 
824  /* Read relevant portion of region array */
825  if ( ( rc = fdt_cells ( fdt, offset, "reg", cell, regs->size_cells,
826  size ) ) != 0 ) {
827  return rc;
828  }
829 
830  return 0;
831 }
832 
833 /**
834  * Get unsized single-entry region address
835  *
836  * @v fdt Device tree
837  * @v offset Starting node offset
838  * @v address Region address to fill in
839  * @ret rc Return status code
840  *
841  * Many region types (e.g. I2C bus addresses) can only ever contain a
842  * single region with no size cells specified.
843  */
844 int fdt_reg ( struct fdt *fdt, unsigned int offset, uint64_t *region ) {
845  struct fdt_reg_cells regs;
846  int rc;
847 
848  /* Get parent region cell size specification */
849  if ( ( rc = fdt_parent_reg_cells ( fdt, offset, &regs ) ) != 0 )
850  return rc;
851 
852  /* Get first region address */
853  if ( ( rc = fdt_reg_address ( fdt, offset, &regs, 0, region ) ) != 0 )
854  return rc;
855 
856  return 0;
857 }
858 
859 /**
860  * Get MAC address from property
861  *
862  * @v fdt Device tree
863  * @v offset Starting node offset
864  * @v netdev Network device
865  * @ret rc Return status code
866  */
867 int fdt_mac ( struct fdt *fdt, unsigned int offset,
868  struct net_device *netdev ) {
869  struct fdt_descriptor desc;
870  size_t len;
871  int rc;
872 
873  /* Find applicable MAC address property */
874  if ( ( ( rc = fdt_property ( fdt, offset, "mac-address",
875  &desc ) ) != 0 ) &&
876  ( ( rc = fdt_property ( fdt, offset, "local-mac-address",
877  &desc ) ) != 0 ) ) {
878  return rc;
879  }
880 
881  /* Check length */
883  if ( len != desc.len ) {
884  DBGC ( fdt, "FDT malformed MAC address \"%s\":\n",
885  desc.name );
886  DBGC_HDA ( fdt, 0, desc.data, desc.len );
887  return -ERANGE;
888  }
889 
890  /* Fill in MAC address */
891  memcpy ( netdev->hw_addr, desc.data, len );
892 
893  return 0;
894 }
895 
896 /**
897  * Parse device tree
898  *
899  * @v fdt Device tree
900  * @v hdr Device tree header
901  * @v max_len Maximum device tree length
902  * @ret rc Return status code
903  */
904 int fdt_parse ( struct fdt *fdt, struct fdt_header *hdr, size_t max_len ) {
905  const uint8_t *nul;
906  unsigned int chosen;
907  size_t end;
908 
909  /* Sanity check */
910  if ( sizeof ( *hdr ) > max_len ) {
911  DBGC ( fdt, "FDT length %#zx too short for header\n",
912  max_len );
913  goto err;
914  }
915 
916  /* Record device tree location */
917  fdt->hdr = hdr;
918  fdt->len = be32_to_cpu ( hdr->totalsize );
919  fdt->used = sizeof ( *hdr );
920  if ( fdt->len > max_len ) {
921  DBGC ( fdt, "FDT has invalid length %#zx / %#zx\n",
922  fdt->len, max_len );
923  goto err;
924  }
925  DBGC ( fdt, "FDT version %d at %p+%#04zx (phys %#08lx)\n",
926  be32_to_cpu ( hdr->version ), fdt->hdr, fdt->len,
927  virt_to_phys ( hdr ) );
928 
929  /* Check signature */
930  if ( hdr->magic != cpu_to_be32 ( FDT_MAGIC ) ) {
931  DBGC ( fdt, "FDT has invalid magic value %#08x\n",
932  be32_to_cpu ( hdr->magic ) );
933  goto err;
934  }
935 
936  /* Check version */
937  if ( hdr->last_comp_version != cpu_to_be32 ( FDT_VERSION ) ) {
938  DBGC ( fdt, "FDT unsupported version %d\n",
939  be32_to_cpu ( hdr->last_comp_version ) );
940  goto err;
941  }
942 
943  /* Record structure block location */
944  fdt->structure = be32_to_cpu ( hdr->off_dt_struct );
945  fdt->structure_len = be32_to_cpu ( hdr->size_dt_struct );
946  DBGC ( fdt, "FDT structure block at +[%#04x,%#04zx)\n",
948  if ( ( fdt->structure > fdt->len ) ||
949  ( fdt->structure_len > ( fdt->len - fdt->structure ) ) ) {
950  DBGC ( fdt, "FDT structure block exceeds table\n" );
951  goto err;
952  }
953  if ( ( fdt->structure | fdt->structure_len ) &
954  ( FDT_STRUCTURE_ALIGN - 1 ) ) {
955  DBGC ( fdt, "FDT structure block is misaligned\n" );
956  goto err;
957  }
958  end = ( fdt->structure + fdt->structure_len );
959  if ( fdt->used < end )
960  fdt->used = end;
961 
962  /* Record strings block location */
963  fdt->strings = be32_to_cpu ( hdr->off_dt_strings );
964  fdt->strings_len = be32_to_cpu ( hdr->size_dt_strings );
965  DBGC ( fdt, "FDT strings block at +[%#04x,%#04zx)\n",
966  fdt->strings, ( fdt->strings + fdt->strings_len ) );
967  if ( ( fdt->strings > fdt->len ) ||
968  ( fdt->strings_len > ( fdt->len - fdt->strings ) ) ) {
969  DBGC ( fdt, "FDT strings block exceeds table\n" );
970  goto err;
971  }
972  end = ( fdt->strings + fdt->strings_len );
973  if ( fdt->used < end )
974  fdt->used = end;
975 
976  /* Shrink strings block to ensure NUL termination safety */
977  nul = ( fdt->raw + fdt->strings + fdt->strings_len );
978  for ( ; fdt->strings_len ; fdt->strings_len-- ) {
979  if ( *(--nul) == '\0' )
980  break;
981  }
982  if ( fdt->strings_len != be32_to_cpu ( hdr->size_dt_strings ) ) {
983  DBGC ( fdt, "FDT strings block shrunk to +[%#04x,%#04zx)\n",
984  fdt->strings, ( fdt->strings + fdt->strings_len ) );
985  }
986 
987  /* Record memory reservation block location */
988  fdt->reservations = be32_to_cpu ( hdr->off_mem_rsvmap );
989  DBGC ( fdt, "FDT memory reservations at +[%#04x,...)\n",
990  fdt->reservations );
991  if ( fdt->used <= fdt->reservations ) {
992  /* No size field exists: assume whole table is used */
993  fdt->used = fdt->len;
994  }
995 
996  /* Identify free space (if any) */
997  if ( fdt->used < fdt->len ) {
998  DBGC ( fdt, "FDT free space at +[%#04zx,%#04zx)\n",
999  fdt->used, fdt->len );
1000  }
1001 
1002  /* Print model name and boot arguments (for debugging) */
1003  if ( DBG_LOG ) {
1004  DBGC ( fdt, "FDT model is \"%s\"\n",
1005  fdt_string ( fdt, 0, "model" ) );
1006  if ( fdt_child ( fdt, 0, "chosen", &chosen ) == 0 ) {
1007  DBGC ( fdt, "FDT boot arguments \"%s\"\n",
1008  fdt_string ( fdt, chosen, "bootargs" ) );
1009  }
1010  }
1011 
1012  return 0;
1013 
1014  err:
1015  DBGC_HDA ( fdt, 0, hdr, sizeof ( *hdr ) );
1016  memset ( fdt, 0, sizeof ( *fdt ) );
1017  return -EINVAL;
1018 }
1019 
1020 /**
1021  * Parse device tree image
1022  *
1023  * @v fdt Device tree
1024  * @v image Image
1025  * @ret rc Return status code
1026  */
1027 static int fdt_parse_image ( struct fdt *fdt, struct image *image ) {
1028  int rc;
1029 
1030  /* Parse image */
1031  if ( ( rc = fdt_parse ( fdt, image->rwdata, image->len ) ) != 0 ) {
1032  DBGC ( fdt, "FDT image \"%s\" is invalid: %s\n",
1033  image->name, strerror ( rc ) );
1034  return rc;
1035  }
1036 
1037  DBGC ( fdt, "FDT image is \"%s\"\n", image->name );
1038  return 0;
1039 }
1040 
1041 /**
1042  * Insert empty space
1043  *
1044  * @v fdt Device tree
1045  * @v offset Offset at which to insert space
1046  * @v len Length to insert (must be a multiple of FDT_MAX_ALIGN)
1047  * @ret rc Return status code
1048  */
1049 static int fdt_insert ( struct fdt *fdt, unsigned int offset, size_t len ) {
1050  size_t free;
1051  size_t new;
1052  int rc;
1053 
1054  /* Sanity checks */
1055  assert ( offset <= fdt->used );
1056  assert ( fdt->used <= fdt->len );
1057  assert ( ( len % FDT_MAX_ALIGN ) == 0 );
1058 
1059  /* Reallocate tree if necessary */
1060  free = ( fdt->len - fdt->used );
1061  if ( free < len ) {
1062  if ( ! fdt->realloc ) {
1063  DBGC ( fdt, "FDT is not reallocatable\n" );
1064  return -ENOTSUP;
1065  }
1066  new = ( fdt->len + ( len - free ) + FDT_INSERT_PAD );
1067  if ( ( rc = fdt->realloc ( fdt, new ) ) != 0 )
1068  return rc;
1069  }
1070  assert ( ( fdt->used + len ) <= fdt->len );
1071 
1072  /* Insert empty space */
1073  memmove ( ( fdt->raw + offset + len ), ( fdt->raw + offset ),
1074  ( fdt->used - offset ) );
1075  memset ( ( fdt->raw + offset ), 0, len );
1076  fdt->used += len;
1077 
1078  /* Update offsets
1079  *
1080  * We assume that we never need to legitimately insert data at
1081  * the start of a block, and therefore can unambiguously
1082  * determine which block offsets need to be updated.
1083  *
1084  * It is the caller's responsibility to update the length (and
1085  * contents) of the block into which it has inserted space.
1086  */
1087  if ( fdt->structure >= offset ) {
1088  fdt->structure += len;
1090  DBGC ( fdt, "FDT structure block now at +[%#04x,%#04zx)\n",
1091  fdt->structure,
1092  ( fdt->structure + fdt->structure_len ) );
1093  }
1094  if ( fdt->strings >= offset ) {
1095  fdt->strings += len;
1097  DBGC ( fdt, "FDT strings block now at +[%#04x,%#04zx)\n",
1098  fdt->strings, ( fdt->strings + fdt->strings_len ) );
1099  }
1100  if ( fdt->reservations >= offset ) {
1101  fdt->reservations += len;
1103  DBGC ( fdt, "FDT memory reservations now at +[%#04x,...)\n",
1104  fdt->reservations );
1105  }
1106 
1107  return 0;
1108 }
1109 
1110 /**
1111  * Fill space in structure block with FDT_NOP
1112  *
1113  * @v fdt Device tree
1114  * @v offset Starting offset
1115  * @v len Length (must be a multiple of FDT_STRUCTURE_ALIGN)
1116  */
1117 static void fdt_nop ( struct fdt *fdt, unsigned int offset, size_t len ) {
1118  fdt_token_t *token;
1119  unsigned int count;
1120 
1121  /* Sanity check */
1122  assert ( ( len % FDT_STRUCTURE_ALIGN ) == 0 );
1123 
1124  /* Fill with FDT_NOP */
1125  token = ( fdt->raw + fdt->structure + offset );
1126  count = ( len / sizeof ( *token ) );
1127  while ( count-- )
1128  *(token++) = cpu_to_be32 ( FDT_NOP );
1129 }
1130 
1131 /**
1132  * Insert FDT_NOP padded space in structure block
1133  *
1134  * @v fdt Device tree
1135  * @v offset Offset at which to insert space
1136  * @v len Minimal length to insert
1137  * @ret rc Return status code
1138  */
1139 static int fdt_insert_nop ( struct fdt *fdt, unsigned int offset,
1140  size_t len ) {
1141  int rc;
1142 
1143  /* Sanity check */
1144  assert ( ( offset % FDT_STRUCTURE_ALIGN ) == 0 );
1145 
1146  /* Round up inserted length to maximal alignment */
1147  len = ( ( len + FDT_MAX_ALIGN - 1 ) & ~( FDT_MAX_ALIGN - 1 ) );
1148 
1149  /* Insert empty space in structure block */
1150  if ( ( rc = fdt_insert ( fdt, ( fdt->structure + offset ),
1151  len ) ) != 0 )
1152  return rc;
1153 
1154  /* Fill with NOPs */
1155  fdt_nop ( fdt, offset, len );
1156 
1157  /* Update structure block size */
1158  fdt->structure_len += len;
1160  DBGC ( fdt, "FDT structure block now at +[%#04x,%#04zx)\n",
1162 
1163  return 0;
1164 }
1165 
1166 /**
1167  * Insert string in strings block
1168  *
1169  * @v fdt Device tree
1170  * @v string String
1171  * @v offset String offset to fill in
1172  * @ret rc Return status code
1173  */
1174 static int fdt_insert_string ( struct fdt *fdt, const char *string,
1175  unsigned int *offset ) {
1176  size_t len = ( strlen ( string ) + 1 /* NUL */ );
1177  int rc;
1178 
1179  /* Round up inserted length to maximal alignment */
1180  len = ( ( len + FDT_MAX_ALIGN - 1 ) & ~( FDT_MAX_ALIGN - 1 ) );
1181 
1182  /* Insert space at end of strings block */
1183  if ( ( rc = fdt_insert ( fdt, ( fdt->strings + fdt->strings_len ),
1184  len ) ) != 0 )
1185  return rc;
1186 
1187  /* Append string to strings block */
1188  *offset = fdt->strings_len;
1189  strcpy ( ( fdt->raw + fdt->strings + *offset ), string );
1190 
1191  /* Update strings block size */
1192  fdt->strings_len += len;
1194  DBGC ( fdt, "FDT strings block now at +[%#04x,%#04zx)\n",
1195  fdt->strings, ( fdt->strings + fdt->strings_len ) );
1196 
1197  return 0;
1198 }
1199 
1200 /**
1201  * Ensure child node exists
1202  *
1203  * @v fdt Device tree
1204  * @v offset Starting node offset
1205  * @v name New node name
1206  * @v child Child node offset to fill in
1207  * @ret rc Return status code
1208  */
1209 static int fdt_ensure_child ( struct fdt *fdt, unsigned int offset,
1210  const char *name, unsigned int *child ) {
1211  size_t name_len = ( strlen ( name ) + 1 /* NUL */ );
1212  fdt_token_t *token;
1213  size_t len;
1214  int rc;
1215 
1216  /* Find existing child node, if any */
1217  if ( ( rc = fdt_child ( fdt, offset, name, child ) ) == 0 )
1218  return 0;
1219 
1220  /* Find end of parent node */
1221  if ( ( rc = fdt_end ( fdt, offset, child ) ) != 0 )
1222  return rc;
1223 
1224  /* Insert space for child node (with maximal alignment) */
1225  len = ( sizeof ( fdt_token_t ) /* BEGIN_NODE */ + name_len +
1226  sizeof ( fdt_token_t ) /* END_NODE */ );
1227  if ( ( rc = fdt_insert_nop ( fdt, *child, len ) ) != 0 )
1228  return rc;
1229 
1230  /* Construct node */
1231  token = ( fdt->raw + fdt->structure + *child );
1232  *(token++) = cpu_to_be32 ( FDT_BEGIN_NODE );
1233  memcpy ( token, name, name_len );
1234  name_len = ( ( name_len + FDT_STRUCTURE_ALIGN - 1 ) &
1235  ~( FDT_STRUCTURE_ALIGN - 1 ) );
1236  token = ( ( ( void * ) token ) + name_len );
1237  *(token++) = cpu_to_be32 ( FDT_END_NODE );
1238  DBGC2 ( fdt, "FDT +%#04x created child \"%s\" at +%#04x\n",
1239  offset, name, *child );
1240 
1241  return 0;
1242 }
1243 
1244 /**
1245  * Set property value
1246  *
1247  * @v fdt Device tree
1248  * @v offset Starting node offset
1249  * @v name Property name
1250  * @v data Property data, or NULL to delete property
1251  * @v len Length of property data
1252  * @ret rc Return status code
1253  */
1254 static int fdt_set ( struct fdt *fdt, unsigned int offset, const char *name,
1255  const void *data, size_t len ) {
1256  struct fdt_descriptor desc;
1257  struct {
1259  struct fdt_prop prop;
1260  uint8_t data[0];
1261  } __attribute__ (( packed )) *hdr;
1262  unsigned int string;
1263  size_t erase;
1264  size_t insert;
1265  int rc;
1266 
1267  /* Find and reuse existing property, if any */
1268  if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) == 0 ) {
1269 
1270  /* Reuse existing name */
1271  hdr = ( fdt->raw + fdt->structure + desc.offset );
1272  string = be32_to_cpu ( hdr->prop.name_off );
1273 
1274  /* Erase existing property */
1275  erase = ( sizeof ( *hdr ) + desc.len );
1276  erase = ( ( erase + FDT_STRUCTURE_ALIGN - 1 ) &
1277  ~( FDT_STRUCTURE_ALIGN - 1 ) );
1278  fdt_nop ( fdt, desc.offset, erase );
1279  DBGC2 ( fdt, "FDT +%#04x erased property \"%s\"\n",
1280  offset, name );
1281 
1282  /* Calculate insertion position and length */
1283  insert = ( ( desc.len < len ) ? ( len - desc.len ) : 0 );
1284 
1285  } else {
1286 
1287  /* Create name */
1288  if ( ( rc = fdt_insert_string ( fdt, name, &string ) ) != 0 )
1289  return rc;
1290 
1291  /* Enter node */
1292  if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 )
1293  return rc;
1294  assert ( desc.depth > 0 );
1295  desc.offset = desc.next;
1296 
1297  /* Calculate insertion length */
1298  insert = ( sizeof ( *hdr ) + len );
1299  }
1300 
1301  /* Leave property erased if applicable */
1302  if ( ! data )
1303  return 0;
1304 
1305  /* Insert space */
1306  if ( ( rc = fdt_insert_nop ( fdt, desc.offset, insert ) ) != 0 )
1307  return rc;
1308 
1309  /* Construct property */
1310  hdr = ( fdt->raw + fdt->structure + desc.offset );
1311  hdr->token = cpu_to_be32 ( FDT_PROP );
1312  hdr->prop.len = cpu_to_be32 ( len );
1313  hdr->prop.name_off = cpu_to_be32 ( string );
1314  memset ( hdr->data, 0, ( ( len + FDT_STRUCTURE_ALIGN - 1 ) &
1315  ~( FDT_STRUCTURE_ALIGN - 1 ) ) );
1316  memcpy ( hdr->data, data, len );
1317  DBGC2 ( fdt, "FDT +%#04x created property \"%s\"\n", offset, name );
1318  DBGC2_HDA ( fdt, 0, hdr->data, len );
1319 
1320  return 0;
1321 }
1322 
1323 /**
1324  * Reallocate device tree via urealloc()
1325  *
1326  * @v fdt Device tree
1327  * @v len New total length
1328  * @ret rc Return status code
1329  */
1330 static int fdt_urealloc ( struct fdt *fdt, size_t len ) {
1331  void *new;
1332 
1333  /* Sanity check */
1334  assert ( len >= fdt->used );
1335 
1336  /* Attempt reallocation */
1337  new = urealloc ( fdt->raw, len );
1338  if ( ! new ) {
1339  DBGC ( fdt, "FDT could not reallocate from +%#04zx to "
1340  "+%#04zx\n", fdt->len, len );
1341  return -ENOMEM;
1342  }
1343  DBGC ( fdt, "FDT reallocated from +%#04zx to +%#04zx\n",
1344  fdt->len, len );
1345 
1346  /* Update device tree */
1347  fdt->raw = new;
1348  fdt->len = len;
1349  fdt->hdr->totalsize = cpu_to_be32 ( len );
1350 
1351  return 0;
1352 }
1353 
1354 /**
1355  * Populate device tree with boot arguments
1356  *
1357  * @v fdt Device tree
1358  * @v cmdline Command line, or NULL
1359  * @v initrd Initial ramdisk address (or 0 for no initrd)
1360  * @v initrd_len Initial ramdisk length (or 0 for no initrd)
1361  * @ret rc Return status code
1362  */
1363 static int fdt_bootargs ( struct fdt *fdt, const char *cmdline,
1364  physaddr_t initrd, size_t initrd_len ) {
1365  unsigned int chosen;
1366  physaddr_t addr;
1367  const void *data;
1368  size_t len;
1369  int rc;
1370 
1371  /* Ensure "chosen" node exists */
1372  if ( ( rc = fdt_ensure_child ( fdt, 0, "chosen", &chosen ) ) != 0 )
1373  return rc;
1374 
1375  /* Set or clear "bootargs" property */
1376  len = ( cmdline ? ( strlen ( cmdline ) + 1 /* NUL */ ) : 0 );
1377  if ( ( rc = fdt_set ( fdt, chosen, "bootargs", cmdline, len ) ) != 0 )
1378  return rc;
1379 
1380  /* Set or clear initrd properties */
1381  data = ( initrd_len ? &addr : NULL );
1382  len = ( initrd_len ? sizeof ( addr ) : 0 );
1383  addr = initrd;
1384  addr = ( ( sizeof ( addr ) == sizeof ( uint64_t ) ) ?
1385  cpu_to_be64 ( addr ) : cpu_to_be32 ( addr ) );
1386  if ( ( rc = fdt_set ( fdt, chosen, "linux,initrd-start", data,
1387  len ) ) != 0 )
1388  return rc;
1389  addr = ( initrd + initrd_len );
1390  addr = ( ( sizeof ( addr ) == sizeof ( uint64_t ) ) ?
1391  cpu_to_be64 ( addr ) : cpu_to_be32 ( addr ) );
1392  if ( ( rc = fdt_set ( fdt, chosen, "linux,initrd-end", data,
1393  len ) ) != 0 )
1394  return rc;
1395 
1396  return 0;
1397 }
1398 
1399 /**
1400  * Create device tree
1401  *
1402  * @v hdr Device tree header to fill in (may be set to NULL)
1403  * @v cmdline Command line, or NULL
1404  * @v initrd Initial ramdisk address (or 0 for no initrd)
1405  * @v initrd_len Initial ramdisk length (or 0 for no initrd)
1406  * @ret rc Return status code
1407  */
1408 int fdt_create ( struct fdt_header **hdr, const char *cmdline,
1409  physaddr_t initrd, size_t initrd_len ) {
1410  struct image *image;
1411  struct fdt fdt;
1412  void *copy;
1413  int rc;
1414 
1415  /* Use system FDT as the base by default */
1416  memcpy ( &fdt, &sysfdt, sizeof ( fdt ) );
1417 
1418  /* If an FDT image exists, use this instead */
1419  image = find_image_tag ( &fdt_image );
1420  if ( image && ( ( rc = fdt_parse_image ( &fdt, image ) ) != 0 ) )
1421  goto err_image;
1422 
1423  /* Exit successfully if we have no base FDT */
1424  if ( ! fdt.len ) {
1425  DBGC ( &fdt, "FDT has no base tree\n" );
1426  goto no_fdt;
1427  }
1428 
1429  /* Create modifiable copy */
1430  copy = umalloc ( fdt.len );
1431  if ( ! copy ) {
1432  rc = -ENOMEM;
1433  goto err_alloc;
1434  }
1435  memcpy ( copy, fdt.raw, fdt.len );
1436  fdt.raw = copy;
1438 
1439  /* Populate boot arguments */
1440  if ( ( rc = fdt_bootargs ( &fdt, cmdline, initrd, initrd_len ) ) != 0 )
1441  goto err_bootargs;
1442 
1443  no_fdt:
1444  *hdr = fdt.raw;
1445  return 0;
1446 
1447  err_bootargs:
1448  ufree ( fdt.raw );
1449  err_alloc:
1450  err_image:
1451  return rc;
1452 }
1453 
1454 /**
1455  * Remove device tree
1456  *
1457  * @v hdr Device tree header, or NULL
1458  */
1459 void fdt_remove ( struct fdt_header *hdr ) {
1460 
1461  /* Free modifiable copy */
1462  ufree ( hdr );
1463 }
1464 
1465 /* Drag in objects via fdt_describe() */
1467 
1468 /* Drag in device tree configuration */
1469 REQUIRE_OBJECT ( config_fdt );
int fdt_parent(struct fdt *fdt, unsigned int offset, unsigned int *parent)
Find parent node.
Definition: fdt.c:293
#define __attribute__(x)
Definition: compiler.h:10
static __always_inline void ufree(void *ptr)
Free external memory.
Definition: umalloc.h:68
#define EINVAL
Invalid argument.
Definition: errno.h:429
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
const char * name
Definition: ath9k_hw.c:1986
int depth
Depth change.
Definition: fdt.h:133
static int fdt_match(const struct fdt_descriptor *desc, const char *name)
Compare node name.
Definition: fdt.c:74
#define FDT_STRUCTURE_ALIGN
Alignment of structure block.
Definition: fdt.h:75
#define FDT_NOP
NOP token.
Definition: fdt.h:69
unsigned int reservations
Offset to memory reservation block.
Definition: fdt.h:110
int erase(void)
Completely clear the screen.
Definition: clear.c:98
int fdt_alias(struct fdt *fdt, const char *name, unsigned int *offset)
Find node by alias.
Definition: fdt.c:466
An image tag.
Definition: image.h:173
int(* realloc)(struct fdt *fdt, size_t len)
Reallocate device tree.
Definition: fdt.h:117
static int fdt_urealloc(struct fdt *fdt, size_t len)
Reallocate device tree via urealloc()
Definition: fdt.c:1330
Error codes.
size_t len
Length of tree.
Definition: fdt.h:98
int fdt_parse(struct fdt *fdt, struct fdt_header *hdr, size_t max_len)
Parse device tree.
Definition: fdt.c:904
Device tree header.
Definition: fdt.h:19
struct golan_inbox_hdr hdr
Message header.
Definition: CIB_PRM.h:28
static int fdt_enter(struct fdt *fdt, unsigned int offset, struct fdt_descriptor *desc)
Enter node.
Definition: fdt.c:212
static int fdt_set(struct fdt *fdt, unsigned int offset, const char *name, const void *data, size_t len)
Set property value.
Definition: fdt.c:1254
uint64_t address
Base address.
Definition: ena.h:24
void * raw
Raw data.
Definition: fdt.h:95
uint16_t size
Buffer size.
Definition: dwmac.h:14
int fdt_describe(struct fdt *fdt, unsigned int offset, struct fdt_descriptor *desc)
Describe device tree token.
Definition: fdt.c:90
int fdt_path(struct fdt *fdt, const char *path, unsigned int *offset)
Find node by path.
Definition: fdt.c:426
#define DBGC(...)
Definition: compiler.h:505
A device tree region cell size specification.
Definition: fdt.h:137
const char * fdt_strings(struct fdt *fdt, unsigned int offset, const char *name, unsigned int *count)
Find strings property.
Definition: fdt.c:540
long index
Definition: bigint.h:65
#define ENOENT
No such file or directory.
Definition: errno.h:515
unsigned long long uint64_t
Definition: stdint.h:13
uint32_t string
Definition: multiboot.h:14
An executable image.
Definition: image.h:24
Character types.
struct image_tag fdt_image __image_tag
The downloaded flattened device tree tag.
Definition: fdt.c:48
size_t strings_len
Length of strings block.
Definition: fdt.h:108
int fdt_mac(struct fdt *fdt, unsigned int offset, struct net_device *netdev)
Get MAC address from property.
Definition: fdt.c:867
uint32_t fdt_token_t
Device tree token.
Definition: fdt.h:49
struct fdt_header * hdr
Tree header.
Definition: fdt.h:93
REQUIRING_SYMBOL(fdt_describe)
uint32_t off_dt_struct
Offset to structure block.
Definition: fdt.h:25
#define ENOTSUP
Operation not supported.
Definition: errno.h:590
struct image * find_image_tag(struct image_tag *tag)
Find image by tag.
Definition: image.c:393
uint32_t len
Data length.
Definition: fdt.h:63
uint8_t ch
Definition: registers.h:83
unsigned long tmp
Definition: linux_pci.h:65
struct ena_llq_option desc
Descriptor counts.
Definition: ena.h:20
#define ENOMEM
Not enough space.
Definition: errno.h:535
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static int fdt_insert_string(struct fdt *fdt, const char *string, unsigned int *offset)
Insert string in strings block.
Definition: fdt.c:1174
uint32_t fdt_phandle(struct fdt *fdt, unsigned int offset)
Get package handle (phandle) property.
Definition: fdt.c:690
FILE_SECBOOT(PERMITTED)
static int fdt_bootargs(struct fdt *fdt, const char *cmdline, physaddr_t initrd, size_t initrd_len)
Populate device tree with boot arguments.
Definition: fdt.c:1363
uint32_t off_dt_strings
Offset to strings block.
Definition: fdt.h:27
Assertions.
#define be32_to_cpu(value)
Definition: byteswap.h:117
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Access to external ("user") memory.
Executable images.
uint8_t hw_addr_len
Hardware address length.
Definition: netdevice.h:197
int fdt_u32(struct fdt *fdt, unsigned int offset, const char *name, uint32_t *value)
Get 32-bit integer property.
Definition: fdt.c:664
static int isalnum(int character)
Check if character is alphanumeric.
Definition: ctype.h:87
#define FDT_MAGIC
Magic signature.
Definition: fdt.h:43
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
#define DBGC_HDA(...)
Definition: compiler.h:506
static int fdt_property(struct fdt *fdt, unsigned int offset, const char *name, struct fdt_descriptor *desc)
Find property.
Definition: fdt.c:495
ring len
Length.
Definition: dwmac.h:231
void fdt_remove(struct fdt_header *hdr)
Remove device tree.
Definition: fdt.c:1459
static struct net_device * netdev
Definition: gdbudp.c:52
static unsigned int count
Number of entries.
Definition: dwmac.h:225
char * strcpy(char *dest, const char *src)
Copy string.
Definition: string.c:347
void fdt_reg_cells(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs)
Get region cell size specification.
Definition: fdt.c:716
const char * fdt_string(struct fdt *fdt, unsigned int offset, const char *name)
Find string property.
Definition: fdt.c:579
unsigned int structure
Offset to structure block.
Definition: fdt.h:102
#define FDT_VERSION
Expected device tree version.
Definition: fdt.h:46
#define DBGC2_HDA(...)
Definition: compiler.h:523
static int fdt_child(struct fdt *fdt, unsigned int offset, const char *name, unsigned int *child)
Find child node.
Definition: fdt.c:347
static int fdt_permitted(char ch)
Check if character is permitted in a name.
Definition: fdt.c:61
#define ERANGE
Result too large.
Definition: errno.h:640
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
size_t len
Length of raw file image.
Definition: image.h:56
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
char * strchr(const char *src, int character)
Find character within a string.
Definition: string.c:272
uint32_t size_dt_strings
Length of string block.
Definition: fdt.h:37
uint32_t addr
Buffer address.
Definition: dwmac.h:20
User memory allocation.
int fdt_reg_count(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs)
Get number of regions.
Definition: fdt.c:767
Property fragment.
Definition: fdt.h:61
A network device.
Definition: netdevice.h:353
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
int fdt_reg_address(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs, unsigned int index, uint64_t *address)
Get region address.
Definition: fdt.c:793
static int fdt_insert_nop(struct fdt *fdt, unsigned int offset, size_t len)
Insert FDT_NOP padded space in structure block.
Definition: fdt.c:1139
static int fdt_next(struct fdt *fdt, struct fdt_descriptor *desc)
Describe next device tree token.
Definition: fdt.c:198
unsigned char uint8_t
Definition: stdint.h:10
size_t strnlen(const char *src, size_t max)
Get length of string.
Definition: string.c:256
size_t used
Used length of tree.
Definition: fdt.h:100
uint32_t off_mem_rsvmap
Offset to memory reservation block.
Definition: fdt.h:29
unsigned int uint32_t
Definition: stdint.h:12
void * memmove(void *dest, const void *src, size_t len) __nonnull
struct i386_regs regs
Definition: registers.h:15
u8 token
Definition: CIB_PRM.h:42
int fdt_reg(struct fdt *fdt, unsigned int offset, uint64_t *region)
Get unsized single-entry region address.
Definition: fdt.c:844
REQUIRE_OBJECT(config_fdt)
size_t structure_len
Length of structure block.
Definition: fdt.h:104
#define FDT_PROP
Property token.
Definition: fdt.h:58
Network device management.
unsigned long physaddr_t
Definition: stdint.h:20
static int fdt_depth(struct fdt *fdt, unsigned int offset, unsigned int target)
Find node relative depth.
Definition: fdt.c:252
#define cpu_to_be32(value)
Definition: byteswap.h:111
A device tree.
Definition: fdt.h:89
uint32_t size_dt_struct
Length of structure block.
Definition: fdt.h:39
#define DBGC2(...)
Definition: compiler.h:522
uint32_t totalsize
Total size of device tree.
Definition: fdt.h:23
uint32_t name_off
Name offset.
Definition: fdt.h:65
#define FDT_END_NODE
End node token.
Definition: fdt.h:55
static __always_inline void * umalloc(size_t size)
Allocate external memory.
Definition: umalloc.h:57
void * rwdata
Writable data.
Definition: image.h:53
Flattened Device Tree.
uint32_t end
Ending offset.
Definition: netvsc.h:18
#define cpu_to_be64(value)
Definition: byteswap.h:112
uint8_t data[48]
Additional event data.
Definition: ena.h:22
static void fdt_nop(struct fdt *fdt, unsigned int offset, size_t len)
Fill space in structure block with FDT_NOP.
Definition: fdt.c:1117
#define FDT_INSERT_PAD
Amount of free space to add whenever we have to reallocate a tree.
Definition: fdt.c:53
static int fdt_insert(struct fdt *fdt, unsigned int offset, size_t len)
Insert empty space.
Definition: fdt.c:1049
#define FDT_BEGIN_NODE
Begin node token.
Definition: fdt.h:52
int fdt_parent_reg_cells(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs)
Get parent region cell size specification.
Definition: fdt.c:744
static int fdt_end(struct fdt *fdt, unsigned int offset, unsigned int *end)
Find end of node.
Definition: fdt.c:391
A device tree token descriptor.
Definition: fdt.h:121
void * urealloc(void *ptr, size_t new_size)
Reallocate external memory.
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
uint32_t cmdline
Definition: multiboot.h:16
#define FDT_DEFAULT_SIZE_CELLS
Default number of size cells, if not specified.
Definition: fdt.h:150
#define DBG_LOG
Definition: compiler.h:317
int fdt_reg_size(struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs, unsigned int index, uint64_t *size)
Get region size.
Definition: fdt.c:818
int fdt_create(struct fdt_header **hdr, const char *cmdline, physaddr_t initrd, size_t initrd_len)
Create device tree.
Definition: fdt.c:1408
int fdt_u64(struct fdt *fdt, unsigned int offset, const char *name, uint64_t *value)
Get 64-bit integer property.
Definition: fdt.c:644
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:115
char * name
Name.
Definition: image.h:38
uint8_t hw_addr[MAX_HW_ADDR_LEN]
Hardware address.
Definition: netdevice.h:382
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
static int fdt_ensure_child(struct fdt *fdt, unsigned int offset, const char *name, unsigned int *child)
Ensure child node exists.
Definition: fdt.c:1209
String functions.
int fdt_cells(struct fdt *fdt, unsigned int offset, const char *name, unsigned int index, unsigned int count, uint64_t *value)
Get integer property.
Definition: fdt.c:598
const char * name
Name.
Definition: image.h:175
const void * data
Property data (if applicable)
Definition: fdt.h:129
#define FDT_DEFAULT_ADDRESS_CELLS
Default number of address cells, if not specified.
Definition: fdt.h:147
struct ll_protocol * ll_protocol
Link-layer protocol.
Definition: netdevice.h:373
#define FDT_MAX_ALIGN
Maximum alignment of any block.
Definition: fdt.h:78
unsigned int strings
Offset to strings block.
Definition: fdt.h:106
static int fdt_parse_image(struct fdt *fdt, struct image *image)
Parse device tree image.
Definition: fdt.c:1027
void * memset(void *dest, int character, size_t len) __nonnull
#define initrd_len
Definition: runtime.c:63
struct fdt sysfdt
The system flattened device tree (if present)
Definition: fdt.c:45