source: rtems/cpukit/libmisc/rtems-fdt/rtems-fdt.c @ 3af84c1

Last change on this file since 3af84c1 was 3af84c1, checked in by Kinsey Moore <kinsey.moore@…>, on 09/20/22 at 15:30:12

cpukit/fdt: Free index before container

Ensure that the index is released before the structure containing it is
freed and NULLed.

Updates #4460

  • Property mode set to 100644
File size: 25.5 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/*
4 *  COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@rtems.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <errno.h>
29#include <fcntl.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34
35#include <libfdt.h>
36#include <zlib.h>
37
38#include <rtems/rtems-fdt.h>
39#include <rtems/thread.h>
40
41/**
42 * An index for quick access to the FDT by name or offset.
43 */
44
45typedef struct
46{
47  const char *             name;         /**< The full path of the FDT item. */
48  int                      offset;       /**< The offset of the item in the FDT blob. */
49} rtems_fdt_index_entry;
50
51typedef struct
52{
53  int                    num_entries;    /**< The number of entries in this index. */
54  rtems_fdt_index_entry* entries;        /**< An ordered set of entries which we
55                                          *  can binary search. */
56  char*                  names;          /**< Storage allocated for all the path names. */
57} rtems_fdt_index;
58
59
60/**
61 * A blob descriptor.
62 */
63struct rtems_fdt_blob
64{
65  rtems_chain_node node;        /**< The node's link in the chain. */
66  const void*      blob;        /**< The FDT blob. */
67  const char*      name;        /**< The name of the blob. */
68  int              refs;        /**< The number of active references of the blob. */
69  rtems_fdt_index  index;       /**< The index used for quick access to items in the blob. */
70};
71
72/**
73 * The global FDT data. This structure is allocated on the heap when the first
74 * call to load a FDT blob is made and released when all blobs have been
75 * unloaded..
76 */
77typedef struct
78{
79  rtems_mutex         lock;     /**< The FDT lock id */
80  rtems_chain_control blobs;    /**< List if loaded blobs. */
81  const char*         paths;    /**< Search paths for blobs. */
82} rtems_fdt_data;
83
84static void
85rtems_fdt_unlock (rtems_fdt_data *fdt)
86{
87  rtems_mutex_unlock (&fdt->lock);
88}
89
90static rtems_fdt_data*
91rtems_fdt_lock (void)
92{
93  static rtems_fdt_data fdt_instance = {
94    .lock = RTEMS_MUTEX_INITIALIZER ("FDT"),
95    .blobs = RTEMS_CHAIN_INITIALIZER_EMPTY (fdt_instance.blobs)
96  };
97  rtems_fdt_data *fdt = &fdt_instance;
98
99  rtems_mutex_lock (&fdt->lock);
100  return fdt;
101}
102
103/**
104 * Create an index based on the contents of an FDT blob.
105 */
106static int
107rtems_fdt_init_index (rtems_fdt_handle* fdt, rtems_fdt_blob* blob)
108{
109  rtems_fdt_index_entry* entries = NULL;
110  int                    num_entries = 0;
111  int                    entry = 0;
112  size_t                 total_name_memory = 0;
113  char                   node_path[256];
114  int                    depth_path[32];
115  int                    start_offset = 0;
116  int                    start_depth = 0;
117  int                    offset = 0;
118  int                    depth = 0;
119  char*                  names = NULL;
120  char*                  names_pos = NULL;
121
122  /*
123   * Count the number of entries in the blob first.
124   */
125  memset(&node_path, 0, sizeof(node_path));
126  strcpy(node_path, "/");
127  depth_path[0] = strlen(node_path);
128
129  start_offset = fdt_path_offset(fdt->blob->blob, node_path);
130  if (start_offset < 0)
131  {
132    return start_offset;
133  }
134
135  start_offset = fdt_next_node(fdt->blob->blob, start_offset, &start_depth);
136  if (start_offset < 0)
137  {
138    return start_offset;
139  }
140
141  offset = start_offset;
142  depth = start_depth;
143
144  while (depth > 0)
145  {
146    /*
147     * Construct the node path name.
148     */
149    int         namelen = 0;
150    const char* name = fdt_get_name(blob->blob, offset, &namelen);
151    strncpy(&node_path[depth_path[depth-1]],
152            name,
153            sizeof(node_path) - depth_path[depth-1] - 1);
154
155    total_name_memory += strlen(node_path) + 1;
156    num_entries++;
157
158    if (depth_path[depth-1] + namelen + 2 <= (int)sizeof(node_path))
159    {
160      strcpy(&node_path[depth_path[depth-1] + namelen], "/");
161    }
162
163    depth_path[depth] = depth_path[depth-1] + namelen + 1;
164
165    /*
166     * Get the next node.
167     */
168    offset = fdt_next_node(fdt->blob->blob, offset, &depth);
169    if (offset < 0)
170    {
171      return offset;
172    }
173  }
174
175  /*
176   * Create the index.
177   */
178  entries = calloc(num_entries, sizeof(rtems_fdt_index_entry));
179  if (!entries)
180  {
181    return -RTEMS_FDT_ERR_NO_MEMORY;
182  }
183
184  names = calloc(1, total_name_memory);
185  if (!names)
186  {
187    free(entries);
188    return -RTEMS_FDT_ERR_NO_MEMORY;
189  }
190
191  /*
192   * Populate the index.
193   */
194  offset = start_offset;
195  depth = start_depth;
196  entry = 0;
197  names_pos = names;
198
199  while (depth > 0)
200  {
201    /*
202     * Record this node in an entry.
203     */
204    int         namelen = 0;
205    const char* name = fdt_get_name(blob->blob, offset, &namelen);
206    strncpy(&node_path[depth_path[depth-1]],
207            name,
208            sizeof(node_path) - depth_path[depth-1] - 1);
209    strcpy(names_pos, node_path);
210
211    entries[entry].name = names_pos;
212    entries[entry].offset = offset;
213
214    names_pos += strlen(node_path) + 1;
215    entry++;
216
217    if (depth_path[depth-1] + namelen + 2 <= (int)sizeof(node_path))
218    {
219      strcpy(&node_path[depth_path[depth-1] + namelen], "/");
220    }
221
222    depth_path[depth] = depth_path[depth-1] + namelen + 1;
223
224    /*
225     * Get the next node.
226     */
227    offset = fdt_next_node(fdt->blob->blob, offset, &depth);
228    if (offset < 0)
229    {
230      free(entries);
231      free(names);
232      return offset;
233    }
234  }
235
236  fdt->blob->index.entries = entries;
237  fdt->blob->index.num_entries = num_entries;
238  fdt->blob->index.names = names;
239
240  return 0;
241}
242
243/**
244 * Release the contents of the index, freeing memory.
245 */
246static void
247rtems_fdt_release_index (rtems_fdt_index* index)
248{
249  if (index->entries)
250  {
251    free(index->entries);
252    free(index->names);
253
254    index->num_entries = 0;
255    index->entries = NULL;
256    index->names = NULL;
257  }
258}
259
260/**
261 * For a given FDT path, find the corresponding offset.
262 * Returns -1 if not found;
263 */
264static int
265rtems_fdt_index_find_by_name(rtems_fdt_index* index,
266                             const char*      name)
267{
268  int         min = 0;
269  int         max = index->num_entries;
270  /*
271   * Handle trailing slash case.
272   */
273  size_t namelen = strlen(name);
274  if (namelen > 0 && name[namelen-1] == '/')
275  {
276    namelen--;
277  }
278
279  /* Binary search for the name. */
280  while (min < max)
281  {
282    int middle = (min + max) / 2;
283    int cmp = strncmp(name, index->entries[middle].name, namelen);
284    if (cmp == 0)
285    {
286      /* 'namelen' characters are equal but 'index->entries[middle].name' */
287      /* could have additional characters. */
288      if (index->entries[middle].name[namelen] == '\0')
289      {
290        /* Found it. */
291        return index->entries[middle].offset;
292      }
293      else
294      {
295         /* 'index->entries[middle].name' is longer than 'name'. */
296         cmp = -1;
297      }
298    }
299    if (cmp < 0)
300    {
301      /* Look lower than here. */
302      max = middle;
303    }
304    else
305    {
306      /* Look higher than here. */
307      min = middle + 1;
308    }
309 }
310
311  /* Didn't find it. */
312  return -FDT_ERR_NOTFOUND;
313}
314
315/**
316 * For a given FDT offset, find the corresponding path name.
317 */
318static const char *
319rtems_fdt_index_find_name_by_offset(rtems_fdt_index* index,
320                                    int              offset)
321{
322  int min = 0;
323  int max = index->num_entries;
324
325  /*
326   * Binary search for the offset.
327   */
328  while (min < max)
329  {
330    int middle = (min + max) / 2;
331    if (offset < index->entries[middle].offset)
332    {
333      /* Look lower than here. */
334      max = middle;
335    }
336    else if (offset > index->entries[middle].offset)
337    {
338      /* Look higher than here. */
339      min = middle + 1;
340    }
341    else
342    {
343      /* Found it. */
344      return index->entries[middle].name;
345    }
346  }
347
348  /* Didn't find it. */
349  return NULL;
350}
351
352void
353rtems_fdt_init_handle (rtems_fdt_handle* handle)
354{
355  if (handle)
356    handle->blob = NULL;
357}
358
359void
360rtems_fdt_dup_handle (rtems_fdt_handle* from, rtems_fdt_handle* to)
361{
362  if (from && to)
363  {
364    rtems_fdt_data* fdt;
365
366    fdt = rtems_fdt_lock ();
367    to->blob = from->blob;
368    ++to->blob->refs;
369    rtems_fdt_unlock (fdt);
370  }
371}
372
373void
374rtems_fdt_release_handle (rtems_fdt_handle* handle)
375{
376  if (handle && handle->blob)
377  {
378    rtems_fdt_data*   fdt;
379    rtems_chain_node* node;
380
381    fdt = rtems_fdt_lock ();
382
383    node = rtems_chain_first (&fdt->blobs);
384
385    while (!rtems_chain_is_tail (&fdt->blobs, node))
386    {
387      rtems_fdt_blob* blob = (rtems_fdt_blob*) node;
388      if (handle->blob == blob)
389      {
390        if (blob->refs)
391          --blob->refs;
392        break;
393      }
394      node = rtems_chain_next (node);
395    }
396
397    rtems_fdt_unlock (fdt);
398
399    handle->blob = NULL;
400  }
401}
402
403bool
404rtems_fdt_valid_handle (const rtems_fdt_handle* handle)
405{
406  if (handle && handle->blob)
407  {
408    rtems_fdt_data*   fdt;
409    rtems_chain_node* node;
410
411    fdt = rtems_fdt_lock ();
412
413    node = rtems_chain_first (&fdt->blobs);
414
415    while (!rtems_chain_is_tail (&fdt->blobs, node))
416    {
417      rtems_fdt_blob* blob = (rtems_fdt_blob*) node;
418      if (handle->blob == blob)
419      {
420        rtems_fdt_unlock (fdt);
421        return true;
422      }
423      node = rtems_chain_next (node);
424    }
425
426    rtems_fdt_unlock (fdt);
427  }
428
429  return false;
430}
431
432int
433rtems_fdt_find_path_offset (rtems_fdt_handle* handle, const char* path)
434{
435  rtems_fdt_data*   fdt;
436  rtems_chain_node* node;
437
438  rtems_fdt_release_handle (handle);
439
440  fdt = rtems_fdt_lock ();
441
442  node = rtems_chain_first (&fdt->blobs);
443
444  while (!rtems_chain_is_tail (&fdt->blobs, node))
445  {
446    rtems_fdt_handle temp_handle;
447    int              offset;
448
449    temp_handle.blob = (rtems_fdt_blob*) node;
450
451    offset = rtems_fdt_path_offset (&temp_handle, path);
452
453    if (offset >= 0)
454    {
455      ++temp_handle.blob->refs;
456      handle->blob = temp_handle.blob;
457      rtems_fdt_unlock (fdt);
458      return offset;
459    }
460
461    node = rtems_chain_next (node);
462  }
463
464  rtems_fdt_unlock (fdt);
465
466  return -FDT_ERR_NOTFOUND;
467}
468
469int
470rtems_fdt_load (const char* filename, rtems_fdt_handle* handle)
471{
472  rtems_fdt_data* fdt;
473  rtems_fdt_blob* blob;
474  size_t          bsize;
475  int             bf;
476  ssize_t         r;
477  size_t          name_len;
478  int             fe;
479  struct stat     sb;
480  uint8_t         gzip_id[2];
481  uint8_t*        cdata;
482  size_t          size;
483
484  rtems_fdt_release_handle (handle);
485
486  if (stat (filename, &sb) < 0)
487  {
488    return -RTEMS_FDT_ERR_NOT_FOUND;
489  }
490
491  bf = open(filename, O_RDONLY);
492  if (bf < 0)
493  {
494    return -RTEMS_FDT_ERR_READ_FAIL;
495  }
496
497  r = read(bf, &gzip_id, sizeof(gzip_id));
498  if (r < 0)
499  {
500    close(bf);
501    return -RTEMS_FDT_ERR_READ_FAIL;
502  }
503
504  if ((gzip_id[0] == 0x1f) && (gzip_id[1] == 0x8b))
505  {
506    size_t offset;
507
508    cdata = malloc(sb.st_size);
509    if (!cdata)
510    {
511      close (bf);
512      return -RTEMS_FDT_ERR_NO_MEMORY;
513    }
514
515    if (lseek(bf, 0, SEEK_SET) < 0)
516    {
517      free(cdata);
518      close(bf);
519      return -RTEMS_FDT_ERR_READ_FAIL;
520    }
521
522    size = sb.st_size;
523    offset = 0;
524    while (size)
525    {
526      r = read(bf, cdata + offset, size);
527      if (r < 0)
528      {
529        free(cdata);
530        close(bf);
531        return -RTEMS_FDT_ERR_READ_FAIL;
532      }
533      size -= r;
534      offset += r;
535    }
536
537    offset = sb.st_size - 4;
538    bsize = ((cdata[offset + 3] << 24) | (cdata[offset + 2] << 16) |
539             (cdata[offset + 1] << 8) | cdata[offset + 0]);
540  }
541  else
542  {
543    cdata = NULL;
544    bsize = sb.st_size;
545  }
546
547  name_len = strlen (filename) + 1;
548
549  blob = malloc(sizeof (rtems_fdt_blob) + name_len + bsize);
550  if (!blob)
551  {
552    free(cdata);
553    close (bf);
554    return -RTEMS_FDT_ERR_NO_MEMORY;
555  }
556
557  blob->name = (const char*) (blob + 1);
558  blob->blob = blob->name + name_len + 1;
559
560  strcpy ((char*) blob->name, filename);
561
562  if ((gzip_id[0] == 0x1f) && (gzip_id[1] == 0x8b))
563  {
564    z_stream stream;
565    int      err;
566    stream.next_in = (Bytef*) cdata;
567    stream.avail_in = (uInt) sb.st_size;
568    stream.next_out = (void*) (blob->name + name_len + 1);
569    stream.avail_out = (uInt) bsize;
570    stream.zalloc = (alloc_func) 0;
571    stream.zfree = (free_func) 0;
572    err = inflateInit(&stream);
573    if (err == Z_OK)
574      err = inflateReset2(&stream, 31);
575    if (err == Z_OK)
576      err = inflate(&stream, Z_FINISH);
577    if ((err == Z_OK) || (err == Z_STREAM_END))
578      err = inflateEnd(&stream);
579    if ((err != Z_OK) || (bsize != stream.total_out))
580    {
581      free (blob);
582      free(cdata);
583      close (bf);
584      return -RTEMS_FDT_ERR_READ_FAIL;
585    }
586    free(cdata);
587    cdata = NULL;
588  }
589  else
590  {
591    char* buf = (char*) blob->name + name_len + 1;
592    size = bsize;
593    while (size)
594    {
595      r = read (bf, buf, size);
596      if (r < 0)
597      {
598        free (blob);
599        close (bf);
600        return -RTEMS_FDT_ERR_READ_FAIL;
601      }
602      size -= r;
603      buf += r;
604    }
605  }
606
607  fe = fdt_check_header(blob->blob);
608  if (fe < 0)
609  {
610    free (blob);
611    close (bf);
612    return fe;
613  }
614
615  fdt = rtems_fdt_lock ();
616
617  rtems_chain_append_unprotected (&fdt->blobs, &blob->node);
618
619  blob->refs = 1;
620
621  rtems_fdt_unlock (fdt);
622
623  handle->blob = blob;
624
625  fe = rtems_fdt_init_index(handle, blob);
626  if (fe < 0)
627  {
628    free (blob);
629    close (bf);
630    return fe;
631  }
632
633  close (bf);
634  return 0;
635}
636
637int
638rtems_fdt_register (const void* dtb, rtems_fdt_handle* handle)
639{
640  rtems_fdt_data* fdt;
641  rtems_fdt_blob* blob;
642  int             fe;
643
644  rtems_fdt_release_handle (handle);
645
646  fe = fdt_check_header(dtb);
647  if (fe < 0)
648  {
649    return fe;
650  }
651
652  blob = malloc(sizeof (rtems_fdt_blob));
653  if (!blob)
654  {
655    return -RTEMS_FDT_ERR_NO_MEMORY;
656  }
657
658  blob->blob = dtb;
659  blob->name = NULL;
660  rtems_chain_initialize_node(&blob->node);
661
662  fdt = rtems_fdt_lock ();
663
664  rtems_chain_append_unprotected (&fdt->blobs, &blob->node);
665
666  blob->refs = 1;
667
668  rtems_fdt_unlock (fdt);
669
670  handle->blob = blob;
671
672  fe = rtems_fdt_init_index(handle, blob);
673  if (fe < 0)
674  {
675    free(blob);
676    return -RTEMS_FDT_ERR_NO_MEMORY;
677  }
678
679  return 0;
680}
681
682int
683rtems_fdt_unload (rtems_fdt_handle* handle)
684{
685  rtems_fdt_data* fdt;
686
687  fdt = rtems_fdt_lock ();
688
689  if (!rtems_fdt_valid_handle (handle))
690  {
691    rtems_fdt_unlock (fdt);
692    return -RTEMS_FDT_ERR_INVALID_HANDLE;
693  }
694
695  if (handle->blob->refs > 1)
696  {
697    rtems_fdt_unlock (fdt);
698    return -RTEMS_FDT_ERR_REFERENCED;
699  }
700
701  rtems_chain_extract_unprotected (&handle->blob->node);
702
703  rtems_fdt_release_index(&handle->blob->index);
704
705  free (handle->blob);
706
707  handle->blob = NULL;
708
709  rtems_fdt_unlock (fdt);
710
711  return 0;
712}
713
714int
715rtems_fdt_num_mem_rsv (rtems_fdt_handle* handle)
716{
717  if (!handle->blob)
718    return -RTEMS_FDT_ERR_INVALID_HANDLE;
719  return fdt_num_mem_rsv (handle->blob->blob);
720}
721
722int
723rtems_fdt_get_mem_rsv (rtems_fdt_handle* handle,
724                       int               n,
725                       uint64_t*         address,
726                       uint64_t*         size)
727{
728  if (!handle->blob)
729    return -RTEMS_FDT_ERR_INVALID_HANDLE;
730  return fdt_get_mem_rsv (handle->blob->blob, n, address, size);
731}
732
733int
734rtems_fdt_subnode_offset_namelen (rtems_fdt_handle* handle,
735                                  int               parentoffset,
736                                  const char*       name,
737                                  int               namelen)
738{
739  if (!handle->blob)
740    return -RTEMS_FDT_ERR_INVALID_HANDLE;
741  return fdt_subnode_offset_namelen (handle->blob->blob,
742                                     parentoffset,
743                                     name,
744                                     namelen);
745}
746
747int
748rtems_fdt_subnode_offset (rtems_fdt_handle* handle,
749                          int               parentoffset,
750                          const char*       name)
751{
752  char full_name[256];
753  const char *path;
754
755  if (!handle->blob)
756    return -RTEMS_FDT_ERR_INVALID_HANDLE;
757
758  path = rtems_fdt_index_find_name_by_offset(&handle->blob->index, parentoffset);
759  snprintf(full_name, sizeof(full_name), "%s/%s", path, name);
760
761  return rtems_fdt_index_find_by_name(&handle->blob->index, full_name);
762}
763
764int
765rtems_fdt_path_offset (rtems_fdt_handle* handle, const char* path)
766{
767  return rtems_fdt_index_find_by_name(&handle->blob->index, path);
768}
769
770const char*
771rtems_fdt_get_name (rtems_fdt_handle* handle, int nodeoffset, int* length)
772{
773  if (!handle->blob)
774    return NULL;
775
776  const char *name = rtems_fdt_index_find_name_by_offset(&handle->blob->index, nodeoffset);
777  if (name && length)
778  {
779    *length = strlen(name);
780  }
781
782  return name;
783}
784
785const void*
786rtems_fdt_getprop_namelen (rtems_fdt_handle* handle,
787                           int               nodeoffset,
788                           const char*       name,
789                           int               namelen,
790                           int*              length)
791{
792  if (!handle->blob)
793    return NULL;
794  return fdt_getprop_namelen (handle->blob->blob,
795                              nodeoffset,
796                              name,
797                              namelen,
798                              length);
799}
800
801const void*
802rtems_fdt_getprop (rtems_fdt_handle* handle,
803                   int               nodeoffset,
804                   const char*       name,
805                   int*              length)
806{
807  if (!handle->blob)
808    return NULL;
809  return fdt_getprop (handle->blob->blob,
810                      nodeoffset,
811                      name,
812                      length);
813}
814
815uint32_t
816rtems_fdt_get_phandle (rtems_fdt_handle* handle, int nodeoffset)
817{
818  if (!handle->blob)
819    return -RTEMS_FDT_ERR_INVALID_HANDLE;
820  return fdt_get_phandle (handle->blob->blob, nodeoffset);
821}
822
823const char*
824rtems_fdt_get_alias_namelen (rtems_fdt_handle* handle,
825                             const char*       name,
826                             int               namelen)
827{
828  if (!handle->blob)
829    return NULL;
830  return fdt_get_alias_namelen (handle->blob->blob, name, namelen);
831}
832
833const char*
834rtems_fdt_get_alias (rtems_fdt_handle* handle, const char* name)
835{
836  if (!handle->blob)
837    return NULL;
838  return fdt_get_alias (handle->blob->blob, name);
839}
840
841int
842rtems_fdt_get_path (rtems_fdt_handle* handle,
843                    int               nodeoffset,
844                    char*             buf,
845                    int               buflen)
846{
847  if (!handle->blob)
848    return -RTEMS_FDT_ERR_INVALID_HANDLE;
849  return fdt_get_path (handle->blob->blob, nodeoffset, buf, buflen);
850}
851
852int
853rtems_fdt_supernode_atdepth_offset (rtems_fdt_handle* handle,
854                                    int               nodeoffset,
855                                    int               supernodedepth,
856                                    int*              nodedepth)
857{
858  if (!handle->blob)
859    return -RTEMS_FDT_ERR_INVALID_HANDLE;
860  return fdt_supernode_atdepth_offset(handle,
861                                      nodeoffset,
862                                      supernodedepth,
863                                      nodedepth);
864}
865
866int
867rtems_fdt_node_depth (rtems_fdt_handle* handle, int nodeoffset)
868{
869  if (!handle->blob)
870    return -RTEMS_FDT_ERR_INVALID_HANDLE;
871  return fdt_node_depth (handle->blob->blob, nodeoffset);
872}
873
874int
875rtems_fdt_parent_offset (rtems_fdt_handle* handle, int nodeoffset)
876{
877  if (!handle->blob)
878    return -RTEMS_FDT_ERR_INVALID_HANDLE;
879  return fdt_parent_offset (handle->blob->blob, nodeoffset);
880}
881
882int
883rtems_fdt_node_offset_by_prop_value (rtems_fdt_handle* handle,
884                                     int               startoffset,
885                                     const char*       propname,
886                                     const void*       propval,
887                                     int               proplen)
888{
889  if (!handle->blob)
890    return -RTEMS_FDT_ERR_INVALID_HANDLE;
891  return fdt_node_offset_by_prop_value (handle,
892                                        startoffset,
893                                        propname,
894                                        propval,
895                                        proplen);
896}
897
898int
899rtems_fdt_node_offset_by_phandle (rtems_fdt_handle* handle, uint32_t phandle)
900{
901  if (!handle->blob)
902    return -RTEMS_FDT_ERR_INVALID_HANDLE;
903  return fdt_node_offset_by_phandle (handle->blob->blob, phandle);
904}
905
906int
907rtems_fdt_node_check_compatible (rtems_fdt_handle* handle,
908                                 int               nodeoffset,
909                                 const char*       compatible)
910{
911  if (!handle->blob)
912    return -RTEMS_FDT_ERR_INVALID_HANDLE;
913  return fdt_node_check_compatible (handle, nodeoffset, compatible);
914}
915
916int
917rtems_fdt_node_offset_by_compatible (rtems_fdt_handle* handle,
918                                     int               startoffset,
919                                     const char*       compatible)
920{
921  if (!handle->blob)
922    return -RTEMS_FDT_ERR_INVALID_HANDLE;
923  return fdt_node_offset_by_compatible (handle->blob->blob,
924                                        startoffset,
925                                        compatible);
926}
927
928int
929rtems_fdt_next_node (rtems_fdt_handle* handle, int offset, int* depth)
930{
931  if (!handle->blob)
932    return -RTEMS_FDT_ERR_INVALID_HANDLE;
933  return fdt_next_node (handle->blob->blob, offset, depth);
934}
935
936const char*
937rtems_fdt_strerror (int errval)
938{
939  const char* errors[] = {
940    "invalid handle",
941    "no memory",
942    "file not found",
943    "DTB read fail",
944    "blob has references"
945  };
946  if (errval > -RTEMS_FDT_ERR_RTEMS_MIN)
947    return fdt_strerror (errval);
948  if (errval < -RTEMS_FDT_ERR_MAX)
949    return "invalid error code";
950  return errors[(-errval) - RTEMS_FDT_ERR_RTEMS_MIN];
951}
952
953int
954rtems_fdt_prop_value(const char* const path,
955                     const char* const propname,
956                     void*             value,
957                     size_t*           size)
958{
959  rtems_fdt_handle fdt;
960  int              node;
961  const void*      prop;
962  int              length;
963
964  rtems_fdt_init_handle (&fdt);
965
966  node = rtems_fdt_find_path_offset (&fdt, path);
967  if (node < 0)
968    return node;
969
970  prop = rtems_fdt_getprop(&fdt, node, propname, &length);
971  if (length < 0)
972  {
973    rtems_fdt_release_handle (&fdt);
974    return length;
975  }
976
977  if (length > (int) *size)
978  {
979    rtems_fdt_release_handle (&fdt);
980    return RTEMS_FDT_ERR_BADPATH;
981  }
982
983  *size = length;
984
985  memcpy (value, prop, length);
986
987  return 0;
988}
989
990int
991rtems_fdt_prop_map(const char* const path,
992                   const char* const propname,
993                   const char* const names[],
994                   uint32_t*         values,
995                   size_t            count)
996{
997  rtems_fdt_handle fdt;
998  int              node;
999  size_t           item;
1000
1001  rtems_fdt_init_handle (&fdt);
1002
1003  node = rtems_fdt_find_path_offset (&fdt, path);
1004  if (node < 0)
1005    return node;
1006
1007  for (item = 0; item < count; item++)
1008  {
1009    const void*    prop;
1010    const uint8_t* p;
1011    int            length;
1012    int            subnode;
1013
1014    subnode = rtems_fdt_subnode_offset (&fdt, node, names[item]);
1015    if (subnode < 0)
1016    {
1017      rtems_fdt_release_handle (&fdt);
1018      return subnode;
1019    }
1020
1021    prop = rtems_fdt_getprop(&fdt, subnode, propname, &length);
1022    if (length < 0)
1023    {
1024      rtems_fdt_release_handle (&fdt);
1025      return length;
1026    }
1027
1028    if (length != sizeof (uint32_t))
1029    {
1030      rtems_fdt_release_handle (&fdt);
1031      return RTEMS_FDT_ERR_BADPATH;
1032    }
1033
1034    p = prop;
1035
1036    values[item] = ((((uint32_t) p[0]) << 24) |
1037                    (((uint32_t) p[1]) << 16) |
1038                    (((uint32_t) p[2]) << 8)  |
1039                    (uint32_t) p[3]);
1040  }
1041
1042  return 0;
1043}
1044
1045uint32_t
1046rtems_fdt_get_uint32 (const void* prop)
1047{
1048  const uint8_t* p = prop;
1049  uint32_t       value;
1050  value = ((((uint32_t) p[0]) << 24) |
1051           (((uint32_t) p[1]) << 16) |
1052           (((uint32_t) p[2]) << 8)  |
1053           (uint32_t) p[3]);
1054  return value;
1055}
1056
1057int
1058rtems_fdt_get_value (const char* path,
1059                     const char* property,
1060                     size_t      size,
1061                     uint32_t*   value)
1062{
1063  rtems_fdt_handle fdt;
1064  const void*      prop;
1065  int              node;
1066  int              length;
1067
1068  rtems_fdt_init_handle (&fdt);
1069
1070  node = rtems_fdt_find_path_offset (&fdt, path);
1071  if (node < 0)
1072  {
1073    rtems_fdt_release_handle (&fdt);
1074    return node;
1075  }
1076
1077  prop = rtems_fdt_getprop(&fdt, node, property, &length);
1078  if (length < 0)
1079  {
1080    rtems_fdt_release_handle (&fdt);
1081    return length;
1082  }
1083
1084  if (length == sizeof (uint32_t))
1085    *value = rtems_fdt_get_uint32 (prop);
1086  else
1087    *value = 0;
1088
1089  rtems_fdt_release_handle (&fdt);
1090
1091  return 0;
1092}
1093
1094/**
1095 * Get the number of entries in an FDT handle.
1096 */
1097int
1098rtems_fdt_num_entries(rtems_fdt_handle* handle)
1099{
1100  return handle->blob->index.num_entries;
1101}
1102
1103/**
1104 * Get the numbered entry name. Note that the id isn't the same as
1105 * the offset - it's numbered 0, 1, 2 ... num_entries-1
1106 */
1107const char *
1108rtems_fdt_entry_name(rtems_fdt_handle* handle, int id)
1109{
1110  return handle->blob->index.entries[id].name;
1111}
1112
1113/**
1114 * Get the numbered entry offset. Note that the id isn't the same as
1115 * the offset - it's numbered 0, 1, 2 ... num_entries-1
1116 */
1117int
1118rtems_fdt_entry_offset(rtems_fdt_handle* handle, int id)
1119{
1120  return handle->blob->index.entries[id].offset;
1121}
Note: See TracBrowser for help on using the repository browser.