Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@rtems.org>
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #include <fcntl.h>
0029 #include <stdio.h>
0030 #include <sys/stat.h>
0031 #include <sys/types.h>
0032 
0033 #include <libfdt.h>
0034 #include <zlib.h>
0035 
0036 #include <rtems/malloc.h>
0037 #include <rtems/rtems-fdt.h>
0038 #include <rtems/thread.h>
0039 
0040 /**
0041  * An index for quick access to the FDT by name or offset.
0042  */
0043 
0044 typedef struct
0045 {
0046   const char* name;         /**< The full path of the FDT item. */
0047   int         offset;       /**< The offset of the item in the FDT blob. */
0048 } rtems_fdt_index_entry;
0049 
0050 typedef struct
0051 {
0052   int                    num_entries;    /**< The number of entries in this index. */
0053   rtems_fdt_index_entry* entries;        /**< An ordered set of entries which we
0054                                           *  can binary search. */
0055   char*                  names;          /**< Storage allocated for all the path names. */
0056 } rtems_fdt_index;
0057 
0058 
0059 /**
0060  * A blob descriptor.
0061  */
0062 struct rtems_fdt_blob
0063 {
0064   rtems_chain_node node;        /**< The node's link in the chain. */
0065   const void*      blob;        /**< The FDT blob. */
0066   const char*      name;        /**< The name of the blob. */
0067   int              refs;        /**< The number of active references of the blob. */
0068   rtems_fdt_index  index;       /**< The index used for quick access to items in the blob. */
0069 };
0070 
0071 /**
0072  * The global FDT data. This structure is allocated on the heap when the first
0073  * call to load a FDT blob is made and released when all blobs have been
0074  * unloaded..
0075  */
0076 typedef struct
0077 {
0078   rtems_mutex         lock;     /**< The FDT lock id */
0079   rtems_chain_control blobs;    /**< List if loaded blobs. */
0080   const char*         paths;    /**< Search paths for blobs. */
0081 } rtems_fdt_data;
0082 
0083 static void
0084 rtems_fdt_unlock (rtems_fdt_data *fdt)
0085 {
0086   rtems_mutex_unlock (&fdt->lock);
0087 }
0088 
0089 static rtems_fdt_data*
0090 rtems_fdt_lock (void)
0091 {
0092   static rtems_fdt_data fdt_instance = {
0093     .lock = RTEMS_MUTEX_INITIALIZER ("FDT"),
0094     .blobs = RTEMS_CHAIN_INITIALIZER_EMPTY (fdt_instance.blobs)
0095   };
0096   rtems_fdt_data *fdt = &fdt_instance;
0097 
0098   rtems_mutex_lock (&fdt->lock);
0099   return fdt;
0100 }
0101 
0102 /**
0103  * Compare node paths
0104  */
0105 static int rtems_fdt_node_path_compare(const char* n1,
0106                                        const char* n2,
0107                                        size_t      namelen)
0108 {
0109   if (namelen == 0)
0110   {
0111     return strcmp(n1, n2);
0112   }
0113   return strncmp(n1, n2, namelen);
0114 }
0115 
0116 /**
0117  * Compare index entries
0118  */
0119 static int rtems_fdt_index_compare(const void* a, const void* b)
0120 {
0121   const rtems_fdt_index_entry* e1 = (const rtems_fdt_index_entry*) a;
0122   const rtems_fdt_index_entry* e2 = (const rtems_fdt_index_entry*) b;
0123   return rtems_fdt_node_path_compare(e1->name, e2->name, 0);
0124 }
0125 
0126 /**
0127  * Create an index based on the contents of an FDT blob.
0128  */
0129 static int
0130 rtems_fdt_init_index (rtems_fdt_handle* fdt, rtems_fdt_blob* blob)
0131 {
0132   rtems_fdt_index_entry* entries = NULL;
0133   int                    num_entries = 0;
0134   int                    entry = 0;
0135   size_t                 total_name_memory = 0;
0136   char                   node_path[256];
0137   int                    depth_path[32];
0138   int                    start_offset = 0;
0139   int                    start_depth = 0;
0140   int                    offset = 0;
0141   int                    depth = 0;
0142   char*                  names = NULL;
0143   char*                  names_pos = NULL;
0144 
0145   /*
0146    * Count the number of entries in the blob first.
0147    */
0148   memset(&node_path, 0, sizeof(node_path));
0149   strcpy(node_path, "/");
0150   depth_path[0] = strlen(node_path);
0151 
0152   start_offset = fdt_path_offset(fdt->blob->blob, node_path);
0153   if (start_offset < 0)
0154   {
0155     return start_offset;
0156   }
0157 
0158   start_offset = fdt_next_node(fdt->blob->blob, start_offset, &start_depth);
0159   if (start_offset < 0)
0160   {
0161     return start_offset;
0162   }
0163 
0164   offset = start_offset;
0165   depth = start_depth;
0166 
0167   while (depth > 0)
0168   {
0169     /*
0170      * Construct the node path name.
0171      */
0172     int         namelen = 0;
0173     const char* name = fdt_get_name(blob->blob, offset, &namelen);
0174     strncpy(&node_path[depth_path[depth-1]],
0175             name,
0176             sizeof(node_path) - depth_path[depth-1] - 1);
0177 
0178     total_name_memory += strlen(node_path) + 1;
0179     num_entries++;
0180 
0181     if (depth_path[depth-1] + namelen + 2 <= (int)sizeof(node_path))
0182     {
0183       strcpy(&node_path[depth_path[depth-1] + namelen], "/");
0184     }
0185 
0186     depth_path[depth] = depth_path[depth-1] + namelen + 1;
0187 
0188     /*
0189      * Get the next node.
0190      */
0191     offset = fdt_next_node(fdt->blob->blob, offset, &depth);
0192     if (offset < 0)
0193     {
0194       return offset;
0195     }
0196   }
0197 
0198   /*
0199    * Create the index.
0200    */
0201   entries = rtems_calloc(num_entries, sizeof(rtems_fdt_index_entry));
0202   if (!entries)
0203   {
0204     return -RTEMS_FDT_ERR_NO_MEMORY;
0205   }
0206 
0207   names = rtems_calloc(1, total_name_memory);
0208   if (!names)
0209   {
0210     free(entries);
0211     return -RTEMS_FDT_ERR_NO_MEMORY;
0212   }
0213 
0214   /*
0215    * Populate the index.
0216    */
0217   offset = start_offset;
0218   depth = start_depth;
0219   entry = 0;
0220   names_pos = names;
0221 
0222   while (depth > 0)
0223   {
0224     /*
0225      * Record this node in an entry.
0226      */
0227     int         namelen = 0;
0228     const char* name = fdt_get_name(blob->blob, offset, &namelen);
0229     strncpy(&node_path[depth_path[depth-1]],
0230             name,
0231             sizeof(node_path) - depth_path[depth-1] - 1);
0232     strcpy(names_pos, node_path);
0233 
0234     entries[entry].name = names_pos;
0235     entries[entry].offset = offset;
0236 
0237     names_pos += strlen(node_path) + 1;
0238     entry++;
0239 
0240     if (depth_path[depth-1] + namelen + 2 <= (int)sizeof(node_path))
0241     {
0242       strcpy(&node_path[depth_path[depth-1] + namelen], "/");
0243     }
0244 
0245     depth_path[depth] = depth_path[depth-1] + namelen + 1;
0246 
0247     /*
0248      * Get the next node.
0249      */
0250     offset = fdt_next_node(fdt->blob->blob, offset, &depth);
0251     if (offset < 0)
0252     {
0253       free(entries);
0254       free(names);
0255       return offset;
0256     }
0257   }
0258 
0259   if (num_entries != 0)
0260   {
0261     qsort(entries,
0262           num_entries,
0263           sizeof(rtems_fdt_index_entry),
0264           rtems_fdt_index_compare);
0265   }
0266 
0267   fdt->blob->index.entries = entries;
0268   fdt->blob->index.num_entries = num_entries;
0269   fdt->blob->index.names = names;
0270 
0271   return 0;
0272 }
0273 
0274 /**
0275  * Release the contents of the index, freeing memory.
0276  */
0277 static void
0278 rtems_fdt_release_index (rtems_fdt_index* index)
0279 {
0280   if (index->entries)
0281   {
0282     free(index->entries);
0283     free(index->names);
0284 
0285     index->num_entries = 0;
0286     index->entries = NULL;
0287     index->names = NULL;
0288   }
0289 }
0290 
0291 /**
0292  * For a given FDT path, find the corresponding offset.
0293  * Returns -1 if not found;
0294  */
0295 static int
0296 rtems_fdt_index_find_by_name(rtems_fdt_index* index,
0297                              const char*      name)
0298 {
0299   int         min = 0;
0300   int         max = index->num_entries;
0301   /*
0302    * Handle trailing slash case.
0303    */
0304   size_t namelen = strlen(name);
0305   if (namelen > 0 && name[namelen-1] == '/')
0306   {
0307     namelen--;
0308   }
0309 
0310   /* Binary search for the name. */
0311   while (min < max)
0312   {
0313     int middle = (min + max) / 2;
0314     int cmp = rtems_fdt_node_path_compare(name,
0315                                           index->entries[middle].name,
0316                                           namelen);
0317     if (cmp == 0)
0318     {
0319       /* 'namelen' characters are equal but 'index->entries[middle].name' */
0320       /* could have additional characters. */
0321       if (index->entries[middle].name[namelen] == '\0')
0322       {
0323         /* Found it. */
0324         return index->entries[middle].offset;
0325       }
0326       else
0327       {
0328          /* 'index->entries[middle].name' is longer than 'name'. */
0329          cmp = -1;
0330       }
0331     }
0332     if (cmp < 0)
0333     {
0334       /* Look lower than here. */
0335       max = middle;
0336     }
0337     else
0338     {
0339       /* Look higher than here. */
0340       min = middle + 1;
0341     }
0342  }
0343 
0344   /* Didn't find it. */
0345   return -FDT_ERR_NOTFOUND;
0346 }
0347 
0348 /**
0349  * For a given FDT offset, find the corresponding path name.
0350  */
0351 static const char *
0352 rtems_fdt_index_find_name_by_offset(rtems_fdt_index* index,
0353                                     int              offset)
0354 {
0355   int min = 0;
0356   int max = index->num_entries;
0357 
0358   /*
0359    * Binary search for the offset.
0360    */
0361   while (min < max)
0362   {
0363     int middle = (min + max) / 2;
0364     if (offset < index->entries[middle].offset)
0365     {
0366       /* Look lower than here. */
0367       max = middle;
0368     }
0369     else if (offset > index->entries[middle].offset)
0370     {
0371       /* Look higher than here. */
0372       min = middle + 1;
0373     }
0374     else
0375     {
0376       /* Found it. */
0377       return index->entries[middle].name;
0378     }
0379   }
0380 
0381   /* Didn't find it. */
0382   return NULL;
0383 }
0384 
0385 void
0386 rtems_fdt_init_handle (rtems_fdt_handle* handle)
0387 {
0388   if (handle)
0389     handle->blob = NULL;
0390 }
0391 
0392 void
0393 rtems_fdt_dup_handle (rtems_fdt_handle* from, rtems_fdt_handle* to)
0394 {
0395   if (from && to)
0396   {
0397     rtems_fdt_data* fdt;
0398 
0399     fdt = rtems_fdt_lock ();
0400     to->blob = from->blob;
0401     ++to->blob->refs;
0402     rtems_fdt_unlock (fdt);
0403   }
0404 }
0405 
0406 void
0407 rtems_fdt_release_handle (rtems_fdt_handle* handle)
0408 {
0409   if (handle && handle->blob)
0410   {
0411     rtems_fdt_data*   fdt;
0412     rtems_chain_node* node;
0413 
0414     fdt = rtems_fdt_lock ();
0415 
0416     node = rtems_chain_first (&fdt->blobs);
0417 
0418     while (!rtems_chain_is_tail (&fdt->blobs, node))
0419     {
0420       rtems_fdt_blob* blob = (rtems_fdt_blob*) node;
0421       if (handle->blob == blob)
0422       {
0423         if (blob->refs)
0424           --blob->refs;
0425         break;
0426       }
0427       node = rtems_chain_next (node);
0428     }
0429 
0430     rtems_fdt_unlock (fdt);
0431 
0432     handle->blob = NULL;
0433   }
0434 }
0435 
0436 bool
0437 rtems_fdt_valid_handle (const rtems_fdt_handle* handle)
0438 {
0439   if (handle && handle->blob)
0440   {
0441     rtems_fdt_data*   fdt;
0442     rtems_chain_node* node;
0443 
0444     fdt = rtems_fdt_lock ();
0445 
0446     node = rtems_chain_first (&fdt->blobs);
0447 
0448     while (!rtems_chain_is_tail (&fdt->blobs, node))
0449     {
0450       rtems_fdt_blob* blob = (rtems_fdt_blob*) node;
0451       if (handle->blob == blob)
0452       {
0453         rtems_fdt_unlock (fdt);
0454         return true;
0455       }
0456       node = rtems_chain_next (node);
0457     }
0458 
0459     rtems_fdt_unlock (fdt);
0460   }
0461 
0462   return false;
0463 }
0464 
0465 int
0466 rtems_fdt_find_path_offset (rtems_fdt_handle* handle, const char* path)
0467 {
0468   rtems_fdt_data*   fdt;
0469   rtems_chain_node* node;
0470 
0471   rtems_fdt_release_handle (handle);
0472 
0473   fdt = rtems_fdt_lock ();
0474 
0475   node = rtems_chain_first (&fdt->blobs);
0476 
0477   while (!rtems_chain_is_tail (&fdt->blobs, node))
0478   {
0479     rtems_fdt_handle temp_handle;
0480     int              offset;
0481 
0482     temp_handle.blob = (rtems_fdt_blob*) node;
0483 
0484     offset = rtems_fdt_path_offset (&temp_handle, path);
0485 
0486     if (offset >= 0)
0487     {
0488       ++temp_handle.blob->refs;
0489       handle->blob = temp_handle.blob;
0490       rtems_fdt_unlock (fdt);
0491       return offset;
0492     }
0493 
0494     node = rtems_chain_next (node);
0495   }
0496 
0497   rtems_fdt_unlock (fdt);
0498 
0499   return -FDT_ERR_NOTFOUND;
0500 }
0501 
0502 int
0503 rtems_fdt_load (const char* filename, rtems_fdt_handle* handle)
0504 {
0505   rtems_fdt_data* fdt;
0506   rtems_fdt_blob* blob;
0507   size_t          bsize;
0508   int             bf;
0509   ssize_t         r;
0510   size_t          name_len;
0511   int             fe;
0512   struct stat     sb;
0513   uint8_t         gzip_id[2];
0514   uint8_t*        cdata;
0515   size_t          size;
0516 
0517   rtems_fdt_release_handle (handle);
0518 
0519   if (stat (filename, &sb) < 0)
0520   {
0521     return -RTEMS_FDT_ERR_NOT_FOUND;
0522   }
0523 
0524   bf = open(filename, O_RDONLY);
0525   if (bf < 0)
0526   {
0527     return -RTEMS_FDT_ERR_READ_FAIL;
0528   }
0529 
0530   r = read(bf, &gzip_id, sizeof(gzip_id));
0531   if (r < 0)
0532   {
0533     close(bf);
0534     return -RTEMS_FDT_ERR_READ_FAIL;
0535   }
0536 
0537   if ((gzip_id[0] == 0x1f) && (gzip_id[1] == 0x8b))
0538   {
0539     size_t offset;
0540 
0541     cdata = rtems_malloc(sb.st_size);
0542     if (!cdata)
0543     {
0544       close (bf);
0545       return -RTEMS_FDT_ERR_NO_MEMORY;
0546     }
0547 
0548     if (lseek(bf, 0, SEEK_SET) < 0)
0549     {
0550       free(cdata);
0551       close(bf);
0552       return -RTEMS_FDT_ERR_READ_FAIL;
0553     }
0554 
0555     size = sb.st_size;
0556     offset = 0;
0557     while (size)
0558     {
0559       r = read(bf, cdata + offset, size);
0560       if (r < 0)
0561       {
0562         free(cdata);
0563         close(bf);
0564         return -RTEMS_FDT_ERR_READ_FAIL;
0565       }
0566       size -= r;
0567       offset += r;
0568     }
0569 
0570     offset = sb.st_size - 4;
0571     bsize = ((cdata[offset + 3] << 24) | (cdata[offset + 2] << 16) |
0572              (cdata[offset + 1] << 8) | cdata[offset + 0]);
0573   }
0574   else
0575   {
0576     cdata = NULL;
0577     bsize = sb.st_size;
0578   }
0579 
0580   name_len = strlen (filename) + 1;
0581 
0582   blob = rtems_malloc(sizeof (rtems_fdt_blob) + name_len + bsize);
0583   if (!blob)
0584   {
0585     free(cdata);
0586     close (bf);
0587     return -RTEMS_FDT_ERR_NO_MEMORY;
0588   }
0589 
0590   blob->name = (const char*) (blob + 1);
0591   blob->blob = blob->name + name_len + 1;
0592 
0593   strcpy ((char*) blob->name, filename);
0594 
0595   if ((gzip_id[0] == 0x1f) && (gzip_id[1] == 0x8b))
0596   {
0597     z_stream stream;
0598     int      err;
0599     stream.next_in = (Bytef*) cdata;
0600     stream.avail_in = (uInt) sb.st_size;
0601     stream.next_out = (void*) (blob->name + name_len + 1);
0602     stream.avail_out = (uInt) bsize;
0603     stream.zalloc = (alloc_func) 0;
0604     stream.zfree = (free_func) 0;
0605     err = inflateInit(&stream);
0606     if (err == Z_OK)
0607       err = inflateReset2(&stream, 31);
0608     if (err == Z_OK)
0609       err = inflate(&stream, Z_FINISH);
0610     if ((err == Z_OK) || (err == Z_STREAM_END))
0611       err = inflateEnd(&stream);
0612     if ((err != Z_OK) || (bsize != stream.total_out))
0613     {
0614       free (blob);
0615       free(cdata);
0616       close (bf);
0617       return -RTEMS_FDT_ERR_READ_FAIL;
0618     }
0619     free(cdata);
0620     cdata = NULL;
0621   }
0622   else
0623   {
0624     char* buf = (char*) blob->name + name_len + 1;
0625     size = bsize;
0626     while (size)
0627     {
0628       r = read (bf, buf, size);
0629       if (r < 0)
0630       {
0631         free (blob);
0632         close (bf);
0633         return -RTEMS_FDT_ERR_READ_FAIL;
0634       }
0635       size -= r;
0636       buf += r;
0637     }
0638   }
0639 
0640   fe = fdt_check_header(blob->blob);
0641   if (fe < 0)
0642   {
0643     free (blob);
0644     close (bf);
0645     return fe;
0646   }
0647 
0648   fdt = rtems_fdt_lock ();
0649 
0650   rtems_chain_append_unprotected (&fdt->blobs, &blob->node);
0651 
0652   blob->refs = 1;
0653 
0654   rtems_fdt_unlock (fdt);
0655 
0656   handle->blob = blob;
0657 
0658   fe = rtems_fdt_init_index(handle, blob);
0659   if (fe < 0)
0660   {
0661     free (blob);
0662     close (bf);
0663     return fe;
0664   }
0665 
0666   close (bf);
0667   return 0;
0668 }
0669 
0670 int
0671 rtems_fdt_register (const void* dtb, rtems_fdt_handle* handle)
0672 {
0673   rtems_fdt_data* fdt;
0674   rtems_fdt_blob* blob;
0675   int             fe;
0676 
0677   rtems_fdt_release_handle (handle);
0678 
0679   fe = fdt_check_header(dtb);
0680   if (fe < 0)
0681   {
0682     return fe;
0683   }
0684 
0685   blob = rtems_malloc(sizeof (rtems_fdt_blob));
0686   if (!blob)
0687   {
0688     return -RTEMS_FDT_ERR_NO_MEMORY;
0689   }
0690 
0691   blob->blob = dtb;
0692   blob->name = NULL;
0693   rtems_chain_initialize_node(&blob->node);
0694 
0695   fdt = rtems_fdt_lock ();
0696 
0697   rtems_chain_append_unprotected (&fdt->blobs, &blob->node);
0698 
0699   blob->refs = 1;
0700 
0701   rtems_fdt_unlock (fdt);
0702 
0703   handle->blob = blob;
0704 
0705   fe = rtems_fdt_init_index(handle, blob);
0706   if (fe < 0)
0707   {
0708     free(blob);
0709     return -RTEMS_FDT_ERR_NO_MEMORY;
0710   }
0711 
0712   return 0;
0713 }
0714 
0715 int
0716 rtems_fdt_unload (rtems_fdt_handle* handle)
0717 {
0718   rtems_fdt_data* fdt;
0719 
0720   fdt = rtems_fdt_lock ();
0721 
0722   if (!rtems_fdt_valid_handle (handle))
0723   {
0724     rtems_fdt_unlock (fdt);
0725     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0726   }
0727 
0728   if (handle->blob->refs > 1)
0729   {
0730     rtems_fdt_unlock (fdt);
0731     return -RTEMS_FDT_ERR_REFERENCED;
0732   }
0733 
0734   rtems_chain_extract_unprotected (&handle->blob->node);
0735 
0736   rtems_fdt_release_index(&handle->blob->index);
0737 
0738   free (handle->blob);
0739 
0740   handle->blob = NULL;
0741 
0742   rtems_fdt_unlock (fdt);
0743 
0744   return 0;
0745 }
0746 
0747 int
0748 rtems_fdt_num_mem_rsv (rtems_fdt_handle* handle)
0749 {
0750   if (!handle->blob)
0751     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0752   return fdt_num_mem_rsv (handle->blob->blob);
0753 }
0754 
0755 int
0756 rtems_fdt_get_mem_rsv (rtems_fdt_handle* handle,
0757                        int               n,
0758                        uint64_t*         address,
0759                        uint64_t*         size)
0760 {
0761   if (!handle->blob)
0762     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0763   return fdt_get_mem_rsv (handle->blob->blob, n, address, size);
0764 }
0765 
0766 int
0767 rtems_fdt_subnode_offset_namelen (rtems_fdt_handle* handle,
0768                                   int               parentoffset,
0769                                   const char*       name,
0770                                   int               namelen)
0771 {
0772   if (!handle->blob)
0773     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0774   return fdt_subnode_offset_namelen (handle->blob->blob,
0775                                      parentoffset,
0776                                      name,
0777                                      namelen);
0778 }
0779 
0780 int
0781 rtems_fdt_subnode_offset (rtems_fdt_handle* handle,
0782                           int               parentoffset,
0783                           const char*       name)
0784 {
0785   char full_name[256];
0786   const char *path;
0787 
0788   if (!handle->blob)
0789     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0790 
0791   path = rtems_fdt_index_find_name_by_offset(&handle->blob->index, parentoffset);
0792   snprintf(full_name, sizeof(full_name), "%s/%s", path, name);
0793 
0794   return rtems_fdt_index_find_by_name(&handle->blob->index, full_name);
0795 }
0796 
0797 int
0798 rtems_fdt_path_offset (rtems_fdt_handle* handle, const char* path)
0799 {
0800   return rtems_fdt_index_find_by_name(&handle->blob->index, path);
0801 }
0802 
0803 const char*
0804 rtems_fdt_get_name (rtems_fdt_handle* handle, int nodeoffset, int* length)
0805 {
0806   if (!handle->blob)
0807     return NULL;
0808 
0809   const char *name = rtems_fdt_index_find_name_by_offset(&handle->blob->index, nodeoffset);
0810   if (name && length)
0811   {
0812     *length = strlen(name);
0813   }
0814 
0815   return name;
0816 }
0817 
0818 int
0819 rtems_fdt_first_prop_offset(rtems_fdt_handle* handle, int nodeoffset)
0820 {
0821   return fdt_first_property_offset(handle->blob->blob, nodeoffset);
0822 }
0823 
0824 int
0825 rtems_fdt_next_prop_offset(rtems_fdt_handle* handle, int propoffset)
0826 {
0827   return fdt_next_property_offset(handle->blob->blob, propoffset);
0828 }
0829 
0830 const void*
0831 rtems_fdt_getprop_by_offset(rtems_fdt_handle* handle,
0832                             int               propoffset,
0833                             const char**      name,
0834                             int*              length)
0835 {
0836   return fdt_getprop_by_offset(handle->blob->blob, propoffset, name, length);
0837 }
0838 
0839 const void*
0840 rtems_fdt_getprop_namelen (rtems_fdt_handle* handle,
0841                            int               nodeoffset,
0842                            const char*       name,
0843                            int               namelen,
0844                            int*              length)
0845 {
0846   if (!handle->blob)
0847     return NULL;
0848   return fdt_getprop_namelen (handle->blob->blob,
0849                               nodeoffset,
0850                               name,
0851                               namelen,
0852                               length);
0853 }
0854 
0855 const void*
0856 rtems_fdt_getprop (rtems_fdt_handle* handle,
0857                    int               nodeoffset,
0858                    const char*       name,
0859                    int*              length)
0860 {
0861   if (!handle->blob)
0862     return NULL;
0863   return fdt_getprop (handle->blob->blob,
0864                       nodeoffset,
0865                       name,
0866                       length);
0867 }
0868 
0869 uint32_t
0870 rtems_fdt_get_phandle (rtems_fdt_handle* handle, int nodeoffset)
0871 {
0872   if (!handle->blob)
0873     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0874   return fdt_get_phandle (handle->blob->blob, nodeoffset);
0875 }
0876 
0877 const char*
0878 rtems_fdt_get_alias_namelen (rtems_fdt_handle* handle,
0879                              const char*       name,
0880                              int               namelen)
0881 {
0882   if (!handle->blob)
0883     return NULL;
0884   return fdt_get_alias_namelen (handle->blob->blob, name, namelen);
0885 }
0886 
0887 const char*
0888 rtems_fdt_get_alias (rtems_fdt_handle* handle, const char* name)
0889 {
0890   if (!handle->blob)
0891     return NULL;
0892   return fdt_get_alias (handle->blob->blob, name);
0893 }
0894 
0895 int
0896 rtems_fdt_get_path (rtems_fdt_handle* handle,
0897                     int               nodeoffset,
0898                     char*             buf,
0899                     int               buflen)
0900 {
0901   if (!handle->blob)
0902     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0903   return fdt_get_path (handle->blob->blob, nodeoffset, buf, buflen);
0904 }
0905 
0906 int
0907 rtems_fdt_supernode_atdepth_offset (rtems_fdt_handle* handle,
0908                                     int               nodeoffset,
0909                                     int               supernodedepth,
0910                                     int*              nodedepth)
0911 {
0912   if (!handle->blob)
0913     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0914   return fdt_supernode_atdepth_offset(handle,
0915                                       nodeoffset,
0916                                       supernodedepth,
0917                                       nodedepth);
0918 }
0919 
0920 int
0921 rtems_fdt_node_depth (rtems_fdt_handle* handle, int nodeoffset)
0922 {
0923   if (!handle->blob)
0924     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0925   return fdt_node_depth (handle->blob->blob, nodeoffset);
0926 }
0927 
0928 int
0929 rtems_fdt_parent_offset (rtems_fdt_handle* handle, int nodeoffset)
0930 {
0931   if (!handle->blob)
0932     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0933   return fdt_parent_offset (handle->blob->blob, nodeoffset);
0934 }
0935 
0936 int
0937 rtems_fdt_node_offset_by_prop_value (rtems_fdt_handle* handle,
0938                                      int               startoffset,
0939                                      const char*       propname,
0940                                      const void*       propval,
0941                                      int               proplen)
0942 {
0943   if (!handle->blob)
0944     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0945   return fdt_node_offset_by_prop_value (handle,
0946                                         startoffset,
0947                                         propname,
0948                                         propval,
0949                                         proplen);
0950 }
0951 
0952 int
0953 rtems_fdt_node_offset_by_phandle (rtems_fdt_handle* handle, uint32_t phandle)
0954 {
0955   if (!handle->blob)
0956     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0957   return fdt_node_offset_by_phandle (handle->blob->blob, phandle);
0958 }
0959 
0960 int
0961 rtems_fdt_node_check_compatible (rtems_fdt_handle* handle,
0962                                  int               nodeoffset,
0963                                  const char*       compatible)
0964 {
0965   if (!handle->blob)
0966     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0967   return fdt_node_check_compatible (handle, nodeoffset, compatible);
0968 }
0969 
0970 int
0971 rtems_fdt_node_offset_by_compatible (rtems_fdt_handle* handle,
0972                                      int               startoffset,
0973                                      const char*       compatible)
0974 {
0975   if (!handle->blob)
0976     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0977   return fdt_node_offset_by_compatible (handle->blob->blob,
0978                                         startoffset,
0979                                         compatible);
0980 }
0981 
0982 int
0983 rtems_fdt_next_node (rtems_fdt_handle* handle, int offset, int* depth)
0984 {
0985   if (!handle->blob)
0986     return -RTEMS_FDT_ERR_INVALID_HANDLE;
0987   return fdt_next_node (handle->blob->blob, offset, depth);
0988 }
0989 
0990 const char*
0991 rtems_fdt_strerror (int errval)
0992 {
0993   const char* errors[] = {
0994     "invalid handle",
0995     "no memory",
0996     "file not found",
0997     "DTB read fail",
0998     "blob has references",
0999     "bad length"
1000   };
1001   if (errval > -RTEMS_FDT_ERR_RTEMS_MIN)
1002     return fdt_strerror (errval);
1003   if (errval < -RTEMS_FDT_ERR_MAX)
1004     return "invalid error code";
1005   return errors[(-errval) - RTEMS_FDT_ERR_RTEMS_MIN];
1006 }
1007 
1008 int
1009 rtems_fdt_prop_value(const char* const path,
1010                      const char* const propname,
1011                      void*             value,
1012                      size_t*           size)
1013 {
1014   rtems_fdt_handle fdt;
1015   int              node;
1016   const void*      prop;
1017   int              length;
1018 
1019   rtems_fdt_init_handle (&fdt);
1020 
1021   node = rtems_fdt_find_path_offset (&fdt, path);
1022   if (node < 0)
1023     return node;
1024 
1025   prop = rtems_fdt_getprop(&fdt, node, propname, &length);
1026   if (length < 0)
1027   {
1028     rtems_fdt_release_handle (&fdt);
1029     return length;
1030   }
1031 
1032   if (length > (int) *size)
1033   {
1034     rtems_fdt_release_handle (&fdt);
1035     return -RTEMS_FDT_ERR_BADPATH;
1036   }
1037 
1038   *size = length;
1039 
1040   memcpy (value, prop, length);
1041 
1042   return 0;
1043 }
1044 
1045 bool
1046 rtems_fdt_get_parent_prop_value(rtems_fdt_handle* handle,
1047                                 int               nodeoffset,
1048                                 const char*       name,
1049                                 uint32_t*         value)
1050 {
1051   const void* prop;
1052   int plen = 0;
1053   int node = rtems_fdt_parent_offset(handle, nodeoffset);
1054   if (node < 0)
1055     return false;
1056   prop = rtems_fdt_getprop(handle, node, name, &plen);
1057   if (plen < 0)
1058     return false;
1059   *value = rtems_fdt_get_uint32(prop);
1060   return true;
1061 }
1062 
1063 int
1064 rtems_fdt_prop_map(const char* const path,
1065                    const char* const propname,
1066                    const char* const names[],
1067                    uintptr_t*        values,
1068                    size_t            count)
1069 {
1070   rtems_fdt_handle fdt;
1071   int              node;
1072   size_t           item;
1073 
1074   rtems_fdt_init_handle (&fdt);
1075 
1076   node = rtems_fdt_find_path_offset (&fdt, path);
1077   if (node < 0)
1078     return node;
1079 
1080   for (item = 0; item < count; item++)
1081   {
1082     const void* prop;
1083     int         length;
1084     int         subnode;
1085 
1086     subnode = rtems_fdt_subnode_offset (&fdt, node, names[item]);
1087     if (subnode < 0)
1088     {
1089       rtems_fdt_release_handle (&fdt);
1090       return subnode;
1091     }
1092 
1093     prop = rtems_fdt_getprop(&fdt, subnode, propname, &length);
1094     if (length < 0)
1095     {
1096       rtems_fdt_release_handle (&fdt);
1097       return length;
1098     }
1099 
1100     if (length > sizeof (uintptr_t))
1101     {
1102       rtems_fdt_release_handle (&fdt);
1103       return -RTEMS_FDT_ERR_BADPATH;
1104     }
1105 
1106     values[item] = rtems_fdt_get_offset_len_uintptr(prop, 0, length);
1107   }
1108 
1109   return 0;
1110 }
1111 
1112 uintptr_t
1113 rtems_fdt_get_offset_len_uintptr (const void* prop, int offset, int len)
1114 {
1115   const uint8_t* p = prop;
1116   uintptr_t      value = 0;
1117   int            b;
1118   if (len <= sizeof(uintptr_t)) {
1119     for (b = 0; b < len; ++b) {
1120       value = (value << 8) | (uintptr_t) p[offset++];
1121     }
1122   }
1123   return value;
1124 }
1125 
1126 
1127 uint32_t
1128 rtems_fdt_get_offset_uint32 (const void* prop, int offset)
1129 {
1130   const uint8_t* p = prop;
1131   uint32_t       value;
1132   offset *= sizeof(uint32_t);
1133   value = ((((uint32_t) p[offset + 0]) << 24) |
1134            (((uint32_t) p[offset + 1]) << 16) |
1135            (((uint32_t) p[offset + 2]) << 8)  |
1136            (uint32_t) p[offset + 3]);
1137   return value;
1138 }
1139 
1140 uint32_t
1141 rtems_fdt_get_uint32 (const void* prop)
1142 {
1143   return rtems_fdt_get_offset_uint32(prop, 0);
1144 }
1145 
1146 uint64_t
1147 rtems_fdt_get_offset_uint64 (const void* prop, int offset)
1148 {
1149   uint64_t value = rtems_fdt_get_offset_uint32(prop, offset);
1150   value = (value << 16) << 16;
1151   return value | rtems_fdt_get_offset_uint32(prop, offset + 1);
1152 }
1153 
1154 uint64_t
1155 rtems_fdt_get_uint64 (const void* prop)
1156 {
1157   return rtems_fdt_get_offset_uint64(prop, 0);
1158 }
1159 
1160 uintptr_t
1161 rtems_fdt_get_uintptr (const void* prop)
1162 {
1163   return rtems_fdt_get_offset_uintptr(prop, 0);
1164 }
1165 
1166 uintptr_t
1167 rtems_fdt_get_offset_uintptr (const void* prop, int offset)
1168 {
1169   if (sizeof(intptr_t) == sizeof(uint32_t))
1170     return rtems_fdt_get_offset_uint32(prop, offset);
1171   return rtems_fdt_get_offset_uint64(prop, offset);
1172 }
1173 
1174 int
1175 rtems_fdt_get_value (const char* path,
1176                      const char* property,
1177                      size_t      size,
1178                      uintptr_t*  value)
1179 {
1180   rtems_fdt_handle fdt;
1181   const void*      prop;
1182   int              node;
1183   int              length;
1184 
1185   rtems_fdt_init_handle (&fdt);
1186 
1187   node = rtems_fdt_find_path_offset (&fdt, path);
1188   if (node < 0)
1189   {
1190     rtems_fdt_release_handle (&fdt);
1191     return node;
1192   }
1193 
1194   prop = rtems_fdt_getprop(&fdt, node, property, &length);
1195   if (length < 0)
1196   {
1197     rtems_fdt_release_handle (&fdt);
1198     return length;
1199   }
1200 
1201   if (length == sizeof (uintptr_t))
1202     *value = rtems_fdt_get_uintptr (prop);
1203   else
1204     *value = 0;
1205 
1206   rtems_fdt_release_handle (&fdt);
1207 
1208   return 0;
1209 }
1210 
1211 /**
1212  * Get the number of entries in an FDT handle.
1213  */
1214 int
1215 rtems_fdt_num_entries(rtems_fdt_handle* handle)
1216 {
1217   return handle->blob->index.num_entries;
1218 }
1219 
1220 /**
1221  * Get the numbered entry name. Note that the id isn't the same as
1222  * the offset - it's numbered 0, 1, 2 ... num_entries-1
1223  */
1224 const char *
1225 rtems_fdt_entry_name(rtems_fdt_handle* handle, int id)
1226 {
1227   return handle->blob->index.entries[id].name;
1228 }
1229 
1230 /**
1231  * Get the numbered entry offset. Note that the id isn't the same as
1232  * the offset - it's numbered 0, 1, 2 ... num_entries-1
1233  */
1234 int
1235 rtems_fdt_entry_offset(rtems_fdt_handle* handle, int id)
1236 {
1237   return handle->blob->index.entries[id].offset;
1238 }
1239 
1240 int
1241 rtems_fdt_getprop_address_cells(rtems_fdt_handle* handle, int nodeoffset)
1242 {
1243   uint32_t value = 0;
1244   if (!rtems_fdt_get_parent_prop_value(handle, nodeoffset, "#address-cells", &value))
1245     return -1;
1246   return value;
1247 }
1248 
1249 int
1250 rtems_fdt_getprop_size_cells(rtems_fdt_handle* handle, int nodeoffset)
1251 {
1252   uint32_t value = 0;
1253   if (!rtems_fdt_get_parent_prop_value(handle, nodeoffset, "#size-cells", &value))
1254     return -1;
1255   return value;
1256 }
1257 
1258 int rtems_fdt_getprop_address_map(rtems_fdt_handle*      handle,
1259                                   const char*            path,
1260                                   const char*            name,
1261                                   rtems_fdt_address_map* addr_map)
1262 {
1263   const void* prop;
1264   int plen = 0;
1265   int poff = 0;
1266   int len;
1267 
1268   memset(addr_map, 0, sizeof(*addr_map));
1269 
1270   addr_map->node = rtems_fdt_path_offset(handle, path);
1271   if (addr_map->node < 0)
1272     return -RTEMS_FDT_ERR_NOTFOUND;
1273 
1274   addr_map->address_cells = rtems_fdt_getprop_address_cells(handle, addr_map->node);
1275   addr_map->size_cells = rtems_fdt_getprop_size_cells(handle, addr_map->node);
1276 
1277   prop = rtems_fdt_getprop(handle, addr_map->node, name, &plen);
1278   if (plen < 0)
1279     return -RTEMS_FDT_ERR_NOTFOUND;
1280 
1281   if (addr_map->address_cells == 0)
1282     return -RTEMS_FDT_ERR_BADOFFSET;
1283 
1284   if (addr_map->address_cells < 0)
1285   {
1286     if (addr_map->size_cells > 0)
1287       return -RTEMS_FDT_ERR_BADOFFSET;
1288     addr_map->address_cells = 1;
1289   }
1290 
1291   if (addr_map->size_cells < 0)
1292   {
1293     addr_map->size = sizeof(uint32_t);
1294     addr_map->size_cells = 0;
1295   }
1296 
1297   len = (addr_map->address_cells + addr_map->size_cells) * sizeof(uint32_t);
1298 
1299   if (len != plen)
1300     return -RTEMS_FDT_ERR_BADLENGTH;
1301 
1302   switch (addr_map->address_cells)
1303   {
1304     case 1:
1305       if (plen < sizeof(uint32_t))
1306         return -RTEMS_FDT_ERR_BADLENGTH;
1307       addr_map->address = rtems_fdt_get_offset_uint32(prop, poff);
1308       poff += 1;
1309       plen -= sizeof(uint32_t);
1310       break;
1311     case 2:
1312       if (plen < sizeof(uint64_t))
1313         return -RTEMS_FDT_ERR_BADLENGTH;
1314       addr_map->address = rtems_fdt_get_offset_uint64(prop, poff);
1315       poff += 2;
1316       plen -= sizeof(uint64_t);
1317       break;
1318     default:
1319       return -RTEMS_FDT_ERR_BADLENGTH;
1320   }
1321 
1322   switch (addr_map->size_cells)
1323   {
1324     case 0:
1325       addr_map->size = sizeof(uint32_t);
1326       break;
1327     case 1:
1328       if (plen < sizeof(uint32_t))
1329         return -RTEMS_FDT_ERR_BADLENGTH;
1330       addr_map->size = rtems_fdt_get_offset_uint32(prop, poff);
1331       poff += 1;
1332       plen -= sizeof(uint32_t);
1333       break;
1334     case 2:
1335       if (plen < sizeof(uint64_t))
1336         return -RTEMS_FDT_ERR_BADLENGTH;
1337       addr_map->size = rtems_fdt_get_offset_uint64(prop, poff);
1338       poff += 2;
1339       plen -= sizeof(uint64_t);
1340       break;
1341     default:
1342       return -RTEMS_FDT_ERR_BADLENGTH;
1343   }
1344 
1345   return 0;
1346 }