Re: [PATCH 4/6] libfdt: overlay: Ignore unresolved symbols during overlay

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



On Fri, Mar 16, 2018 at 06:38:19PM +0530, Srivatsa Vaddagiri wrote:
> When overlaying onto a base blob which itself has unresolved symbols as
> mentioned in its __fixups__ section, its possible that not all external
> references specified in overlay blob's __fixups__ section are satisfied by base
> blob. Ignore such unresolved references (rather than aborting the whole overlay
> process upon the first instance of unresolved symbol found).
> 
> Further for any external reference satisfied by base blob, delete the external
> reference found in overlay blob's __fixups__ section and add that reference in
> __local_fixups__ section of base blob. This will be because __fixups__ section
> of both blobs will need to be merged eventually and need to reflect only
> unresolved external references of the combined blob.
> 
> Signed-off-by: Srivatsa Vaddagiri <vatsa@xxxxxxxxxxxxxx>

I could go through with detailed comments here, but at this point I
don't think it's worth it.  These patches need a *lot* of work before
they're ready.

Please at least fix the following, then repost for another round of
review:
    * Use a separate entry point for overlay merging
    * Don't rely on malloc() / realloc()
    * Don't use global variables

> ---
>  libfdt/fdt_overlay.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 250 insertions(+), 6 deletions(-)
> 
> diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c
> index 556551e..560bb27 100644
> --- a/libfdt/fdt_overlay.c
> +++ b/libfdt/fdt_overlay.c
> @@ -145,6 +145,46 @@ static int fdt_set_name_memcheck(void **fdt, int offset,
>  	return fdt_set_name(*fdt, offset, name);
>  }
>  
> +static int new_node_len(const char *name)
> +{
> +        /* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
> +        return sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
> +                        + FDT_TAGSIZE;
> +}
> +
> +static int fdt_add_subnode_memcheck(void **fdt, int nodeoffset,
> +						const char *nodename)
> +{
> +	int offset;
> +
> +	offset = fdt_add_subnode(*fdt, nodeoffset, nodename);
> +	if (offset > 0)
> +		return offset;
> +
> +	if (offset < 0 && offset != -FDT_ERR_NOSPACE)
> +		return offset;
> +
> +	*fdt = realloc_fdt(*fdt, new_node_len(nodename));
> +
> +	return fdt_add_subnode(*fdt, nodeoffset, nodename);
> +}
> +
> +static int fdt_setprop_u32_memcheck(void **fdt, int offset,
> +				const char *propname, int proplen, uint32_t val)
> +{
> +	int err;
> +
> +	err = fdt_setprop_u32(*fdt, offset, propname, val);
> +	if (!err)
> +		return 0;
> +
> +	if (err != -FDT_ERR_NOSPACE)
> +		return err;
> +
> +	*fdt = realloc_fdt(*fdt, proplen);
> +	return fdt_setprop_u32(*fdt, offset, propname, val);
> +}
> +
>  /**
>   * fdt_setprop_placeholder_memcheck - Set property value
>   *
> @@ -573,6 +613,207 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto,
>  						   sizeof(phandle_prop));
>  };
>  
> +char **del_property;
> +int del_prop_size = 100 * sizeof(char *);
> +int del_idx;
> +
> +/*
> + * In case of base blob itself having unresolved external references (non-empty
> + * fixup section), we want to merge the fixup sections of all blobs, excluding
> + * those entries that could be resolved during overlay process.
> + * 'mark_for_deletion' marks those properties in fixup section that were
> + * successfully resolved. 'delete_fixed_properties' removes the resolved entries
> + * from 'fixup' section of overlay blob (so that when we finally merge 'fixups'
> + * sections of all blobs, the resolved entries don't appear in final fixups
> + * section) and adds them to 'local_fixup' section of base blob
> + */
> +static int delete_fixed_properties(void **fdt, void *fdto, int fixups_off)
> +{
> +	int idx, localfixup_off, rc, del_prop = 0;
> +
> +	localfixup_off = fdt_path_offset(*fdt, "/__local_fixups__");
> +	if ((localfixup_off < 0 && (localfixup_off != -FDT_ERR_NOTFOUND))) {
> +		rc = localfixup_off;
> +		goto cleanup;
> +	}
> +
> +	if (localfixup_off == -FDT_ERR_NOTFOUND) {
> +		localfixup_off = fdt_add_subnode_memcheck(fdt, 0, "__local_fixups__");
> +		if (localfixup_off < 0) {
> +			rc = localfixup_off;
> +			goto cleanup;
> +		}
> +	}
> +
> +	for (idx = 0; idx < del_idx; ++idx) {
> +		const char *value;
> +		int len, pathlen, proplen;
> +
> +		value = fdt_getprop(fdto, fixups_off, del_property[idx], &len);
> +		if (!value) {
> +			rc = len;
> +			goto cleanup;
> +		}
> +
> +		/*
> +		 * Properties found in __fixups__ section are typically one of
> +		 * these:
> +		 *
> +		 * 	abc = "/fragment@2:target:0";	OR
> +		 *	abc = "/fragment@2/__overlay__:xyz:0"
> +		 *
> +		 * Only in case of latter, we would have inserted a phandle
> +		 * reference in some node's property, which needs to be
> +		 * reflected in combined blob's __local_fixup__ section
> +		 */
> +
> +		dprintf("property %s is being added to local_fixups\n",
> +							del_property[idx]);
> +		while (len > 0) {
> +			const char *path, *fixup_end, *prop;
> +			const char *fixup_str = value;
> +			uint32_t clen;
> +			uint32_t fixup_len;
> +			char *sep, *endptr;
> +			const char *c;
> +			int poffset;
> +			int nodeoffset;
> +			char propname[PATH_MAX];
> +
> +			fixup_end = memchr(value, '\0', len);
> +			if (!fixup_end)
> +				break;
> +
> +			fixup_len = fixup_end - fixup_str;
> +
> +			len -= (fixup_len + 1);
> +			value += fixup_len + 1;
> +
> +			c = path = fixup_str;
> +			sep = memchr(c, ':', fixup_len);
> +			if (!sep || *sep != ':') {
> +				rc = -FDT_ERR_BADOVERLAY;
> +				goto cleanup;
> +			}
> +			pathlen = sep - path;
> +			if (pathlen == (fixup_len - 1)) {
> +				rc = -FDT_ERR_BADOVERLAY;
> +				goto cleanup;
> +			}
> +
> +			fixup_len -= (pathlen + 1);
> +			c = path + pathlen + 1;
> +
> +			sep = memchr(c, ':', fixup_len);
> +			if (!sep || *sep != ':') {
> +				rc = -FDT_ERR_BADOVERLAY;
> +				goto cleanup;
> +			}
> +
> +			prop = c;
> +			proplen = sep - c;
> +
> +			if (proplen >= PATH_MAX) {
> +				rc = -FDT_ERR_BADOVERLAY;
> +				goto cleanup;
> +			}
> +
> +			if (!strncmp(prop, "target", proplen))
> +				continue;
> +
> +			memcpy(propname, prop, proplen);
> +			propname[proplen] = 0;
> +
> +			fixup_len -= (proplen + 1);
> +			c = prop + proplen + 1;
> +			poffset = strtoul(c, &endptr, 10);
> +
> +			nodeoffset = localfixup_off;
> +
> +			c = path;
> +			clen = pathlen;
> +
> +			if (*c == '/') {
> +				c++;
> +				clen -= 1;
> +			}
> +
> +			while (clen > 0) {
> +				char nodename[PATH_MAX];
> +				int nodelen;
> +
> +				sep = memchr(c, '/', clen);
> +				if (!sep)
> +					nodelen = clen;
> +				else
> +					nodelen = sep - c;
> +
> +				if (nodelen + 1 >= PATH_MAX) {
> +					dprintf("Very large node name %s\n", c);
> +					rc = -FDT_ERR_BADSTRUCTURE;
> +					goto cleanup;
> +				}
> +				memcpy(nodename, c, nodelen);
> +				nodename[nodelen] = 0;
> +
> +				nodeoffset = fdt_add_subnode_memcheck(fdt, nodeoffset, nodename);
> +				if (nodeoffset < 0) {
> +					rc = nodeoffset;
> +					goto cleanup;
> +				}
> +
> +				c += nodelen;
> +				clen -= nodelen;
> +
> +				if (*c == '/') {
> +					c++;
> +					clen -= 1;
> +				}
> +			}
> +
> +			rc = fdt_setprop_u32_memcheck(fdt, nodeoffset, propname, proplen, poffset);
> +			if (rc < 0)
> +				goto cleanup;
> +		}
> +	}
> +
> +	del_prop = 1;
> +	rc = 0;
> +
> +cleanup:
> +	for (idx = 0; idx < del_idx; ++idx) {
> +		if (del_prop)
> +			rc = fdt_delprop(fdto, fixups_off, del_property[idx]);
> +
> +		free(del_property[idx]);
> +	}
> +
> +	/* Reset index before the next blob gets overlaid */
> +	del_idx = 0;
> +
> +	return rc;
> +}
> +
> +static void mark_for_deletion(const char *name)
> +{
> +	int len = strlen(name) + 1;
> +
> +	if (!del_property)
> +		del_property = xmalloc(del_prop_size);
> +
> +	/*
> +	 * Perhaps we can note down the offset of prop to be deleted rather than
> +	 * its name? Will avoid the need for malloc()
> +	 */
> +	del_property[del_idx] = xmalloc(len);
> +	memcpy(del_property[del_idx], name, len);
> +
> +	if (++del_idx >= del_prop_size/sizeof(char *)) {
> +		del_property = xrealloc(del_property, del_prop_size + 512);
> +		del_prop_size += 512;
> +	}
> +}
> +
>  /**
>   * overlay_fixup_phandle - Set an overlay phandle to the base one
>   * @fdt: Base Device Tree blob
> @@ -654,6 +895,9 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
>  			return ret;
>  	} while (len > 0);
>  
> +	if (base_has_fixups)
> +		mark_for_deletion(label);
> +
>  	return 0;
>  }
>  
> @@ -674,7 +918,7 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
>   *      0 on success
>   *      Negative error code on failure
>   */
> -static int overlay_fixup_phandles(void *fdt, void *fdto)
> +static int overlay_fixup_phandles(void **fdt, void *fdto)
>  {
>  	int fixups_off, symbols_off;
>  	int property;
> @@ -687,19 +931,19 @@ static int overlay_fixup_phandles(void *fdt, void *fdto)
>  		return fixups_off;
>  
>  	/* And base DTs without symbols */
> -	symbols_off = fdt_path_offset(fdt, "/__symbols__");
> +	symbols_off = fdt_path_offset(*fdt, "/__symbols__");
>  	if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
>  		return symbols_off;
>  
>  	fdt_for_each_property_offset(property, fdto, fixups_off) {
>  		int ret;
>  
> -		ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
> -		if (ret)
> +		ret = overlay_fixup_phandle(*fdt, fdto, symbols_off, property);
> +		if (ret && (!base_has_fixups || ret != -FDT_ERR_NOTFOUND))
>  			return ret;
>  	}
>  
> -	return 0;
> +	return delete_fixed_properties(fdt, fdto, fixups_off);
>  }
>  
>  /**
> @@ -1283,7 +1527,7 @@ int fdt_overlay_apply(void **fdt, void **fdto)
>  		goto err;
>  
>  	dprintf("Fixing phandles\n");
> -	ret = overlay_fixup_phandles(*fdt, *fdto);
> +	ret = overlay_fixup_phandles(fdt, *fdto);
>  	if (ret)
>  		goto err;
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Device Tree]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux