diff options
author | Tom Rini <trini@konsulko.com> | 2020-04-28 09:52:01 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-04-28 09:52:01 -0400 |
commit | 545c747447706d9601cc5c65a85ec44e688bfe08 (patch) | |
tree | 398a874161673df9656e271a6dbb4b127a45f725 /lib | |
parent | 08977f873f4034307796173784fc17a11188a0cb (diff) | |
parent | c1f39edc62adc81775e750957aa557bcf994e607 (diff) | |
download | u-boot-545c747447706d9601cc5c65a85ec44e688bfe08.tar.gz |
Merge tag 'dm-pull-27apr20' of git://git.denx.de/u-boot-dm
Move Python tools to use absolute paths
Minor buildman fixes for new features
Make libfdt code more similar to upsteam
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libfdt/Makefile | 9 | ||||
-rw-r--r-- | lib/libfdt/fdt_region.c | 656 | ||||
-rw-r--r-- | lib/libfdt/fdt_ro.c | 925 |
3 files changed, 2 insertions, 1588 deletions
diff --git a/lib/libfdt/Makefile b/lib/libfdt/Makefile index 5d3ae4e2f1..1fe50ecbe5 100644 --- a/lib/libfdt/Makefile +++ b/lib/libfdt/Makefile @@ -3,9 +3,9 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -# Use upstream code. obj-y += \ fdt.o \ + fdt_ro.o \ fdt_wip.o \ fdt_strerror.o \ fdt_sw.o \ @@ -15,12 +15,5 @@ obj-y += \ obj-$(CONFIG_OF_LIBFDT_OVERLAY) += fdt_overlay.o -# Locally modified for U-Boot. -# TODO: split out the local modifiction. -obj-y += fdt_ro.o - -# U-Boot own file -obj-y += fdt_region.o - ccflags-y := -I$(srctree)/scripts/dtc/libfdt \ -DFDT_ASSUME_MASK=$(CONFIG_$(SPL_TPL_)OF_LIBFDT_ASSUME_MASK) diff --git a/lib/libfdt/fdt_region.c b/lib/libfdt/fdt_region.c deleted file mode 100644 index 7e9fa9272e..0000000000 --- a/lib/libfdt/fdt_region.c +++ /dev/null @@ -1,656 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2013 Google, Inc - * Written by Simon Glass <sjg@chromium.org> - */ - -#include <linux/libfdt_env.h> - -#ifndef USE_HOSTCC -#include <fdt.h> -#include <linux/libfdt.h> -#else -#include "fdt_host.h" -#endif - -#define FDT_MAX_DEPTH 32 - -static int str_in_list(const char *str, char * const list[], int count) -{ - int i; - - for (i = 0; i < count; i++) - if (!strcmp(list[i], str)) - return 1; - - return 0; -} - -int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, - char * const exc_prop[], int exc_prop_count, - struct fdt_region region[], int max_regions, - char *path, int path_len, int add_string_tab) -{ - int stack[FDT_MAX_DEPTH] = { 0 }; - char *end; - int nextoffset = 0; - uint32_t tag; - int count = 0; - int start = -1; - int depth = -1; - int want = 0; - int base = fdt_off_dt_struct(fdt); - - end = path; - *end = '\0'; - do { - const struct fdt_property *prop; - const char *name; - const char *str; - int include = 0; - int stop_at = 0; - int offset; - int len; - - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - stop_at = nextoffset; - - switch (tag) { - case FDT_PROP: - include = want >= 2; - stop_at = offset; - prop = fdt_get_property_by_offset(fdt, offset, NULL); - str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - if (str_in_list(str, exc_prop, exc_prop_count)) - include = 0; - break; - - case FDT_NOP: - include = want >= 2; - stop_at = offset; - break; - - case FDT_BEGIN_NODE: - depth++; - if (depth == FDT_MAX_DEPTH) - return -FDT_ERR_BADSTRUCTURE; - name = fdt_get_name(fdt, offset, &len); - if (end - path + 2 + len >= path_len) - return -FDT_ERR_NOSPACE; - if (end != path + 1) - *end++ = '/'; - strcpy(end, name); - end += len; - stack[depth] = want; - if (want == 1) - stop_at = offset; - if (str_in_list(path, inc, inc_count)) - want = 2; - else if (want) - want--; - else - stop_at = offset; - include = want; - break; - - case FDT_END_NODE: - /* Depth must never go below -1 */ - if (depth < 0) - return -FDT_ERR_BADSTRUCTURE; - include = want; - want = stack[depth--]; - while (end > path && *--end != '/') - ; - *end = '\0'; - break; - - case FDT_END: - include = 1; - break; - } - - if (include && start == -1) { - /* Should we merge with previous? */ - if (count && count <= max_regions && - offset == region[count - 1].offset + - region[count - 1].size - base) - start = region[--count].offset - base; - else - start = offset; - } - - if (!include && start != -1) { - if (count < max_regions) { - region[count].offset = base + start; - region[count].size = stop_at - start; - } - count++; - start = -1; - } - } while (tag != FDT_END); - - if (nextoffset != fdt_size_dt_struct(fdt)) - return -FDT_ERR_BADLAYOUT; - - /* Add a region for the END tag and the string table */ - if (count < max_regions) { - region[count].offset = base + start; - region[count].size = nextoffset - start; - if (add_string_tab) - region[count].size += fdt_size_dt_strings(fdt); - } - count++; - - return count; -} - -/** - * fdt_add_region() - Add a new region to our list - * @info: State information - * @offset: Start offset of region - * @size: Size of region - * - * The region is added if there is space, but in any case we increment the - * count. If permitted, and the new region overlaps the last one, we merge - * them. - */ -static int fdt_add_region(struct fdt_region_state *info, int offset, int size) -{ - struct fdt_region *reg; - - reg = info->region ? &info->region[info->count - 1] : NULL; - if (info->can_merge && info->count && - info->count <= info->max_regions && - reg && offset <= reg->offset + reg->size) { - reg->size = offset + size - reg->offset; - } else if (info->count++ < info->max_regions) { - if (reg) { - reg++; - reg->offset = offset; - reg->size = size; - } - } else { - return -1; - } - - return 0; -} - -static int region_list_contains_offset(struct fdt_region_state *info, - const void *fdt, int target) -{ - struct fdt_region *reg; - int num; - - target += fdt_off_dt_struct(fdt); - for (reg = info->region, num = 0; num < info->count; reg++, num++) { - if (target >= reg->offset && target < reg->offset + reg->size) - return 1; - } - - return 0; -} - -/** - * fdt_add_alias_regions() - Add regions covering the aliases that we want - * - * The /aliases node is not automatically included by fdtgrep unless the - * command-line arguments cause to be included (or not excluded). However - * aliases are special in that we generally want to include those which - * reference a node that fdtgrep includes. - * - * In fact we want to include only aliases for those nodes still included in - * the fdt, and drop the other aliases since they point to nodes that will not - * be present. - * - * This function scans the aliases and adds regions for those which we want - * to keep. - * - * @fdt: Device tree to scan - * @region: List of regions - * @count: Number of regions in the list so far (i.e. starting point for this - * function) - * @max_regions: Maximum number of regions in @region list - * @info: Place to put the region state - * @return number of regions after processing, or -FDT_ERR_NOSPACE if we did - * not have enough room in the regions table for the regions we wanted to add. - */ -int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count, - int max_regions, struct fdt_region_state *info) -{ - int base = fdt_off_dt_struct(fdt); - int node, node_end, offset; - int did_alias_header; - - node = fdt_subnode_offset(fdt, 0, "aliases"); - if (node < 0) - return -FDT_ERR_NOTFOUND; - - /* - * Find the next node so that we know where the /aliases node ends. We - * need special handling if /aliases is the last node. - */ - node_end = fdt_next_subnode(fdt, node); - if (node_end == -FDT_ERR_NOTFOUND) - /* Move back to the FDT_END_NODE tag of '/' */ - node_end = fdt_size_dt_struct(fdt) - sizeof(fdt32_t) * 2; - else if (node_end < 0) /* other error */ - return node_end; - node_end -= sizeof(fdt32_t); /* Move to FDT_END_NODE tag of /aliases */ - - did_alias_header = 0; - info->region = region; - info->count = count; - info->can_merge = 0; - info->max_regions = max_regions; - - for (offset = fdt_first_property_offset(fdt, node); - offset >= 0; - offset = fdt_next_property_offset(fdt, offset)) { - const struct fdt_property *prop; - const char *name; - int target, next; - - prop = fdt_get_property_by_offset(fdt, offset, NULL); - name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - target = fdt_path_offset(fdt, name); - if (!region_list_contains_offset(info, fdt, target)) - continue; - next = fdt_next_property_offset(fdt, offset); - if (next < 0) - next = node_end; - - if (!did_alias_header) { - fdt_add_region(info, base + node, 12); - did_alias_header = 1; - } - fdt_add_region(info, base + offset, next - offset); - } - - /* Add the FDT_END_NODE tag */ - if (did_alias_header) - fdt_add_region(info, base + node_end, sizeof(fdt32_t)); - - return info->count < max_regions ? info->count : -FDT_ERR_NOSPACE; -} - -/** - * fdt_include_supernodes() - Include supernodes required by this node - * @info: State information - * @depth: Current stack depth - * - * When we decided to include a node or property which is not at the top - * level, this function forces the inclusion of higher level nodes. For - * example, given this tree: - * - * / { - * testing { - * } - * } - * - * If we decide to include testing then we need the root node to have a valid - * tree. This function adds those regions. - */ -static int fdt_include_supernodes(struct fdt_region_state *info, int depth) -{ - int base = fdt_off_dt_struct(info->fdt); - int start, stop_at; - int i; - - /* - * Work down the stack looking for supernodes that we didn't include. - * The algortihm here is actually pretty simple, since we know that - * no previous subnode had to include these nodes, or if it did, we - * marked them as included (on the stack) already. - */ - for (i = 0; i <= depth; i++) { - if (!info->stack[i].included) { - start = info->stack[i].offset; - - /* Add the FDT_BEGIN_NODE tag of this supernode */ - fdt_next_tag(info->fdt, start, &stop_at); - if (fdt_add_region(info, base + start, stop_at - start)) - return -1; - - /* Remember that this supernode is now included */ - info->stack[i].included = 1; - info->can_merge = 1; - } - - /* Force (later) generation of the FDT_END_NODE tag */ - if (!info->stack[i].want) - info->stack[i].want = WANT_NODES_ONLY; - } - - return 0; -} - -enum { - FDT_DONE_NOTHING, - FDT_DONE_MEM_RSVMAP, - FDT_DONE_STRUCT, - FDT_DONE_END, - FDT_DONE_STRINGS, - FDT_DONE_ALL, -}; - -int fdt_first_region(const void *fdt, - int (*h_include)(void *priv, const void *fdt, int offset, - int type, const char *data, int size), - void *priv, struct fdt_region *region, - char *path, int path_len, int flags, - struct fdt_region_state *info) -{ - struct fdt_region_ptrs *p = &info->ptrs; - - /* Set up our state */ - info->fdt = fdt; - info->can_merge = 1; - info->max_regions = 1; - info->start = -1; - p->want = WANT_NOTHING; - p->end = path; - *p->end = '\0'; - p->nextoffset = 0; - p->depth = -1; - p->done = FDT_DONE_NOTHING; - - return fdt_next_region(fdt, h_include, priv, region, - path, path_len, flags, info); -} - -/*********************************************************************** - * - * Theory of operation - * - * Note: in this description 'included' means that a node (or other part - * of the tree) should be included in the region list, i.e. it will have - * a region which covers its part of the tree. - * - * This function maintains some state from the last time it is called. - * It checks the next part of the tree that it is supposed to look at - * (p.nextoffset) to see if that should be included or not. When it - * finds something to include, it sets info->start to its offset. This - * marks the start of the region we want to include. - * - * Once info->start is set to the start (i.e. not -1), we continue - * scanning until we find something that we don't want included. This - * will be the end of a region. At this point we can close off the - * region and add it to the list. So we do so, and reset info->start - * to -1. - * - * One complication here is that we want to merge regions. So when we - * come to add another region later, we may in fact merge it with the - * previous one if one ends where the other starts. - * - * The function fdt_add_region() will return -1 if it fails to add the - * region, because we already have a region ready to be returned, and - * the new one cannot be merged in with it. In this case, we must return - * the region we found, and wait for another call to this function. - * When it comes, we will repeat the processing of the tag and again - * try to add a region. This time it will succeed. - * - * The current state of the pointers (stack, offset, etc.) is maintained - * in a ptrs member. At the start of every loop iteration we make a copy - * of it. The copy is then updated as the tag is processed. Only if we - * get to the end of the loop iteration (and successfully call - * fdt_add_region() if we need to) can we commit the changes we have - * made to these pointers. For example, if we see an FDT_END_NODE tag, - * we will decrement the depth value. But if we need to add a region - * for this tag (let's say because the previous tag is included and this - * FDT_END_NODE tag is not included) then we will only commit the result - * if we were able to add the region. That allows us to retry again next - * time. - * - * We keep track of a variable called 'want' which tells us what we want - * to include when there is no specific information provided by the - * h_include function for a particular property. This basically handles - * the inclusion of properties which are pulled in by virtue of the node - * they are in. So if you include a node, its properties are also - * included. In this case 'want' will be WANT_NODES_AND_PROPS. The - * FDT_REG_DIRECT_SUBNODES feature also makes use of 'want'. While we - * are inside the subnode, 'want' will be set to WANT_NODES_ONLY, so - * that only the subnode's FDT_BEGIN_NODE and FDT_END_NODE tags will be - * included, and properties will be skipped. If WANT_NOTHING is - * selected, then we will just rely on what the h_include() function - * tells us. - * - * Using 'want' we work out 'include', which tells us whether this - * current tag should be included or not. As you can imagine, if the - * value of 'include' changes, that means we are on a boundary between - * nodes to include and nodes to exclude. At this point we either close - * off a previous region and add it to the list, or mark the start of a - * new region. - * - * Apart from the nodes, we have mem_rsvmap, the FDT_END tag and the - * string list. Each of these dealt with as a whole (i.e. we create a - * region for each if it is to be included). For mem_rsvmap we don't - * allow it to merge with the first struct region. For the stringlist, - * we don't allow it to merge with the last struct region (which - * contains at minimum the FDT_END tag). - * - *********************************************************************/ - -int fdt_next_region(const void *fdt, - int (*h_include)(void *priv, const void *fdt, int offset, - int type, const char *data, int size), - void *priv, struct fdt_region *region, - char *path, int path_len, int flags, - struct fdt_region_state *info) -{ - int base = fdt_off_dt_struct(fdt); - int last_node = 0; - const char *str; - - info->region = region; - info->count = 0; - if (info->ptrs.done < FDT_DONE_MEM_RSVMAP && - (flags & FDT_REG_ADD_MEM_RSVMAP)) { - /* Add the memory reserve map into its own region */ - if (fdt_add_region(info, fdt_off_mem_rsvmap(fdt), - fdt_off_dt_struct(fdt) - - fdt_off_mem_rsvmap(fdt))) - return 0; - info->can_merge = 0; /* Don't allow merging with this */ - info->ptrs.done = FDT_DONE_MEM_RSVMAP; - } - - /* - * Work through the tags one by one, deciding whether each needs to - * be included or not. We set the variable 'include' to indicate our - * decision. 'want' is used to track what we want to include - it - * allows us to pick up all the properties (and/or subnode tags) of - * a node. - */ - while (info->ptrs.done < FDT_DONE_STRUCT) { - const struct fdt_property *prop; - struct fdt_region_ptrs p; - const char *name; - int include = 0; - int stop_at = 0; - uint32_t tag; - int offset; - int val; - int len; - - /* - * Make a copy of our pointers. If we make it to the end of - * this block then we will commit them back to info->ptrs. - * Otherwise we can try again from the same starting state - * next time we are called. - */ - p = info->ptrs; - - /* - * Find the tag, and the offset of the next one. If we need to - * stop including tags, then by default we stop *after* - * including the current tag - */ - offset = p.nextoffset; - tag = fdt_next_tag(fdt, offset, &p.nextoffset); - stop_at = p.nextoffset; - - switch (tag) { - case FDT_PROP: - stop_at = offset; - prop = fdt_get_property_by_offset(fdt, offset, NULL); - str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - val = h_include(priv, fdt, last_node, FDT_IS_PROP, str, - strlen(str) + 1); - if (val == -1) { - include = p.want >= WANT_NODES_AND_PROPS; - } else { - include = val; - /* - * Make sure we include the } for this block. - * It might be more correct to have this done - * by the call to fdt_include_supernodes() in - * the case where it adds the node we are - * currently in, but this is equivalent. - */ - if ((flags & FDT_REG_SUPERNODES) && val && - !p.want) - p.want = WANT_NODES_ONLY; - } - - /* Value grepping is not yet supported */ - break; - - case FDT_NOP: - include = p.want >= WANT_NODES_AND_PROPS; - stop_at = offset; - break; - - case FDT_BEGIN_NODE: - last_node = offset; - p.depth++; - if (p.depth == FDT_MAX_DEPTH) - return -FDT_ERR_BADSTRUCTURE; - name = fdt_get_name(fdt, offset, &len); - if (p.end - path + 2 + len >= path_len) - return -FDT_ERR_NOSPACE; - - /* Build the full path of this node */ - if (p.end != path + 1) - *p.end++ = '/'; - strcpy(p.end, name); - p.end += len; - info->stack[p.depth].want = p.want; - info->stack[p.depth].offset = offset; - - /* - * If we are not intending to include this node unless - * it matches, make sure we stop *before* its tag. - */ - if (p.want == WANT_NODES_ONLY || - !(flags & (FDT_REG_DIRECT_SUBNODES | - FDT_REG_ALL_SUBNODES))) { - stop_at = offset; - p.want = WANT_NOTHING; - } - val = h_include(priv, fdt, offset, FDT_IS_NODE, path, - p.end - path + 1); - - /* Include this if requested */ - if (val) { - p.want = (flags & FDT_REG_ALL_SUBNODES) ? - WANT_ALL_NODES_AND_PROPS : - WANT_NODES_AND_PROPS; - } - - /* If not requested, decay our 'p.want' value */ - else if (p.want) { - if (p.want != WANT_ALL_NODES_AND_PROPS) - p.want--; - - /* Not including this tag, so stop now */ - } else { - stop_at = offset; - } - - /* - * Decide whether to include this tag, and update our - * stack with the state for this node - */ - include = p.want; - info->stack[p.depth].included = include; - break; - - case FDT_END_NODE: - include = p.want; - if (p.depth < 0) - return -FDT_ERR_BADSTRUCTURE; - - /* - * If we don't want this node, stop right away, unless - * we are including subnodes - */ - if (!p.want && !(flags & FDT_REG_DIRECT_SUBNODES)) - stop_at = offset; - p.want = info->stack[p.depth].want; - p.depth--; - while (p.end > path && *--p.end != '/') - ; - *p.end = '\0'; - break; - - case FDT_END: - /* We always include the end tag */ - include = 1; - p.done = FDT_DONE_STRUCT; - break; - } - - /* If this tag is to be included, mark it as region start */ - if (include && info->start == -1) { - /* Include any supernodes required by this one */ - if (flags & FDT_REG_SUPERNODES) { - if (fdt_include_supernodes(info, p.depth)) - return 0; - } - info->start = offset; - } - - /* - * If this tag is not to be included, finish up the current - * region. - */ - if (!include && info->start != -1) { - if (fdt_add_region(info, base + info->start, - stop_at - info->start)) - return 0; - info->start = -1; - info->can_merge = 1; - } - - /* If we have made it this far, we can commit our pointers */ - info->ptrs = p; - } - - /* Add a region for the END tag and a separate one for string table */ - if (info->ptrs.done < FDT_DONE_END) { - if (info->ptrs.nextoffset != fdt_size_dt_struct(fdt)) - return -FDT_ERR_BADSTRUCTURE; - - if (fdt_add_region(info, base + info->start, - info->ptrs.nextoffset - info->start)) - return 0; - info->ptrs.done++; - } - if (info->ptrs.done < FDT_DONE_STRINGS) { - if (flags & FDT_REG_ADD_STRING_TAB) { - info->can_merge = 0; - if (fdt_off_dt_strings(fdt) < - base + info->ptrs.nextoffset) - return -FDT_ERR_BADLAYOUT; - if (fdt_add_region(info, fdt_off_dt_strings(fdt), - fdt_size_dt_strings(fdt))) - return 0; - } - info->ptrs.done++; - } - - return info->count > 0 ? 0 : -FDT_ERR_NOTFOUND; -} diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c index be03aea9eb..7ede074537 100644 --- a/lib/libfdt/fdt_ro.c +++ b/lib/libfdt/fdt_ro.c @@ -1,925 +1,2 @@ -// SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - */ #include <linux/libfdt_env.h> - -#ifndef USE_HOSTCC -#include <fdt.h> -#include <linux/libfdt.h> -#else -#include "fdt_host.h" -#endif - -#include "libfdt_internal.h" - -static int fdt_nodename_eq_(const void *fdt, int offset, - const char *s, int len) -{ - int olen; - const char *p = fdt_get_name(fdt, offset, &olen); - - if (!p || (fdt_chk_extra() && olen < len)) - /* short match */ - return 0; - - if (memcmp(p, s, len) != 0) - return 0; - - if (p[len] == '\0') - return 1; - else if (!memchr(s, '@', len) && (p[len] == '@')) - return 1; - else - return 0; -} - -const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) -{ - int32_t totalsize; - uint32_t absoffset; - size_t len; - int err; - const char *s, *n; - - if (!fdt_chk_extra()) { - s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; - - if (lenp) - *lenp = strlen(s); - return s; - } - totalsize = fdt_ro_probe_(fdt); - err = totalsize; - if (totalsize < 0) - goto fail; - - err = -FDT_ERR_BADOFFSET; - absoffset = stroffset + fdt_off_dt_strings(fdt); - if (absoffset >= totalsize) - goto fail; - len = totalsize - absoffset; - - if (fdt_magic(fdt) == FDT_MAGIC) { - if (stroffset < 0) - goto fail; - if (!fdt_chk_version() || fdt_version(fdt) >= 17) { - if (stroffset >= fdt_size_dt_strings(fdt)) - goto fail; - if ((fdt_size_dt_strings(fdt) - stroffset) < len) - len = fdt_size_dt_strings(fdt) - stroffset; - } - } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - if ((stroffset >= 0) - || (stroffset < -fdt_size_dt_strings(fdt))) - goto fail; - if ((-stroffset) < len) - len = -stroffset; - } else { - err = -FDT_ERR_INTERNAL; - goto fail; - } - - s = (const char *)fdt + absoffset; - n = memchr(s, '\0', len); - if (!n) { - /* missing terminating NULL */ - err = -FDT_ERR_TRUNCATED; - goto fail; - } - - if (lenp) - *lenp = n - s; - return s; - -fail: - if (lenp) - *lenp = err; - return NULL; -} - -const char *fdt_string(const void *fdt, int stroffset) -{ - return fdt_get_string(fdt, stroffset, NULL); -} - -static int fdt_string_eq_(const void *fdt, int stroffset, - const char *s, int len) -{ - int slen; - const char *p = fdt_get_string(fdt, stroffset, &slen); - - return p && (slen == len) && (memcmp(p, s, len) == 0); -} - -int fdt_find_max_phandle(const void *fdt, uint32_t *phandle) -{ - uint32_t max = 0; - int offset = -1; - - while (true) { - uint32_t value; - - offset = fdt_next_node(fdt, offset, NULL); - if (offset < 0) { - if (offset == -FDT_ERR_NOTFOUND) - break; - - return offset; - } - - value = fdt_get_phandle(fdt, offset); - - if (value > max) - max = value; - } - - if (phandle) - *phandle = max; - - return 0; -} - -int fdt_generate_phandle(const void *fdt, uint32_t *phandle) -{ - uint32_t max; - int err; - - err = fdt_find_max_phandle(fdt, &max); - if (err < 0) - return err; - - if (max == FDT_MAX_PHANDLE) - return -FDT_ERR_NOPHANDLES; - - if (phandle) - *phandle = max + 1; - - return 0; -} - -static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) -{ - int offset = n * sizeof(struct fdt_reserve_entry); - int absoffset = fdt_off_mem_rsvmap(fdt) + offset; - - if (fdt_chk_extra()) { - if (absoffset < fdt_off_mem_rsvmap(fdt)) - return NULL; - if (absoffset > fdt_totalsize(fdt) - - sizeof(struct fdt_reserve_entry)) - return NULL; - } - return fdt_mem_rsv_(fdt, n); -} - -int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) -{ - const struct fdt_reserve_entry *re; - - FDT_RO_PROBE(fdt); - re = fdt_mem_rsv(fdt, n); - if (fdt_chk_extra() && !re) - return -FDT_ERR_BADOFFSET; - - *address = fdt64_to_cpu(re->address); - *size = fdt64_to_cpu(re->size); - return 0; -} - -int fdt_num_mem_rsv(const void *fdt) -{ - int i; - const struct fdt_reserve_entry *re; - - for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { - if (fdt64_to_cpu(re->size) == 0) - return i; - } - return -FDT_ERR_TRUNCATED; -} - -static int nextprop_(const void *fdt, int offset) -{ - uint32_t tag; - int nextoffset; - - do { - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_END: - if (nextoffset >= 0) - return -FDT_ERR_BADSTRUCTURE; - else - return nextoffset; - - case FDT_PROP: - return offset; - } - offset = nextoffset; - } while (tag == FDT_NOP); - - return -FDT_ERR_NOTFOUND; -} - -int fdt_subnode_offset_namelen(const void *fdt, int offset, - const char *name, int namelen) -{ - int depth; - - FDT_RO_PROBE(fdt); - - for (depth = 0; - (offset >= 0) && (depth >= 0); - offset = fdt_next_node(fdt, offset, &depth)) - if ((depth == 1) - && fdt_nodename_eq_(fdt, offset, name, namelen)) - return offset; - - if (depth < 0) - return -FDT_ERR_NOTFOUND; - return offset; /* error */ -} - -int fdt_subnode_offset(const void *fdt, int parentoffset, - const char *name) -{ - return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); -} - -int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) -{ - const char *end = path + namelen; - const char *p = path; - int offset = 0; - - FDT_RO_PROBE(fdt); - - /* see if we have an alias */ - if (*path != '/') { - const char *q = memchr(path, '/', end - p); - - if (!q) - q = end; - - p = fdt_get_alias_namelen(fdt, p, q - p); - if (!p) - return -FDT_ERR_BADPATH; - offset = fdt_path_offset(fdt, p); - - p = q; - } - - while (p < end) { - const char *q; - - while (*p == '/') { - p++; - if (p == end) - return offset; - } - q = memchr(p, '/', end - p); - if (! q) - q = end; - - offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); - if (offset < 0) - return offset; - - p = q; - } - - 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 char *nameptr; - int err; - - if (fdt_chk_extra() && - (((err = fdt_ro_probe_(fdt)) < 0) - || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))) - goto fail; - - nameptr = nh->name; - - if (fdt_chk_version() && fdt_version(fdt) < 0x10) { - /* - * For old FDT versions, match the naming conventions of V16: - * give only the leaf name (after all /). The actual tree - * contents are loosely checked. - */ - const char *leaf; - leaf = strrchr(nameptr, '/'); - if (leaf == NULL) { - err = -FDT_ERR_BADSTRUCTURE; - goto fail; - } - nameptr = leaf+1; - } - - if (len) - *len = strlen(nameptr); - - return nameptr; - - fail: - if (len) - *len = err; - return NULL; -} - -int fdt_first_property_offset(const void *fdt, int nodeoffset) -{ - int offset; - - if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) - return offset; - - return nextprop_(fdt, offset); -} - -int fdt_next_property_offset(const void *fdt, int offset) -{ - if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) - return offset; - - return nextprop_(fdt, offset); -} - -static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, - int offset, - int *lenp) -{ - int err; - const struct fdt_property *prop; - - if (fdt_chk_basic() && (err = fdt_check_prop_offset_(fdt, offset)) < 0) { - if (lenp) - *lenp = err; - return NULL; - } - - prop = fdt_offset_ptr_(fdt, offset); - - if (lenp) - *lenp = fdt32_to_cpu(prop->len); - - return prop; -} - -const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp) -{ - /* Prior to version 16, properties may need realignment - * and this API does not work. fdt_getprop_*() will, however. */ - - if (fdt_chk_version() && fdt_version(fdt) < 0x10) { - if (lenp) - *lenp = -FDT_ERR_BADVERSION; - return NULL; - } - - return fdt_get_property_by_offset_(fdt, offset, lenp); -} - -static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, - int offset, - const char *name, - int namelen, - int *lenp, - int *poffset) -{ - for (offset = fdt_first_property_offset(fdt, offset); - (offset >= 0); - (offset = fdt_next_property_offset(fdt, offset))) { - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset_(fdt, offset, lenp); - if (fdt_chk_extra() && !prop) { - offset = -FDT_ERR_INTERNAL; - break; - } - if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), - name, namelen)) { - if (poffset) - *poffset = offset; - return prop; - } - } - - if (lenp) - *lenp = offset; - return NULL; -} - - -const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int offset, - const char *name, - int namelen, int *lenp) -{ - /* Prior to version 16, properties may need realignment - * and this API does not work. fdt_getprop_*() will, however. */ - if (fdt_chk_version() && fdt_version(fdt) < 0x10) { - if (lenp) - *lenp = -FDT_ERR_BADVERSION; - return NULL; - } - - return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp, - NULL); -} - - -const struct fdt_property *fdt_get_property(const void *fdt, - int nodeoffset, - const char *name, int *lenp) -{ - return fdt_get_property_namelen(fdt, nodeoffset, name, - strlen(name), lenp); -} - -const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp) -{ - int poffset; - const struct fdt_property *prop; - - prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, - &poffset); - if (!prop) - return NULL; - - /* Handle realignment */ - if (fdt_chk_version() && fdt_version(fdt) < 0x10 && - (poffset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8) - return prop->data + 4; - return prop->data; -} - -const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset_(fdt, offset, lenp); - if (!prop) - return NULL; - if (namep) { - const char *name; - int namelen; - - if (fdt_chk_extra()) { - name = fdt_get_string(fdt, fdt32_to_cpu(prop->nameoff), - &namelen); - if (!name) { - if (lenp) - *lenp = namelen; - return NULL; - } - *namep = name; - } else { - *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - } - } - - /* Handle realignment */ - if (fdt_chk_version() && fdt_version(fdt) < 0x10 && - (offset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8) - return prop->data + 4; - return prop->data; -} - -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp) -{ - return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); -} - -uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) -{ - const fdt32_t *php; - int len; - - /* FIXME: This is a bit sub-optimal, since we potentially scan - * over all the properties twice. */ - php = fdt_getprop(fdt, nodeoffset, "phandle", &len); - if (!php || (len != sizeof(*php))) { - php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); - if (!php || (len != sizeof(*php))) - return 0; - } - - return fdt32_to_cpu(*php); -} - -const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen) -{ - int aliasoffset; - - aliasoffset = fdt_path_offset(fdt, "/aliases"); - if (aliasoffset < 0) - return NULL; - - return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); -} - -const char *fdt_get_alias(const void *fdt, const char *name) -{ - return fdt_get_alias_namelen(fdt, name, strlen(name)); -} - -int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) -{ - int pdepth = 0, p = 0; - int offset, depth, namelen; - const char *name; - - FDT_RO_PROBE(fdt); - - if (buflen < 2) - return -FDT_ERR_NOSPACE; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - while (pdepth > depth) { - do { - p--; - } while (buf[p-1] != '/'); - pdepth--; - } - - if (pdepth >= depth) { - name = fdt_get_name(fdt, offset, &namelen); - if (!name) - return namelen; - if ((p + namelen + 1) <= buflen) { - memcpy(buf + p, name, namelen); - p += namelen; - buf[p++] = '/'; - pdepth++; - } - } - - if (offset == nodeoffset) { - if (pdepth < (depth + 1)) - return -FDT_ERR_NOSPACE; - - if (p > 1) /* special case so that root path is "/", not "" */ - p--; - buf[p] = '\0'; - return 0; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ -} - -int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth) -{ - int offset, depth; - int supernodeoffset = -FDT_ERR_INTERNAL; - - FDT_RO_PROBE(fdt); - - if (supernodedepth < 0) - return -FDT_ERR_NOTFOUND; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - if (depth == supernodedepth) - supernodeoffset = offset; - - if (offset == nodeoffset) { - if (nodedepth) - *nodedepth = depth; - - if (supernodedepth > depth) - return -FDT_ERR_NOTFOUND; - else - return supernodeoffset; - } - } - - if (fdt_chk_extra()) { - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_node_depth(const void *fdt, int nodeoffset) -{ - int nodedepth; - int err; - - err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); - if (err) - return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL; - return nodedepth; -} - -int fdt_parent_offset(const void *fdt, int nodeoffset) -{ - int nodedepth = fdt_node_depth(fdt, nodeoffset); - - if (nodedepth < 0) - return nodedepth; - return fdt_supernode_atdepth_offset(fdt, nodeoffset, - nodedepth - 1, NULL); -} - -int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen) -{ - int offset; - const void *val; - int len; - - FDT_RO_PROBE(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_getprop(), then if that didn't - * find what we want, we scan over them again making our way - * to the next node. Still it's the easiest to implement - * approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - val = fdt_getprop(fdt, offset, propname, &len); - if (val && (len == proplen) - && (memcmp(val, propval, len) == 0)) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) -{ - int offset; - - if ((phandle == 0) || (phandle == -1)) - return -FDT_ERR_BADPHANDLE; - - FDT_RO_PROBE(fdt); - - /* FIXME: The algorithm here is pretty horrible: we - * potentially scan each property of a node in - * fdt_get_phandle(), then if that didn't find what - * we want, we scan over them again making our way to the next - * node. Still it's the easiest to implement approach; - * performance can come later. */ - for (offset = fdt_next_node(fdt, -1, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - if (fdt_get_phandle(fdt, offset) == phandle) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) -{ - int len = strlen(str); - const char *p; - - while (listlen >= len) { - if (memcmp(str, strlist, len+1) == 0) - return 1; - p = memchr(strlist, '\0', listlen); - if (!p) - return 0; /* malformed strlist.. */ - listlen -= (p-strlist) + 1; - strlist = p + 1; - } - return 0; -} - -int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) -{ - const char *list, *end; - int length, count = 0; - - list = fdt_getprop(fdt, nodeoffset, property, &length); - if (!list) - return length; - - 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) - return -FDT_ERR_BADVALUE; - - list += length; - count++; - } - - return count; -} - -int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, - const char *string) -{ - int length, len, idx = 0; - const char *list, *end; - - list = fdt_getprop(fdt, nodeoffset, property, &length); - if (!list) - return length; - - len = strlen(string) + 1; - 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) - return -FDT_ERR_BADVALUE; - - if (length == len && memcmp(list, string, length) == 0) - return idx; - - 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) -{ - const void *prop; - int len; - - prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); - if (!prop) - return len; - - return !fdt_stringlist_contains(prop, len, compatible); -} - -int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible) -{ - int offset, err; - - FDT_RO_PROBE(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_node_check_compatible(), then if - * that didn't find what we want, we scan over them again - * making our way to the next node. Still it's the easiest to - * implement approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - err = fdt_node_check_compatible(fdt, offset, compatible); - if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) - return err; - else if (err == 0) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -#if !defined(CHECK_LEVEL) || CHECK_LEVEL > 0 -int fdt_check_full(const void *fdt, size_t bufsize) -{ - int err; - int num_memrsv; - int offset, nextoffset = 0; - uint32_t tag; - unsigned depth = 0; - const void *prop; - const char *propname; - - if (bufsize < FDT_V1_SIZE) - return -FDT_ERR_TRUNCATED; - err = fdt_check_header(fdt); - if (err != 0) - return err; - if (bufsize < fdt_totalsize(fdt)) - return -FDT_ERR_TRUNCATED; - - num_memrsv = fdt_num_mem_rsv(fdt); - if (num_memrsv < 0) - return num_memrsv; - - while (1) { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - if (nextoffset < 0) - return nextoffset; - - switch (tag) { - case FDT_NOP: - break; - - case FDT_END: - if (depth != 0) - return -FDT_ERR_BADSTRUCTURE; - return 0; - - case FDT_BEGIN_NODE: - depth++; - if (depth > INT_MAX) - return -FDT_ERR_BADSTRUCTURE; - break; - - case FDT_END_NODE: - if (depth == 0) - return -FDT_ERR_BADSTRUCTURE; - depth--; - break; - - case FDT_PROP: - prop = fdt_getprop_by_offset(fdt, offset, &propname, - &err); - if (!prop) - return err; - break; - - default: - return -FDT_ERR_INTERNAL; - } - } -} -#endif +#include "../../scripts/dtc/libfdt/fdt_ro.c" |