diff options
Diffstat (limited to 'cpukit/libmisc/rtems-fdt')
-rw-r--r-- | cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c | 375 | ||||
-rw-r--r-- | cpukit/libmisc/rtems-fdt/rtems-fdt.c | 283 |
2 files changed, 508 insertions, 150 deletions
diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c index 61f20765e0..0bf6c84208 100644 --- a/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c +++ b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c @@ -1,9 +1,28 @@ +/* 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. */ /** * @file @@ -108,32 +127,6 @@ rtems_fdt_get_value32 (const char* path, size_t size, uint32_t* value) { - const void* prop; - int node; - int length; - - node = rtems_fdt_path_offset(&cmd_fdt_handle, path); - if (node < 0) - { - rtems_fdt_check_error (node, "path lookup", path); - return false; - } - - prop = rtems_fdt_getprop(&cmd_fdt_handle, node, property, &length); - if (length < 0) - { - rtems_fdt_check_error (length, "get property", path); - return false; - } - - if (length != sizeof (uint32_t)) - { - printf ("error: property is not sizeof(uint32_t): %s\n", path); - return false; - } - - *value = rtems_fdt_get_uint32 (prop); - return true; } @@ -166,7 +159,10 @@ rtems_fdt_shell_ls (int argc, char *argv[]) bool debug = false; int arg = 1; size_t path_len = 0; + int total_entries = 0; int num_entries = 0; + int max_name_len = 0; + int name_offset = 0; int i = 0; while (arg < argc) @@ -201,10 +197,15 @@ rtems_fdt_shell_ls (int argc, char *argv[]) ++arg; } - if (!path) + if (path == NULL) { path = ""; } + else + { + if (path[0] != '/') + name_offset = 1; + } /* Eliminate trailing slashes. */ path_len = strlen (path); @@ -212,45 +213,99 @@ rtems_fdt_shell_ls (int argc, char *argv[]) if (path_len > 0 && path[path_len - 1] == '/') path_len--; - /* Loop through the entries, looking for matches. */ - num_entries = rtems_fdt_num_entries(&cmd_fdt_handle); - printf("Total: %d\n", num_entries); - for (i = 0; i < num_entries; i++) + /* Loop through the entries to get the mac name len. */ + total_entries = rtems_fdt_num_entries(&cmd_fdt_handle); + + for (i = 0; i < total_entries; i++) { /* Add it to the result set. */ const char *name = rtems_fdt_entry_name(&cmd_fdt_handle, i); size_t name_len = strlen(name); - if ((name_len > path_len) && - ((strncmp (path, name, path_len) == 0) && (name[path_len] == '/')) && - (recursive || (index(&name[path_len+1], '/') == 0))) + if ((name_len >= path_len + name_offset) && + ((strncmp (path, name + name_offset, path_len) == 0) && + ((name[path_len + name_offset] == '/' || + name[path_len + name_offset] == '\0'))) && + (recursive || name_len == path_len + name_offset || + (strchr(&name[path_len + name_offset + 1], '/') == NULL))) { + ++num_entries; if (long_path) { - printf ("%s", name); + if (name_len > max_name_len) + { + max_name_len = name_len; + } } else if (name_len != path_len) { - printf ("%s", &name[path_len + 1]); + if (name_len - path_len > max_name_len) + { + max_name_len = name_len - path_len; + } + } + } + } + + printf("Total: %d of %d\n", num_entries, total_entries); + + for (i = 0; i < total_entries; i++) + { + /* Add it to the result set. */ + const char *name = rtems_fdt_entry_name(&cmd_fdt_handle, i); + size_t name_len = strlen(name); + + if ((name_len >= path_len + name_offset) && + ((strncmp (path, name + name_offset, path_len) == 0) && + ((name[path_len + name_offset] == '/' || + name[path_len + name_offset] == '\0'))) && + (recursive || name_len == path_len + name_offset || + (strchr(&name[path_len + name_offset + 1], '/') == NULL))) + { + const char* print_name = "."; + + if (long_path) + { + print_name = name + name_offset; } + else if (name_len != path_len + name_offset) + { + print_name = &name[path_len + name_offset + 1]; + } + + printf ("%-*s", max_name_len, print_name); if (debug) { /* Get properties if we're in debug mode. */ - int proplen = 0; - int offset = rtems_fdt_entry_offset(&cmd_fdt_handle, i); - const void *prop = rtems_fdt_getprop(&cmd_fdt_handle, offset, "reg", &proplen); - const void *prop2 = rtems_fdt_getprop(&cmd_fdt_handle, offset, "mask", &proplen); - - if (prop) + int printed = 0; + const int noffset = rtems_fdt_entry_offset(&cmd_fdt_handle, i); + int poffset = rtems_fdt_first_prop_offset(&cmd_fdt_handle, noffset); + int address_cells = + rtems_fdt_getprop_address_cells(&cmd_fdt_handle, noffset); + int size_cells = rtems_fdt_getprop_size_cells(&cmd_fdt_handle, noffset); + printf("cells(a:%d s:%d) ", address_cells, size_cells); + while (poffset >= 0) { - printf(" addr 0x%08" PRIx32, *(uint32_t *)prop); - } - - proplen = 0; - if (prop2) - { - printf(" mask 0x%08" PRIx32, *(uint32_t *)prop2); + int plen = 0; + const char* pname = NULL; + const uint8_t *pvalue = + rtems_fdt_getprop_by_offset(&cmd_fdt_handle, poffset, &pname, &plen); + if (pvalue != NULL) + { + int b; + if (printed > 0) + printf(","); + ++printed; + printf(" %s %i:", pname, plen); + for (b = 0; b < plen; ++b) + { + if (b > 0 && (b % 4) == 0) + printf(" "); + printf("%02" PRIx8, *pvalue++); + } + } + poffset = rtems_fdt_next_prop_offset(&cmd_fdt_handle, poffset); } } @@ -264,9 +319,11 @@ rtems_fdt_shell_ls (int argc, char *argv[]) static int rtems_fdt_shell_wr (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t value; + rtems_fdt_address_map addr_map; + uint64_t offset = 0; + uint32_t value; + int fmt; + int r; if ((argc < 3) || (argc > 4)) return rtems_fdt_wrong_number_of_args (); @@ -277,18 +334,30 @@ rtems_fdt_shell_wr (int argc, char *argv[]) } else { - offset = strtoul (argv[2], 0, 0); + offset = strtoull (argv[2], 0, 0); value = strtoul (argv[3], 0, 0); } - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } - address += offset; + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 "\n", address, value); + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; - rtems_fdt_write (address, value); + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 "\n", fmt, addr_map.address, value); + + rtems_fdt_write (addr_map.address, value); return 0; } @@ -296,8 +365,10 @@ rtems_fdt_shell_wr (int argc, char *argv[]) static int rtems_fdt_shell_rd (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + int fmt; + int r; if ((argc < 1) || (argc > 3)) return rtems_fdt_wrong_number_of_args (); @@ -305,12 +376,25 @@ rtems_fdt_shell_rd (int argc, char *argv[]) if (argc == 3) offset = strtoul (argv[2], 0, 0); - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); + return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); return 1; + } + + addr_map.address += offset; - address += offset; + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; - printf ("0x%08" PRIx32 " => 0x%08" PRIx32 "\n", address, rtems_fdt_read (address)); + printf ("0x%0*" PRIx64 " => 0x%08" PRIx32 "\n", + fmt, addr_map.address, rtems_fdt_read (addr_map.address)); return 0; } @@ -318,11 +402,13 @@ rtems_fdt_shell_rd (int argc, char *argv[]) static int rtems_fdt_shell_set (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t value; - int mask_arg; - uint32_t mask; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + uint32_t value; + int mask_arg; + uint32_t mask; + int fmt; + int r; if ((argc < 3) || (argc > 4)) return rtems_fdt_wrong_number_of_args (); @@ -335,24 +421,38 @@ rtems_fdt_shell_set (int argc, char *argv[]) mask_arg = 3; } - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; if (isdigit ((unsigned char) argv[mask_arg][0])) mask = strtoul (argv[mask_arg], 0, 0); else { + mask = 0; if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) return 1; } - address += offset; - value = rtems_fdt_read (address); + value = rtems_fdt_read (addr_map.address); - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 " | 0x%08" PRIx32 "\n", - address, value | mask, value, mask); + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 " | 0x%08" PRIx32 "\n", + fmt, addr_map.address, value | mask, value, mask); - rtems_fdt_write (address, value | mask); + rtems_fdt_write (addr_map.address, value | mask); return 0; } @@ -360,11 +460,13 @@ rtems_fdt_shell_set (int argc, char *argv[]) static int rtems_fdt_shell_cl (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t value; - int mask_arg; - uint32_t mask; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + uint32_t value; + int mask_arg; + uint32_t mask; + int fmt; + int r; if ((argc < 3) || (argc > 4)) return rtems_fdt_wrong_number_of_args (); @@ -377,25 +479,39 @@ rtems_fdt_shell_cl (int argc, char *argv[]) mask_arg = 3; } - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; if (isdigit ((unsigned char) argv[mask_arg][0])) mask = strtoul (argv[mask_arg], 0, 0); else { + mask = 0; if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) return 1; } - address += offset; - value = rtems_fdt_read (address); + value = rtems_fdt_read (addr_map.address); - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 \ + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 \ " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")\n", - address, value & ~mask, value, mask, ~mask); + fmt, addr_map.address, value & ~mask, value, mask, ~mask); - rtems_fdt_write (address, value & ~mask); + rtems_fdt_write (addr_map.address, value & ~mask); return 0; } @@ -403,12 +519,14 @@ rtems_fdt_shell_cl (int argc, char *argv[]) static int rtems_fdt_shell_up (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t set; - uint32_t value; - int mask_arg; - uint32_t mask; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + uint32_t set; + uint32_t value; + int mask_arg; + uint32_t mask; + int fmt; + int r; if ((argc < 4) || (argc > 5)) return rtems_fdt_wrong_number_of_args (); @@ -423,25 +541,39 @@ rtems_fdt_shell_up (int argc, char *argv[]) set = strtoul (argv[mask_arg + 1], 0, 0); - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; if (isdigit ((unsigned char) argv[mask_arg][0])) mask = strtoul (argv[mask_arg], 0, 0); else { + mask = 0; if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) return 1; } - address += offset; - value = rtems_fdt_read (address); + value = rtems_fdt_read (addr_map.address); - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = (0x%08" PRIx32 \ + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 " = (0x%08" PRIx32 \ " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")) | 0x%08" PRIx32 "\n", - address, (value & ~mask) | set, value, mask, ~mask, set); + fmt, addr_map.address, (value & ~mask) | set, value, mask, ~mask, set); - rtems_fdt_write (address, (value & ~mask) | set); + rtems_fdt_write (addr_map.address, (value & ~mask) | set); return 0; } @@ -449,13 +581,15 @@ rtems_fdt_shell_up (int argc, char *argv[]) static int rtems_fdt_shell_tst (int argc, char *argv[]) { - uint32_t address; - uint32_t offset = 0; - uint32_t test; - uint32_t value = 0; - int mask_arg; - uint32_t mask; - time_t start; + rtems_fdt_address_map addr_map; + uint32_t offset = 0; + uint32_t test; + uint32_t value = 0; + int mask_arg; + uint32_t mask; + time_t start; + int fmt; + int r; if ((argc < 4) || (argc > 5)) return rtems_fdt_wrong_number_of_args (); @@ -470,37 +604,50 @@ rtems_fdt_shell_tst (int argc, char *argv[]) test = strtoul (argv[mask_arg + 1], 0, 0); - if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address)) + r = rtems_fdt_getprop_address_map(&cmd_fdt_handle, argv[1], "reg", &addr_map); + if (r < 0) + { + printf("error: invalid reg address map: %d: %s\n", -r, argv[1]); return 1; + } + + if (offset >= addr_map.size) + { + printf("error: offset out of range: %" PRIu64 ": %s\n", addr_map.size, argv[1]); + return 1; + } + + addr_map.address += offset; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; if (isdigit ((unsigned char) argv[mask_arg][0])) mask = strtoul (argv[mask_arg], 0, 0); else { - if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) + mask = 0; + if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask)) return 1; } - address += offset; - start = time (NULL); - printf ("0x%08" PRIx32 " => (value & 0x%08" PRIx32 ") == 0x%08" PRIx32 \ + printf ("0x%0*" PRIx64 " => (value & 0x%08" PRIx32 ") == 0x%08" PRIx32 \ " for %ld seconds\n", - address, mask, test, rtems_fdt_test_timeout); + fmt, addr_map.address, mask, test, rtems_fdt_test_timeout); while ((time (NULL) - start) < rtems_fdt_test_timeout) { int i; for (i = 0; i < 10000; ++i) { - value = rtems_fdt_read (address); + value = rtems_fdt_read (addr_map.address); if ((value & mask) == test) return 0; } } - printf ("0x%08" PRIx32 " => 0x%08" PRIx32 ": timeout\n", address, value); + printf ("0x%0*" PRIx64 " => 0x%08" PRIx32 ": timeout\n", fmt, addr_map.address, value); return 1; } 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; +} |