From: Masahiro Yamada Date: Thu, 16 Apr 2020 09:30:17 +0000 (+0900) Subject: fdt_region: move fdt_region.c to common/ from lib/libfdt/ X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=3e69db1223b9db82705fcc96b76caf0d8a468d12;p=u-boot.git fdt_region: move fdt_region.c to common/ from lib/libfdt/ My goal is to sync lib/libfdt/ with scripts/dtc/libfdt/, that is, make lib/libfdt/ contain only wrapper files. fdt_region.c was written only for U-Boot to implement the verified boot. So, this belongs to the same group as common/fdt_support.c, which is a collection of U-Boot own fdt helpers. Move lib/libfdt/fdt_region.c to common/fdt_region.c . This is necessary only when CONFIG_(SPL_TPL_)_FIT_SIGNATURE is enabled. Signed-off-by: Masahiro Yamada --- diff --git a/common/Makefile b/common/Makefile index 3471c47be5..2e7a090588 100644 --- a/common/Makefile +++ b/common/Makefile @@ -110,6 +110,7 @@ obj-y += image.o obj-$(CONFIG_ANDROID_AB) += android_ab.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o +obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o obj-$(CONFIG_$(SPL_)MULTI_DTB_FIT) += boot_fit.o common_fit.o obj-$(CONFIG_$(SPL_TPL_)IMAGE_SIGN_INFO) += image-sig.o diff --git a/lib/libfdt/Makefile b/lib/libfdt/Makefile index 878659f99e..1fe50ecbe5 100644 --- a/lib/libfdt/Makefile +++ b/lib/libfdt/Makefile @@ -15,8 +15,5 @@ obj-y += \ obj-$(CONFIG_OF_LIBFDT_OVERLAY) += fdt_overlay.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 - */ - -#include - -#ifndef USE_HOSTCC -#include -#include -#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/tools/Makefile b/tools/Makefile index 1f7d4d1fae..1f9144f028 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -63,13 +63,8 @@ FIT_CIPHER_OBJS-$(CONFIG_FIT_CIPHER) := common/image-cipher.o # The following files are synced with upstream DTC. # Use synced versions from scripts/dtc/libfdt/. -LIBFDT_SRCS_SYNCED := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c \ - fdt_strerror.c fdt_empty_tree.c fdt_addresses.c fdt_overlay.c -# Use U-Boot own versions from lib/libfdt/. -LIBFDT_SRCS_UNSYNCED := fdt_region.c - -LIBFDT_OBJS := $(addprefix libfdt/, $(patsubst %.c, %.o, $(LIBFDT_SRCS_SYNCED))) \ - $(addprefix lib/libfdt/, $(patsubst %.c, %.o, $(LIBFDT_SRCS_UNSYNCED))) +LIBFDT_OBJS := $(addprefix libfdt/, fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o \ + fdt_strerror.o fdt_empty_tree.o fdt_addresses.o fdt_overlay.o) RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \ rsa-sign.o rsa-verify.o rsa-checksum.o \ @@ -86,6 +81,7 @@ dumpimage-mkimage-objs := aisimage.o \ $(FIT_OBJS-y) \ $(FIT_SIG_OBJS-y) \ $(FIT_CIPHER_OBJS-y) \ + common/fdt_region.o \ common/bootm.o \ lib/crc32.o \ default_image.o \ @@ -210,7 +206,7 @@ hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela hostprogs-$(CONFIG_RISCV) += prelink-riscv hostprogs-y += fdtgrep -fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o +fdtgrep-objs += $(LIBFDT_OBJS) common/fdt_region.o fdtgrep.o ifneq ($(TOOLS_ONLY),y) hostprogs-y += spl_size_limit