* Copyright (C) 2006 David Gibson, IBM Corporation.
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
*/
-#include "libfdt_env.h"
+#include <libfdt_env.h>
#ifndef USE_HOSTCC
#include <fdt.h>
{
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
- if (! p)
+ if (!p)
/* short match */
return 0;
return (strnlen(p, len + 1) == len) && (memcmp(p, s, len) == 0);
}
+uint32_t fdt_get_max_phandle(const void *fdt)
+{
+ uint32_t max_phandle = 0;
+ int offset;
+
+ for (offset = fdt_next_node(fdt, -1, NULL);;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ uint32_t phandle;
+
+ if (offset == -FDT_ERR_NOTFOUND)
+ return max_phandle;
+
+ if (offset < 0)
+ return (uint32_t)-1;
+
+ phandle = fdt_get_phandle(fdt, offset);
+ if (phandle == (uint32_t)-1)
+ continue;
+
+ if (phandle > max_phandle)
+ max_phandle = phandle;
+ }
+
+ return 0;
+}
+
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
FDT_CHECK_HEADER(fdt);
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
}
-int fdt_path_offset(const void *fdt, const char *path)
+/*
+ * Find the next of path separator, note we need to search for both '/' and ':'
+ * and then take the first one so that we do the right thing for e.g.
+ * "foo/bar:option" and "bar:option/otheroption", both of which happen, so
+ * first searching for either ':' or '/' does not work.
+ */
+static const char *fdt_path_next_separator(const char *path, int len)
+{
+ const void *sep1 = memchr(path, '/', len);
+ const void *sep2 = memchr(path, ':', len);
+
+ if (sep1 && sep2)
+ return (sep1 < sep2) ? sep1 : sep2;
+ else if (sep1)
+ return sep1;
+ else
+ return sep2;
+}
+
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
{
- const char *end = path + strlen(path);
+ const char *end = path + namelen;
const char *p = path;
int offset = 0;
/* see if we have an alias */
if (*path != '/') {
- const char *q = strchr(path, '/');
+ const char *q = fdt_path_next_separator(path, namelen);
if (!q)
q = end;
p = q;
}
- while (*p) {
+ while (*p && (p < end)) {
const char *q;
while (*p == '/')
p++;
- if (! *p)
+
+ if (*p == '\0' || *p == ':')
return offset;
- q = strchr(p, '/');
- if (! q)
+
+ q = fdt_path_next_separator(p, end - p);
+ if (!q)
q = end;
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
return offset;
}
+int fdt_path_offset(const void *fdt, const char *path)
+{
+ return fdt_path_offset_namelen(fdt, path, strlen(path));
+}
+
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
const struct fdt_property *prop;
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
- if (! prop)
+ if (!prop)
return NULL;
return prop->data;
return 0;
}
-int fdt_count_strings(const void *fdt, int node, const char *property)
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
{
- int length, i, count = 0;
- const char *list;
+ const char *list, *end;
+ int length, count = 0;
- list = fdt_getprop(fdt, node, property, &length);
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
- return -length;
+ return length;
+
+ end = list + length;
- for (i = 0; i < length; i++) {
- int len = strlen(list);
+ while (list < end) {
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end)
+ return -FDT_ERR_BADVALUE;
- list += len + 1;
- i += len;
+ list += length;
count++;
}
return count;
}
-int fdt_find_string(const void *fdt, int node, const char *property,
- const char *string)
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+ const char *string)
{
+ int length, len, idx = 0;
const char *list, *end;
- int len, index = 0;
- list = fdt_getprop(fdt, node, property, &len);
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
- return len;
+ return length;
- end = list + len;
- len = strlen(string);
+ len = strlen(string) + 1;
+ end = list + length;
while (list < end) {
- int l = strlen(list);
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end)
+ return -FDT_ERR_BADVALUE;
- if (l == len && memcmp(list, string, len) == 0)
- return index;
+ if (length == len && memcmp(list, string, length) == 0)
+ return idx;
- list += l + 1;
- index++;
+ list += length;
+ idx++;
}
return -FDT_ERR_NOTFOUND;
}
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+ const char *property, int idx,
+ int *lenp)
+{
+ const char *list, *end;
+ int length;
+
+ list = fdt_getprop(fdt, nodeoffset, property, &length);
+ if (!list) {
+ if (lenp)
+ *lenp = length;
+
+ return NULL;
+ }
+
+ end = list + length;
+
+ while (list < end) {
+ length = strnlen(list, end - list) + 1;
+
+ /* Abort if the last string isn't properly NUL-terminated. */
+ if (list + length > end) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADVALUE;
+
+ return NULL;
+ }
+
+ if (idx == 0) {
+ if (lenp)
+ *lenp = length - 1;
+
+ return list;
+ }
+
+ list += length;
+ idx--;
+ }
+
+ if (lenp)
+ *lenp = -FDT_ERR_NOTFOUND;
+
+ return NULL;
+}
+
int fdt_node_check_compatible(const void *fdt, int nodeoffset,
const char *compatible)
{
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop)
return len;
- if (fdt_stringlist_contains(prop, len, compatible))
- return 0;
- else
- return 1;
+
+ return !fdt_stringlist_contains(prop, len, compatible);
}
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,