From 40eb58fd5e7f0480601b0a9c3f48756921726df7 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 29 Sep 2022 15:47:30 +1000 Subject: libmisc/rtems-fdt: Update to support 64bit addresses - Add support to get the parent address and size cells - Provide support to get a reg prop address map - Change getting a set of properties to uintptr_t - Improve the debug mode of the ls command to print all props Closes #4729 --- cpukit/include/rtems/rtems-fdt.h | 99 +++++++- cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c | 350 ++++++++++++++++++++--------- cpukit/libmisc/rtems-fdt/rtems-fdt.c | 214 ++++++++++++++++-- 3 files changed, 529 insertions(+), 134 deletions(-) (limited to 'cpukit') diff --git a/cpukit/include/rtems/rtems-fdt.h b/cpukit/include/rtems/rtems-fdt.h index 62db32e912..3919593582 100644 --- a/cpukit/include/rtems/rtems-fdt.h +++ b/cpukit/include/rtems/rtems-fdt.h @@ -64,6 +64,21 @@ typedef struct rtems_fdt_blob* blob; /**< The blob the handle references. */ } rtems_fdt_handle; +/** + * FDT Address property. It is an address an optionally a size. + * + * Only 32bit addresses and sizes on 32bit machine. Ignore the upper + * 32bits. + */ +typedef struct +{ + int node; + uint64_t address; + uint64_t size; + int address_cells; + int size_cells; +} rtems_fdt_address_map; + /* * The following are mappings to the standard FDT calls. */ @@ -165,9 +180,13 @@ typedef struct * The blob cannot be unloaded as it is referenced. */ #define RTEMS_FDT_ERR_REFERENCED 104 +/** + * The property length is invalid + */ +#define RTEMS_FDT_ERR_BADLENGTH 105 #define RTEMS_FDT_ERR_RTEMS_MIN 100 -#define RTEMS_FDT_ERR_MAX 104 +#define RTEMS_FDT_ERR_MAX 105 /** * Initialise a handle to a default state. @@ -334,6 +353,39 @@ const char* rtems_fdt_get_name (rtems_fdt_handle* handle, int nodeoffset, int* length); +/** + * Retrieve the offset for the first property for a node. + * + * @param handle The FDT handle to the current blob. + * @param nodeoffset Structure block offset of the starting node. + * @return int The offset of a node's first property. + */ +int rtems_fdt_first_prop_offset(rtems_fdt_handle* handle, int nodeoffset); + +/** + * Retrieve the next property of a node relative to the property + * + * @param handle The FDT handle to the current blob. + * @param propoffset Property offset to search from + * @return int Property offset or end if less than 0. + */ +int rtems_fdt_next_prop_offset(rtems_fdt_handle* handle, int propoffset); + +/** + * Retrieve the property value, name and length of name given a + * property offset. + * + * @param handle The FDT handle to the current blob. + * @param propoffset Property offset + * @param name If not NULL set the pointer to the name string. + * @param length Pointer to an integer variable (will be overwritten) or NULL. + * @return const void* The node's value data. + */ +const void* rtems_fdt_getprop_by_offset(rtems_fdt_handle* handle, + int propoffset, + const char** name, + int* length); + /** * Get property value based on substring. Identical to rtems_fdt_getprop(), but * only examine the first namelen characters of name for matching the property @@ -585,6 +637,14 @@ int rtems_fdt_next_node (rtems_fdt_handle* handle, int offset, int* depth); */ const char* rtems_fdt_strerror (int errval); +/** + * Return a parent property given a node offset. Travel up until found + * or the root node is reached + */ +bool rtems_fdt_get_parent_prop_value(rtems_fdt_handle* handle, + int nodeoffset, + const char* name, + uint32_t* value); /** * Return a property given a path. */ @@ -600,7 +660,7 @@ int rtems_fdt_prop_value(const char* const path, 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); /* @@ -609,7 +669,7 @@ int rtems_fdt_prop_map (const char* const path, int rtems_fdt_get_value (const char* const path, const char* const property, size_t size, - uint32_t* value); + uintptr_t* value); /** * Get the number of entries in an FDT handle. @@ -631,7 +691,38 @@ int rtems_fdt_entry_offset(rtems_fdt_handle* handle, int id); /* * Helper function to convert the void* property result to a 32bit unsigned int. */ -uint32_t rtems_fdt_get_uint32 (const void* prop); +uint32_t rtems_fdt_get_uint32(const void* prop); +uint32_t rtems_fdt_get_offset_uint32(const void* prop, int offset); + +/* + * Helper function to convert the void* property result to a 64bit unsigned int. + */ +uint64_t rtems_fdt_get_uint64(const void* prop); +uint64_t rtems_fdt_get_offset_uint64(const void* prop, int offset); + +/* + * Helper function to convert the void* property result to a uintptr_t + */ +uintptr_t rtems_fdt_get_uintptr(const void* prop); +uintptr_t rtems_fdt_get_offset_uintptr(const void* prop, int offset); + +/* + * Find the address cells property in parent nodes. + */ +int rtems_fdt_getprop_address_cells(rtems_fdt_handle* handle, int nodeoffset); + +/* + * Find the size cells property in parent nodes. + */ +int rtems_fdt_getprop_size_cells(rtems_fdt_handle* handle, int nodeoffset); + +/* + * Get an address space property. + */ +int rtems_fdt_getprop_address_map(rtems_fdt_handle* handle, + const char* path, + const char* name, + rtems_fdt_address_map* addr_map); #ifdef __cplusplus } diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c index 76f5cd7dbb..0bf6c84208 100644 --- a/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c +++ b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c @@ -127,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; } @@ -185,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) @@ -220,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); @@ -231,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; + } } + } + } - if (debug) + 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) { - /* 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); + print_name = name + name_offset; + } + else if (name_len != path_len + name_offset) + { + print_name = &name[path_len + name_offset + 1]; + } - if (prop) - { - printf(" addr 0x%08" PRIx32, *(uint32_t *)prop); - } + printf ("%-*s", max_name_len, print_name); - proplen = 0; - if (prop2) + if (debug) + { + /* Get properties if we're in debug mode. */ + 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(" 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); } } @@ -283,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 (); @@ -296,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; + + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; - printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 "\n", address, value); + printf ("0x%0*" PRIx64 " <= 0x%08" PRIx32 "\n", fmt, addr_map.address, value); - rtems_fdt_write (address, value); + rtems_fdt_write (addr_map.address, value); return 0; } @@ -315,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 (); @@ -324,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; + } - 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, rtems_fdt_read (address)); + fmt = addr_map.address >= 0x0000000100000000ULL ? 16 : 8; + + printf ("0x%0*" PRIx64 " => 0x%08" PRIx32 "\n", + fmt, addr_map.address, rtems_fdt_read (addr_map.address)); return 0; } @@ -337,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 (); @@ -354,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; } @@ -379,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 (); @@ -396,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; } @@ -422,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 (); @@ -442,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; } @@ -468,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 (); @@ -489,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 bea01dbf78..4ec54ca20f 100644 --- a/cpukit/libmisc/rtems-fdt/rtems-fdt.c +++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.c @@ -782,6 +782,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, @@ -987,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; @@ -1006,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) @@ -1025,40 +1063,70 @@ 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; } - 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_uintptr(prop); } return 0; } 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; @@ -1081,7 +1149,7 @@ rtems_fdt_get_value (const char* path, return length; } - if (length == sizeof (uint32_t)) + if (length == sizeof (uintptr_t)) *value = rtems_fdt_get_uint32 (prop); else *value = 0; @@ -1119,3 +1187,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; +} -- cgit v1.2.3