diff options
Diffstat (limited to 'cpukit/libmisc/rtems-fdt/rtems-fdt.c')
-rw-r--r-- | cpukit/libmisc/rtems-fdt/rtems-fdt.c | 283 |
1 files changed, 247 insertions, 36 deletions
diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt.c b/cpukit/libmisc/rtems-fdt/rtems-fdt.c index 1cd2377967..9f8d7bfb24 100644 --- a/cpukit/libmisc/rtems-fdt/rtems-fdt.c +++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.c @@ -1,14 +1,31 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /* * COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@rtems.org> * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ -#include <errno.h> #include <fcntl.h> -#include <stdlib.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> @@ -16,6 +33,7 @@ #include <libfdt.h> #include <zlib.h> +#include <rtems/malloc.h> #include <rtems/rtems-fdt.h> #include <rtems/thread.h> @@ -156,14 +174,14 @@ rtems_fdt_init_index (rtems_fdt_handle* fdt, rtems_fdt_blob* blob) /* * Create the index. */ - entries = calloc(num_entries, sizeof(rtems_fdt_index_entry)); + entries = rtems_calloc(num_entries, sizeof(rtems_fdt_index_entry)); if (!entries) { return -RTEMS_FDT_ERR_NO_MEMORY; } - names = calloc(1, total_name_memory); - if (!entries) + names = rtems_calloc(1, total_name_memory); + if (!names) { free(entries); return -RTEMS_FDT_ERR_NO_MEMORY; @@ -486,7 +504,7 @@ rtems_fdt_load (const char* filename, rtems_fdt_handle* handle) { size_t offset; - cdata = malloc(sb.st_size); + cdata = rtems_malloc(sb.st_size); if (!cdata) { close (bf); @@ -527,7 +545,7 @@ rtems_fdt_load (const char* filename, rtems_fdt_handle* handle) name_len = strlen (filename) + 1; - blob = malloc(sizeof (rtems_fdt_blob) + name_len + bsize); + blob = rtems_malloc(sizeof (rtems_fdt_blob) + name_len + bsize); if (!blob) { free(cdata); @@ -611,6 +629,7 @@ rtems_fdt_load (const char* filename, rtems_fdt_handle* handle) return fe; } + close (bf); return 0; } @@ -629,7 +648,7 @@ rtems_fdt_register (const void* dtb, rtems_fdt_handle* handle) return fe; } - blob = malloc(sizeof (rtems_fdt_blob)); + blob = rtems_malloc(sizeof (rtems_fdt_blob)); if (!blob) { return -RTEMS_FDT_ERR_NO_MEMORY; @@ -680,14 +699,14 @@ rtems_fdt_unload (rtems_fdt_handle* handle) rtems_chain_extract_unprotected (&handle->blob->node); + rtems_fdt_release_index(&handle->blob->index); + free (handle->blob); handle->blob = NULL; rtems_fdt_unlock (fdt); - rtems_fdt_release_index(&handle->blob->index); - return 0; } @@ -762,6 +781,27 @@ rtems_fdt_get_name (rtems_fdt_handle* handle, int nodeoffset, int* length) return name; } +int +rtems_fdt_first_prop_offset(rtems_fdt_handle* handle, int nodeoffset) +{ + return fdt_first_property_offset(handle->blob->blob, nodeoffset); +} + +int +rtems_fdt_next_prop_offset(rtems_fdt_handle* handle, int propoffset) +{ + return fdt_next_property_offset(handle->blob->blob, propoffset); +} + +const void* +rtems_fdt_getprop_by_offset(rtems_fdt_handle* handle, + int propoffset, + const char** name, + int* length) +{ + return fdt_getprop_by_offset(handle->blob->blob, propoffset, name, length); +} + const void* rtems_fdt_getprop_namelen (rtems_fdt_handle* handle, int nodeoffset, @@ -921,7 +961,8 @@ rtems_fdt_strerror (int errval) "no memory", "file not found", "DTB read fail", - "blob has references" + "blob has references", + "bad length" }; if (errval > -RTEMS_FDT_ERR_RTEMS_MIN) return fdt_strerror (errval); @@ -957,7 +998,7 @@ rtems_fdt_prop_value(const char* const path, if (length > (int) *size) { rtems_fdt_release_handle (&fdt); - return RTEMS_FDT_ERR_BADPATH; + return -RTEMS_FDT_ERR_BADPATH; } *size = length; @@ -967,11 +1008,29 @@ rtems_fdt_prop_value(const char* const path, return 0; } +bool +rtems_fdt_get_parent_prop_value(rtems_fdt_handle* handle, + int nodeoffset, + const char* name, + uint32_t* value) +{ + const void* prop; + int plen = 0; + int node = rtems_fdt_parent_offset(handle, nodeoffset); + if (node < 0) + return false; + prop = rtems_fdt_getprop(handle, node, name, &plen); + if (plen < 0) + return false; + *value = rtems_fdt_get_uint32(prop); + return true; +} + int rtems_fdt_prop_map(const char* const path, const char* const propname, const char* const names[], - uint32_t* values, + uintptr_t* values, size_t count) { rtems_fdt_handle fdt; @@ -986,10 +1045,9 @@ rtems_fdt_prop_map(const char* const path, for (item = 0; item < count; item++) { - const void* prop; - const uint8_t* p; - int length; - int subnode; + const void* prop; + int length; + int subnode; subnode = rtems_fdt_subnode_offset (&fdt, node, names[item]); if (subnode < 0) @@ -1005,40 +1063,85 @@ rtems_fdt_prop_map(const char* const path, return length; } - if (length != sizeof (uint32_t)) + if (length > sizeof (uintptr_t)) { rtems_fdt_release_handle (&fdt); - return RTEMS_FDT_ERR_BADPATH; + return -RTEMS_FDT_ERR_BADPATH; } - p = prop; - - values[item] = ((((uint32_t) p[0]) << 24) | - (((uint32_t) p[1]) << 16) | - (((uint32_t) p[2]) << 8) | - (uint32_t) p[3]); + values[item] = rtems_fdt_get_offset_len_uintptr(prop, 0, length); } return 0; } +uintptr_t +rtems_fdt_get_offset_len_uintptr (const void* prop, int offset, int len) +{ + const uint8_t* p = prop; + uintptr_t value = 0; + int b; + if (len <= sizeof(uintptr_t)) { + for (b = 0; b < len; ++b) { + value = (value << 8) | (uintptr_t) p[offset++]; + } + } + return value; +} + + uint32_t -rtems_fdt_get_uint32 (const void* prop) +rtems_fdt_get_offset_uint32 (const void* prop, int offset) { const uint8_t* p = prop; uint32_t value; - value = ((((uint32_t) p[0]) << 24) | - (((uint32_t) p[1]) << 16) | - (((uint32_t) p[2]) << 8) | - (uint32_t) p[3]); + offset *= sizeof(uint32_t); + value = ((((uint32_t) p[offset + 0]) << 24) | + (((uint32_t) p[offset + 1]) << 16) | + (((uint32_t) p[offset + 2]) << 8) | + (uint32_t) p[offset + 3]); return value; } +uint32_t +rtems_fdt_get_uint32 (const void* prop) +{ + return rtems_fdt_get_offset_uint32(prop, 0); +} + +uint64_t +rtems_fdt_get_offset_uint64 (const void* prop, int offset) +{ + uint64_t value = rtems_fdt_get_offset_uint32(prop, offset); + value = (value << 16) << 16; + return value | rtems_fdt_get_offset_uint32(prop, offset + 1); +} + +uint64_t +rtems_fdt_get_uint64 (const void* prop) +{ + return rtems_fdt_get_offset_uint64(prop, 0); +} + +uintptr_t +rtems_fdt_get_uintptr (const void* prop) +{ + return rtems_fdt_get_offset_uintptr(prop, 0); +} + +uintptr_t +rtems_fdt_get_offset_uintptr (const void* prop, int offset) +{ + if (sizeof(intptr_t) == sizeof(uint32_t)) + return rtems_fdt_get_offset_uint32(prop, offset); + return rtems_fdt_get_offset_uint64(prop, offset); +} + int rtems_fdt_get_value (const char* path, const char* property, size_t size, - uint32_t* value) + uintptr_t* value) { rtems_fdt_handle fdt; const void* prop; @@ -1061,8 +1164,8 @@ rtems_fdt_get_value (const char* path, return length; } - if (length == sizeof (uint32_t)) - *value = rtems_fdt_get_uint32 (prop); + if (length == sizeof (uintptr_t)) + *value = rtems_fdt_get_uintptr (prop); else *value = 0; @@ -1099,3 +1202,111 @@ rtems_fdt_entry_offset(rtems_fdt_handle* handle, int id) { return handle->blob->index.entries[id].offset; } + +int +rtems_fdt_getprop_address_cells(rtems_fdt_handle* handle, int nodeoffset) +{ + uint32_t value = 0; + if (!rtems_fdt_get_parent_prop_value(handle, nodeoffset, "#address-cells", &value)) + return -1; + return value; +} + +int +rtems_fdt_getprop_size_cells(rtems_fdt_handle* handle, int nodeoffset) +{ + uint32_t value = 0; + if (!rtems_fdt_get_parent_prop_value(handle, nodeoffset, "#size-cells", &value)) + return -1; + return value; +} + +int rtems_fdt_getprop_address_map(rtems_fdt_handle* handle, + const char* path, + const char* name, + rtems_fdt_address_map* addr_map) +{ + const void* prop; + int plen = 0; + int poff = 0; + int len; + + memset(addr_map, 0, sizeof(*addr_map)); + + addr_map->node = rtems_fdt_path_offset(handle, path); + if (addr_map->node < 0) + return -RTEMS_FDT_ERR_NOTFOUND; + + addr_map->address_cells = rtems_fdt_getprop_address_cells(handle, addr_map->node); + addr_map->size_cells = rtems_fdt_getprop_size_cells(handle, addr_map->node); + + prop = rtems_fdt_getprop(handle, addr_map->node, name, &plen); + if (plen < 0) + return -RTEMS_FDT_ERR_NOTFOUND; + + if (addr_map->address_cells == 0) + return -RTEMS_FDT_ERR_BADOFFSET; + + if (addr_map->address_cells < 0) + { + if (addr_map->size_cells > 0) + return -RTEMS_FDT_ERR_BADOFFSET; + addr_map->address_cells = 1; + } + + if (addr_map->size_cells < 0) + { + addr_map->size = sizeof(uint32_t); + addr_map->size_cells = 0; + } + + len = (addr_map->address_cells + addr_map->size_cells) * sizeof(uint32_t); + + if (len != plen) + return -RTEMS_FDT_ERR_BADLENGTH; + + switch (addr_map->address_cells) + { + case 1: + if (plen < sizeof(uint32_t)) + return -RTEMS_FDT_ERR_BADLENGTH; + addr_map->address = rtems_fdt_get_offset_uint32(prop, poff); + poff += 1; + plen -= sizeof(uint32_t); + break; + case 2: + if (plen < sizeof(uint64_t)) + return -RTEMS_FDT_ERR_BADLENGTH; + addr_map->address = rtems_fdt_get_offset_uint64(prop, poff); + poff += 2; + plen -= sizeof(uint64_t); + break; + default: + return -RTEMS_FDT_ERR_BADLENGTH; + } + + switch (addr_map->size_cells) + { + case 0: + addr_map->size = sizeof(uint32_t); + break; + case 1: + if (plen < sizeof(uint32_t)) + return -RTEMS_FDT_ERR_BADLENGTH; + addr_map->size = rtems_fdt_get_offset_uint32(prop, poff); + poff += 1; + plen -= sizeof(uint32_t); + break; + case 2: + if (plen < sizeof(uint64_t)) + return -RTEMS_FDT_ERR_BADLENGTH; + addr_map->size = rtems_fdt_get_offset_uint64(prop, poff); + poff += 2; + plen -= sizeof(uint64_t); + break; + default: + return -RTEMS_FDT_ERR_BADLENGTH; + } + + return 0; +} |