fdt: Sync up to the latest libfdt
Bring over the fdt from this commit: 430419c (origin/master) tests: fix some python warnings adding in the 'assumptions' series designed to reduce code size. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
		
							parent
							
								
									e9bae5c534
								
							
						
					
					
						commit
						f0921f5098
					
				|  | @ -14,12 +14,13 @@ | ||||||
| 
 | 
 | ||||||
| #include "libfdt_internal.h" | #include "libfdt_internal.h" | ||||||
| 
 | 
 | ||||||
| static int _fdt_nodename_eq(const void *fdt, int offset, | static int fdt_nodename_eq_(const void *fdt, int offset, | ||||||
| 			    const char *s, int len) | 			    const char *s, int len) | ||||||
| { | { | ||||||
| 	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); | 	int olen; | ||||||
|  | 	const char *p = fdt_get_name(fdt, offset, &olen); | ||||||
| 
 | 
 | ||||||
| 	if (!p) | 	if (!p || (fdt_chk_extra() && olen < len)) | ||||||
| 		/* short match */ | 		/* short match */ | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
|  | @ -34,46 +35,85 @@ static int _fdt_nodename_eq(const void *fdt, int offset, | ||||||
| 		return 0; | 		return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char *fdt_string(const void *fdt, int stroffset) | const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) | ||||||
| { | { | ||||||
| 	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; | 	int32_t totalsize; | ||||||
| } | 	uint32_t absoffset; | ||||||
|  | 	size_t len; | ||||||
|  | 	int err; | ||||||
|  | 	const char *s, *n; | ||||||
| 
 | 
 | ||||||
| static int _fdt_string_eq(const void *fdt, int stroffset, | 	if (!fdt_chk_extra()) { | ||||||
| 			  const char *s, int len) | 		s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; | ||||||
| { |  | ||||||
| 	const char *p = fdt_string(fdt, stroffset); |  | ||||||
| 
 | 
 | ||||||
| 	return (strnlen(p, len + 1) == len) && (memcmp(p, s, len) == 0); | 		if (lenp) | ||||||
| } | 			*lenp = strlen(s); | ||||||
|  | 		return s; | ||||||
|  | 	} | ||||||
|  | 	totalsize = fdt_ro_probe_(fdt); | ||||||
|  | 	err = totalsize; | ||||||
|  | 	if (totalsize < 0) | ||||||
|  | 		goto fail; | ||||||
| 
 | 
 | ||||||
| uint32_t fdt_get_max_phandle(const void *fdt) | 	err = -FDT_ERR_BADOFFSET; | ||||||
| { | 	absoffset = stroffset + fdt_off_dt_strings(fdt); | ||||||
| 	uint32_t max_phandle = 0; | 	if (absoffset >= totalsize) | ||||||
| 	int offset; | 		goto fail; | ||||||
|  | 	len = totalsize - absoffset; | ||||||
| 
 | 
 | ||||||
| 	for (offset = fdt_next_node(fdt, -1, NULL);; | 	if (fdt_magic(fdt) == FDT_MAGIC) { | ||||||
| 	     offset = fdt_next_node(fdt, offset, NULL)) { | 		if (stroffset < 0) | ||||||
| 		uint32_t phandle; | 			goto fail; | ||||||
| 
 | 		if (!fdt_chk_version() || fdt_version(fdt) >= 17) { | ||||||
| 		if (offset == -FDT_ERR_NOTFOUND) | 			if (stroffset >= fdt_size_dt_strings(fdt)) | ||||||
| 			return max_phandle; | 				goto fail; | ||||||
| 
 | 			if ((fdt_size_dt_strings(fdt) - stroffset) < len) | ||||||
| 		if (offset < 0) | 				len = fdt_size_dt_strings(fdt) - stroffset; | ||||||
| 			return (uint32_t)-1; | 		} | ||||||
| 
 | 	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) { | ||||||
| 		phandle = fdt_get_phandle(fdt, offset); | 		if ((stroffset >= 0) | ||||||
| 		if (phandle == (uint32_t)-1) | 		    || (stroffset < -fdt_size_dt_strings(fdt))) | ||||||
| 			continue; | 			goto fail; | ||||||
| 
 | 		if ((-stroffset) < len) | ||||||
| 		if (phandle > max_phandle) | 			len = -stroffset; | ||||||
| 			max_phandle = phandle; | 	} else { | ||||||
|  | 		err = -FDT_ERR_INTERNAL; | ||||||
|  | 		goto fail; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	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; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int fdt_generate_phandle(const void *fdt, uint32_t *phandle) | 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; | 	uint32_t max = 0; | ||||||
| 	int offset = -1; | 	int offset = -1; | ||||||
|  | @ -95,6 +135,21 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle) | ||||||
| 			max = value; | 			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) | 	if (max == FDT_MAX_PHANDLE) | ||||||
| 		return -FDT_ERR_NOPHANDLES; | 		return -FDT_ERR_NOPHANDLES; | ||||||
| 
 | 
 | ||||||
|  | @ -104,24 +159,48 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle) | ||||||
| 	return 0; | 	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) | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) | ||||||
| { | { | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	const struct fdt_reserve_entry *re; | ||||||
| 	*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address); | 
 | ||||||
| 	*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); | 	FDT_RO_PROBE(fdt); | ||||||
|  | 	re = fdt_mem_rsv(fdt, n); | ||||||
|  | 	if (fdt_chk_extra() && !re) | ||||||
|  | 		return -FDT_ERR_BADOFFSET; | ||||||
|  | 
 | ||||||
|  | 	*address = fdt64_ld(&re->address); | ||||||
|  | 	*size = fdt64_ld(&re->size); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int fdt_num_mem_rsv(const void *fdt) | int fdt_num_mem_rsv(const void *fdt) | ||||||
| { | { | ||||||
| 	int i = 0; | 	int i; | ||||||
|  | 	const struct fdt_reserve_entry *re; | ||||||
| 
 | 
 | ||||||
| 	while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0) | 	for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { | ||||||
| 		i++; | 		if (fdt64_ld(&re->size) == 0) | ||||||
| 	return i; | 			return i; | ||||||
|  | 	} | ||||||
|  | 	return -FDT_ERR_TRUNCATED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int _nextprop(const void *fdt, int offset) | static int nextprop_(const void *fdt, int offset) | ||||||
| { | { | ||||||
| 	uint32_t tag; | 	uint32_t tag; | ||||||
| 	int nextoffset; | 	int nextoffset; | ||||||
|  | @ -150,13 +229,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, | ||||||
| { | { | ||||||
| 	int depth; | 	int depth; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	for (depth = 0; | 	for (depth = 0; | ||||||
| 	     (offset >= 0) && (depth >= 0); | 	     (offset >= 0) && (depth >= 0); | ||||||
| 	     offset = fdt_next_node(fdt, offset, &depth)) | 	     offset = fdt_next_node(fdt, offset, &depth)) | ||||||
| 		if ((depth == 1) | 		if ((depth == 1) | ||||||
| 		    && _fdt_nodename_eq(fdt, offset, name, namelen)) | 		    && fdt_nodename_eq_(fdt, offset, name, namelen)) | ||||||
| 			return offset; | 			return offset; | ||||||
| 
 | 
 | ||||||
| 	if (depth < 0) | 	if (depth < 0) | ||||||
|  | @ -170,36 +249,17 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, | ||||||
| 	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); | 	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * 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) | int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) | ||||||
| { | { | ||||||
| 	const char *end = path + namelen; | 	const char *end = path + namelen; | ||||||
| 	const char *p = path; | 	const char *p = path; | ||||||
| 	int offset = 0; | 	int offset = 0; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* see if we have an alias */ | 	/* see if we have an alias */ | ||||||
| 	if (*path != '/') { | 	if (*path != '/') { | ||||||
| 		const char *q = fdt_path_next_separator(path, namelen); | 		const char *q = memchr(path, '/', end - p); | ||||||
| 
 | 
 | ||||||
| 		if (!q) | 		if (!q) | ||||||
| 			q = end; | 			q = end; | ||||||
|  | @ -212,17 +272,16 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) | ||||||
| 		p = q; | 		p = q; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	while (*p && (p < end)) { | 	while (p < end) { | ||||||
| 		const char *q; | 		const char *q; | ||||||
| 
 | 
 | ||||||
| 		while (*p == '/') | 		while (*p == '/') { | ||||||
| 			p++; | 			p++; | ||||||
| 
 | 			if (p == end) | ||||||
| 		if (*p == '\0' || *p == ':') | 				return offset; | ||||||
| 			return offset; | 		} | ||||||
| 
 | 		q = memchr(p, '/', end - p); | ||||||
| 		q = fdt_path_next_separator(p, end - p); | 		if (! q) | ||||||
| 		if (!q) |  | ||||||
| 			q = end; | 			q = end; | ||||||
| 
 | 
 | ||||||
| 		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); | 		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); | ||||||
|  | @ -243,16 +302,35 @@ int fdt_path_offset(const void *fdt, const char *path) | ||||||
| const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) | 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_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); | ||||||
|  | 	const char *nameptr; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	if (((err = fdt_check_header(fdt)) != 0) | 	if (fdt_chk_extra() && | ||||||
| 	    || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) | 	    (((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; | 			goto fail; | ||||||
|  | 		} | ||||||
|  | 		nameptr = leaf+1; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (len) | 	if (len) | ||||||
| 		*len = strlen(nh->name); | 		*len = strlen(nameptr); | ||||||
| 
 | 
 | ||||||
| 	return nh->name; | 	return nameptr; | ||||||
| 
 | 
 | ||||||
|  fail: |  fail: | ||||||
| 	if (len) | 	if (len) | ||||||
|  | @ -267,7 +345,7 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset) | ||||||
| 	if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) | 	if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) | ||||||
| 		return offset; | 		return offset; | ||||||
| 
 | 
 | ||||||
| 	return _nextprop(fdt, offset); | 	return nextprop_(fdt, offset); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int fdt_next_property_offset(const void *fdt, int offset) | int fdt_next_property_offset(const void *fdt, int offset) | ||||||
|  | @ -275,17 +353,17 @@ int fdt_next_property_offset(const void *fdt, int offset) | ||||||
| 	if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) | 	if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) | ||||||
| 		return offset; | 		return offset; | ||||||
| 
 | 
 | ||||||
| 	return _nextprop(fdt, offset); | 	return nextprop_(fdt, offset); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const struct fdt_property *fdt_get_property_by_offset(const void *fdt, | static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, | ||||||
| 						      int offset, | 						              int offset, | ||||||
| 						      int *lenp) | 						              int *lenp) | ||||||
| { | { | ||||||
| 	int err; | 	int err; | ||||||
| 	const struct fdt_property *prop; | 	const struct fdt_property *prop; | ||||||
| 
 | 
 | ||||||
| 	if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) { | 	if (fdt_chk_basic() && (err = fdt_check_prop_offset_(fdt, offset)) < 0) { | ||||||
| 		if (lenp) | 		if (lenp) | ||||||
| 			*lenp = err; | 			*lenp = err; | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -294,28 +372,50 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, | ||||||
| 	prop = fdt_offset_ptr_(fdt, offset); | 	prop = fdt_offset_ptr_(fdt, offset); | ||||||
| 
 | 
 | ||||||
| 	if (lenp) | 	if (lenp) | ||||||
| 		*lenp = fdt32_to_cpu(prop->len); | 		*lenp = fdt32_ld(&prop->len); | ||||||
| 
 | 
 | ||||||
| 	return prop; | 	return prop; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const struct fdt_property *fdt_get_property_namelen(const void *fdt, | const struct fdt_property *fdt_get_property_by_offset(const void *fdt, | ||||||
| 						    int offset, | 						      int offset, | ||||||
| 						    const char *name, | 						      int *lenp) | ||||||
| 						    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_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); | 	for (offset = fdt_first_property_offset(fdt, offset); | ||||||
| 	     (offset >= 0); | 	     (offset >= 0); | ||||||
| 	     (offset = fdt_next_property_offset(fdt, offset))) { | 	     (offset = fdt_next_property_offset(fdt, offset))) { | ||||||
| 		const struct fdt_property *prop; | 		const struct fdt_property *prop; | ||||||
| 
 | 
 | ||||||
| 		if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { | 		prop = fdt_get_property_by_offset_(fdt, offset, lenp); | ||||||
|  | 		if (fdt_chk_extra() && !prop) { | ||||||
| 			offset = -FDT_ERR_INTERNAL; | 			offset = -FDT_ERR_INTERNAL; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), | 		if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), | ||||||
| 				   name, namelen)) | 				   name, namelen)) { | ||||||
|  | 			if (poffset) | ||||||
|  | 				*poffset = offset; | ||||||
| 			return prop; | 			return prop; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (lenp) | 	if (lenp) | ||||||
|  | @ -323,6 +423,25 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, | ||||||
| 	return NULL; | 	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, | const struct fdt_property *fdt_get_property(const void *fdt, | ||||||
| 					    int nodeoffset, | 					    int nodeoffset, | ||||||
| 					    const char *name, int *lenp) | 					    const char *name, int *lenp) | ||||||
|  | @ -334,12 +453,18 @@ const struct fdt_property *fdt_get_property(const void *fdt, | ||||||
| const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, | const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, | ||||||
| 				const char *name, int namelen, int *lenp) | 				const char *name, int namelen, int *lenp) | ||||||
| { | { | ||||||
|  | 	int poffset; | ||||||
| 	const struct fdt_property *prop; | 	const struct fdt_property *prop; | ||||||
| 
 | 
 | ||||||
| 	prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); | 	prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, | ||||||
|  | 					 &poffset); | ||||||
| 	if (!prop) | 	if (!prop) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
|  | 	/* Handle realignment */ | ||||||
|  | 	if (fdt_chk_version() && fdt_version(fdt) < 0x10 && | ||||||
|  | 	    (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) | ||||||
|  | 		return prop->data + 4; | ||||||
| 	return prop->data; | 	return prop->data; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -348,11 +473,31 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, | ||||||
| { | { | ||||||
| 	const struct fdt_property *prop; | 	const struct fdt_property *prop; | ||||||
| 
 | 
 | ||||||
| 	prop = fdt_get_property_by_offset(fdt, offset, lenp); | 	prop = fdt_get_property_by_offset_(fdt, offset, lenp); | ||||||
| 	if (!prop) | 	if (!prop) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	if (namep) | 	if (namep) { | ||||||
| 		*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); | 		const char *name; | ||||||
|  | 		int namelen; | ||||||
|  | 
 | ||||||
|  | 		if (fdt_chk_extra()) { | ||||||
|  | 			name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff), | ||||||
|  | 					      &namelen); | ||||||
|  | 			if (!name) { | ||||||
|  | 				if (lenp) | ||||||
|  | 					*lenp = namelen; | ||||||
|  | 				return NULL; | ||||||
|  | 			} | ||||||
|  | 			*namep = name; | ||||||
|  | 		} else { | ||||||
|  | 			*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff)); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Handle realignment */ | ||||||
|  | 	if (fdt_chk_version() && fdt_version(fdt) < 0x10 && | ||||||
|  | 	    (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) | ||||||
|  | 		return prop->data + 4; | ||||||
| 	return prop->data; | 	return prop->data; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -376,7 +521,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) | ||||||
| 			return 0; | 			return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return fdt32_to_cpu(*php); | 	return fdt32_ld(php); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char *fdt_get_alias_namelen(const void *fdt, | const char *fdt_get_alias_namelen(const void *fdt, | ||||||
|  | @ -402,7 +547,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | ||||||
| 	int offset, depth, namelen; | 	int offset, depth, namelen; | ||||||
| 	const char *name; | 	const char *name; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	if (buflen < 2) | 	if (buflen < 2) | ||||||
| 		return -FDT_ERR_NOSPACE; | 		return -FDT_ERR_NOSPACE; | ||||||
|  | @ -454,7 +599,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, | ||||||
| 	int offset, depth; | 	int offset, depth; | ||||||
| 	int supernodeoffset = -FDT_ERR_INTERNAL; | 	int supernodeoffset = -FDT_ERR_INTERNAL; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	if (supernodedepth < 0) | 	if (supernodedepth < 0) | ||||||
| 		return -FDT_ERR_NOTFOUND; | 		return -FDT_ERR_NOTFOUND; | ||||||
|  | @ -476,10 +621,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) | 	if (fdt_chk_extra()) { | ||||||
| 		return -FDT_ERR_BADOFFSET; | 		if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) | ||||||
| 	else if (offset == -FDT_ERR_BADOFFSET) | 			return -FDT_ERR_BADOFFSET; | ||||||
| 		return -FDT_ERR_BADSTRUCTURE; | 		else if (offset == -FDT_ERR_BADOFFSET) | ||||||
|  | 			return -FDT_ERR_BADSTRUCTURE; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return offset; /* error from fdt_next_node() */ | 	return offset; /* error from fdt_next_node() */ | ||||||
| } | } | ||||||
|  | @ -491,7 +638,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset) | ||||||
| 
 | 
 | ||||||
| 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); | 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return (err < 0) ? err : -FDT_ERR_INTERNAL; | 		return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL; | ||||||
| 	return nodedepth; | 	return nodedepth; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -513,7 +660,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, | ||||||
| 	const void *val; | 	const void *val; | ||||||
| 	int len; | 	int len; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* FIXME: The algorithm here is pretty horrible: we scan each
 | 	/* FIXME: The algorithm here is pretty horrible: we scan each
 | ||||||
| 	 * property of a node in fdt_getprop(), then if that didn't | 	 * property of a node in fdt_getprop(), then if that didn't | ||||||
|  | @ -539,7 +686,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) | ||||||
| 	if ((phandle == 0) || (phandle == -1)) | 	if ((phandle == 0) || (phandle == -1)) | ||||||
| 		return -FDT_ERR_BADPHANDLE; | 		return -FDT_ERR_BADPHANDLE; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* FIXME: The algorithm here is pretty horrible: we
 | 	/* FIXME: The algorithm here is pretty horrible: we
 | ||||||
| 	 * potentially scan each property of a node in | 	 * potentially scan each property of a node in | ||||||
|  | @ -692,7 +839,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, | ||||||
| { | { | ||||||
| 	int offset, err; | 	int offset, err; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* FIXME: The algorithm here is pretty horrible: we scan each
 | 	/* FIXME: The algorithm here is pretty horrible: we scan each
 | ||||||
| 	 * property of a node in fdt_node_check_compatible(), then if | 	 * property of a node in fdt_node_check_compatible(), then if | ||||||
|  | @ -711,3 +858,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, | ||||||
| 
 | 
 | ||||||
| 	return offset; /* error from fdt_next_node() */ | 	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 | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | # SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| # Makefile.libfdt
 | # Makefile.libfdt
 | ||||||
| #
 | #
 | ||||||
| # This is not a complete Makefile of itself.  Instead, it is designed to
 | # This is not a complete Makefile of itself.  Instead, it is designed to
 | ||||||
|  | @ -9,3 +10,9 @@ LIBFDT_VERSION = version.lds | ||||||
| LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
 | LIBFDT_SRCS = 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 | 	fdt_addresses.c fdt_overlay.c | ||||||
| LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) | LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) | ||||||
|  | LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) | ||||||
|  | 
 | ||||||
|  | libfdt_clean: | ||||||
|  | 	@$(VECHO) CLEAN "(libfdt)" | ||||||
|  | 	rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%) | ||||||
|  | 	rm -f $(LIBFDT_dir)/$(LIBFDT_soname) | ||||||
|  |  | ||||||
|  | @ -1,52 +1,7 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
| 
 | 
 | ||||||
|  | @ -55,14 +10,24 @@ | ||||||
| 
 | 
 | ||||||
| #include "libfdt_internal.h" | #include "libfdt_internal.h" | ||||||
| 
 | 
 | ||||||
| int fdt_check_header(const void *fdt) | /*
 | ||||||
|  |  * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks | ||||||
|  |  * that the given buffer contains what appears to be a flattened | ||||||
|  |  * device tree with sane information in its header. | ||||||
|  |  */ | ||||||
|  | int32_t fdt_ro_probe_(const void *fdt) | ||||||
| { | { | ||||||
|  | 	uint32_t totalsize = fdt_totalsize(fdt); | ||||||
|  | 
 | ||||||
| 	if (fdt_magic(fdt) == FDT_MAGIC) { | 	if (fdt_magic(fdt) == FDT_MAGIC) { | ||||||
| 		/* Complete tree */ | 		/* Complete tree */ | ||||||
| 		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) | 		if (fdt_chk_version()) { | ||||||
| 			return -FDT_ERR_BADVERSION; | 			if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) | ||||||
| 		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) | 				return -FDT_ERR_BADVERSION; | ||||||
| 			return -FDT_ERR_BADVERSION; | 			if (fdt_last_comp_version(fdt) > | ||||||
|  | 					FDT_LAST_SUPPORTED_VERSION) | ||||||
|  | 				return -FDT_ERR_BADVERSION; | ||||||
|  | 		} | ||||||
| 	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) { | 	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) { | ||||||
| 		/* Unfinished sequential-write blob */ | 		/* Unfinished sequential-write blob */ | ||||||
| 		if (fdt_size_dt_struct(fdt) == 0) | 		if (fdt_size_dt_struct(fdt) == 0) | ||||||
|  | @ -71,6 +36,96 @@ int fdt_check_header(const void *fdt) | ||||||
| 		return -FDT_ERR_BADMAGIC; | 		return -FDT_ERR_BADMAGIC; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (totalsize < INT32_MAX) | ||||||
|  | 		return totalsize; | ||||||
|  | 	else | ||||||
|  | 		return -FDT_ERR_TRUNCATED; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off) | ||||||
|  | { | ||||||
|  | 	return (off >= hdrsize) && (off <= totalsize); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int check_block_(uint32_t hdrsize, uint32_t totalsize, | ||||||
|  | 			uint32_t base, uint32_t size) | ||||||
|  | { | ||||||
|  | 	if (!check_off_(hdrsize, totalsize, base)) | ||||||
|  | 		return 0; /* block start out of bounds */ | ||||||
|  | 	if ((base + size) < base) | ||||||
|  | 		return 0; /* overflow */ | ||||||
|  | 	if (!check_off_(hdrsize, totalsize, base + size)) | ||||||
|  | 		return 0; /* block end out of bounds */ | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t fdt_header_size_(uint32_t version) | ||||||
|  | { | ||||||
|  | 	if (version <= 1) | ||||||
|  | 		return FDT_V1_SIZE; | ||||||
|  | 	else if (version <= 2) | ||||||
|  | 		return FDT_V2_SIZE; | ||||||
|  | 	else if (version <= 3) | ||||||
|  | 		return FDT_V3_SIZE; | ||||||
|  | 	else if (version <= 16) | ||||||
|  | 		return FDT_V16_SIZE; | ||||||
|  | 	else | ||||||
|  | 		return FDT_V17_SIZE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t fdt_header_size(const void *fdt) | ||||||
|  | { | ||||||
|  | 	return fdt_chk_version() ? fdt_header_size_(fdt_version(fdt)) : | ||||||
|  | 		FDT_V17_SIZE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int fdt_check_header(const void *fdt) | ||||||
|  | { | ||||||
|  | 	size_t hdrsize; | ||||||
|  | 
 | ||||||
|  | 	if (fdt_magic(fdt) != FDT_MAGIC) | ||||||
|  | 		return -FDT_ERR_BADMAGIC; | ||||||
|  | 	if (fdt_chk_version()) { | ||||||
|  | 		if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) | ||||||
|  | 		    || (fdt_last_comp_version(fdt) > | ||||||
|  | 			FDT_LAST_SUPPORTED_VERSION)) | ||||||
|  | 			return -FDT_ERR_BADVERSION; | ||||||
|  | 		if (fdt_version(fdt) < fdt_last_comp_version(fdt)) | ||||||
|  | 			return -FDT_ERR_BADVERSION; | ||||||
|  | 	} | ||||||
|  | 	hdrsize = fdt_header_size(fdt); | ||||||
|  | 	if (fdt_chk_basic()) { | ||||||
|  | 
 | ||||||
|  | 		if ((fdt_totalsize(fdt) < hdrsize) | ||||||
|  | 		    || (fdt_totalsize(fdt) > INT_MAX)) | ||||||
|  | 			return -FDT_ERR_TRUNCATED; | ||||||
|  | 
 | ||||||
|  | 		/* Bounds check memrsv block */ | ||||||
|  | 		if (!check_off_(hdrsize, fdt_totalsize(fdt), | ||||||
|  | 				fdt_off_mem_rsvmap(fdt))) | ||||||
|  | 			return -FDT_ERR_TRUNCATED; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (fdt_chk_extra()) { | ||||||
|  | 		/* Bounds check structure block */ | ||||||
|  | 		if (fdt_chk_version() && fdt_version(fdt) < 17) { | ||||||
|  | 			if (!check_off_(hdrsize, fdt_totalsize(fdt), | ||||||
|  | 					fdt_off_dt_struct(fdt))) | ||||||
|  | 				return -FDT_ERR_TRUNCATED; | ||||||
|  | 		} else { | ||||||
|  | 			if (!check_block_(hdrsize, fdt_totalsize(fdt), | ||||||
|  | 					  fdt_off_dt_struct(fdt), | ||||||
|  | 					  fdt_size_dt_struct(fdt))) | ||||||
|  | 				return -FDT_ERR_TRUNCATED; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* Bounds check strings block */ | ||||||
|  | 		if (!check_block_(hdrsize, fdt_totalsize(fdt), | ||||||
|  | 				  fdt_off_dt_strings(fdt), | ||||||
|  | 				  fdt_size_dt_strings(fdt))) | ||||||
|  | 			return -FDT_ERR_TRUNCATED; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -78,12 +133,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) | ||||||
| { | { | ||||||
| 	unsigned absoffset = offset + fdt_off_dt_struct(fdt); | 	unsigned absoffset = offset + fdt_off_dt_struct(fdt); | ||||||
| 
 | 
 | ||||||
| 	if ((absoffset < offset) | 	if (fdt_chk_basic()) | ||||||
| 	    || ((absoffset + len) < absoffset) | 		if ((absoffset < offset) | ||||||
| 	    || (absoffset + len) > fdt_totalsize(fdt)) | 		    || ((absoffset + len) < absoffset) | ||||||
| 		return NULL; | 		    || (absoffset + len) > fdt_totalsize(fdt)) | ||||||
|  | 			return NULL; | ||||||
| 
 | 
 | ||||||
| 	if (fdt_version(fdt) >= 0x11) | 	if (!fdt_chk_version() || fdt_version(fdt) >= 0x11) | ||||||
| 		if (((offset + len) < offset) | 		if (((offset + len) < offset) | ||||||
| 		    || ((offset + len) > fdt_size_dt_struct(fdt))) | 		    || ((offset + len) > fdt_size_dt_struct(fdt))) | ||||||
| 			return NULL; | 			return NULL; | ||||||
|  | @ -100,7 +156,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) | ||||||
| 
 | 
 | ||||||
| 	*nextoffset = -FDT_ERR_TRUNCATED; | 	*nextoffset = -FDT_ERR_TRUNCATED; | ||||||
| 	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); | 	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); | ||||||
| 	if (!tagp) | 	if (fdt_chk_basic() && !tagp) | ||||||
| 		return FDT_END; /* premature end */ | 		return FDT_END; /* premature end */ | ||||||
| 	tag = fdt32_to_cpu(*tagp); | 	tag = fdt32_to_cpu(*tagp); | ||||||
| 	offset += FDT_TAGSIZE; | 	offset += FDT_TAGSIZE; | ||||||
|  | @ -112,18 +168,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) | ||||||
| 		do { | 		do { | ||||||
| 			p = fdt_offset_ptr(fdt, offset++, 1); | 			p = fdt_offset_ptr(fdt, offset++, 1); | ||||||
| 		} while (p && (*p != '\0')); | 		} while (p && (*p != '\0')); | ||||||
| 		if (!p) | 		if (fdt_chk_basic() && !p) | ||||||
| 			return FDT_END; /* premature end */ | 			return FDT_END; /* premature end */ | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	case FDT_PROP: | 	case FDT_PROP: | ||||||
| 		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); | 		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); | ||||||
| 		if (!lenp) | 		if (fdt_chk_basic() && !lenp) | ||||||
| 			return FDT_END; /* premature end */ | 			return FDT_END; /* premature end */ | ||||||
| 		/* skip-name offset, length and value */ | 		/* skip-name offset, length and value */ | ||||||
| 		offset += sizeof(struct fdt_property) - FDT_TAGSIZE | 		offset += sizeof(struct fdt_property) - FDT_TAGSIZE | ||||||
| 			+ fdt32_to_cpu(*lenp); | 			+ fdt32_to_cpu(*lenp); | ||||||
| 		if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && | 		if (fdt_chk_version() && | ||||||
|  | 		    fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && | ||||||
| 		    ((offset - fdt32_to_cpu(*lenp)) % 8) != 0) | 		    ((offset - fdt32_to_cpu(*lenp)) % 8) != 0) | ||||||
| 			offset += 4; | 			offset += 4; | ||||||
| 		break; | 		break; | ||||||
|  | @ -137,7 +194,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) | ||||||
| 		return FDT_END; | 		return FDT_END; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) | 	if (fdt_chk_basic() && | ||||||
|  | 	    !fdt_offset_ptr(fdt, startoffset, offset - startoffset)) | ||||||
| 		return FDT_END; /* premature end */ | 		return FDT_END; /* premature end */ | ||||||
| 
 | 
 | ||||||
| 	*nextoffset = FDT_TAGALIGN(offset); | 	*nextoffset = FDT_TAGALIGN(offset); | ||||||
|  | @ -244,7 +302,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) | ||||||
| 
 | 
 | ||||||
| int fdt_move(const void *fdt, void *buf, int bufsize) | int fdt_move(const void *fdt, void *buf, int bufsize) | ||||||
| { | { | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	if (fdt_totalsize(fdt) > bufsize) | 	if (fdt_totalsize(fdt) > bufsize) | ||||||
| 		return -FDT_ERR_NOSPACE; | 		return -FDT_ERR_NOSPACE; | ||||||
|  |  | ||||||
|  | @ -1,55 +1,10 @@ | ||||||
|  | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ | ||||||
| #ifndef FDT_H | #ifndef FDT_H | ||||||
| #define FDT_H | #define FDT_H | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * Copyright 2012 Kim Phillips, Freescale Semiconductor. |  * Copyright 2012 Kim Phillips, Freescale Semiconductor. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef __ASSEMBLY__ | #ifndef __ASSEMBLY__ | ||||||
|  |  | ||||||
|  | @ -1,53 +1,8 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> |  * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> | ||||||
|  * Copyright (C) 2018 embedded brains GmbH |  * Copyright (C) 2018 embedded brains GmbH | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
| 
 | 
 | ||||||
|  | @ -97,3 +52,50 @@ int fdt_size_cells(const void *fdt, int nodeoffset) | ||||||
| 		return 1; | 		return 1; | ||||||
| 	return val; | 	return val; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /* This function assumes that [address|size]_cells is 1 or 2 */ | ||||||
|  | int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, | ||||||
|  | 			     const char *name, uint64_t addr, uint64_t size) | ||||||
|  | { | ||||||
|  | 	int addr_cells, size_cells, ret; | ||||||
|  | 	uint8_t data[sizeof(fdt64_t) * 2], *prop; | ||||||
|  | 
 | ||||||
|  | 	ret = fdt_address_cells(fdt, parent); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return ret; | ||||||
|  | 	addr_cells = ret; | ||||||
|  | 
 | ||||||
|  | 	ret = fdt_size_cells(fdt, parent); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return ret; | ||||||
|  | 	size_cells = ret; | ||||||
|  | 
 | ||||||
|  | 	/* check validity of address */ | ||||||
|  | 	prop = data; | ||||||
|  | 	if (addr_cells == 1) { | ||||||
|  | 		if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size)) | ||||||
|  | 			return -FDT_ERR_BADVALUE; | ||||||
|  | 
 | ||||||
|  | 		fdt32_st(prop, (uint32_t)addr); | ||||||
|  | 	} else if (addr_cells == 2) { | ||||||
|  | 		fdt64_st(prop, addr); | ||||||
|  | 	} else { | ||||||
|  | 		return -FDT_ERR_BADNCELLS; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* check validity of size */ | ||||||
|  | 	prop += addr_cells * sizeof(fdt32_t); | ||||||
|  | 	if (size_cells == 1) { | ||||||
|  | 		if (size > UINT32_MAX) | ||||||
|  | 			return -FDT_ERR_BADVALUE; | ||||||
|  | 
 | ||||||
|  | 		fdt32_st(prop, (uint32_t)size); | ||||||
|  | 	} else if (size_cells == 2) { | ||||||
|  | 		fdt64_st(prop, size); | ||||||
|  | 	} else { | ||||||
|  | 		return -FDT_ERR_BADNCELLS; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return fdt_appendprop(fdt, nodeoffset, name, data, | ||||||
|  | 			      (addr_cells + size_cells) * sizeof(fdt32_t)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,52 +1,7 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2012 David Gibson, IBM Corporation. |  * Copyright (C) 2012 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,53 +1,8 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2016 Free Electrons |  * Copyright (C) 2016 Free Electrons | ||||||
|  * Copyright (C) 2016 NextThing Co. |  * Copyright (C) 2016 NextThing Co. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
| 
 | 
 | ||||||
|  | @ -93,11 +48,11 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) | ||||||
|  * @pathp: pointer which receives the path of the target (or NULL) |  * @pathp: pointer which receives the path of the target (or NULL) | ||||||
|  * |  * | ||||||
|  * overlay_get_target() retrieves the target offset in the base |  * overlay_get_target() retrieves the target offset in the base | ||||||
|  * device tree of a fragment, no matter how the actual targetting is |  * device tree of a fragment, no matter how the actual targeting is | ||||||
|  * done (through a phandle or a path) |  * done (through a phandle or a path) | ||||||
|  * |  * | ||||||
|  * returns: |  * returns: | ||||||
|  *      the targetted node offset in the base device tree |  *      the targeted node offset in the base device tree | ||||||
|  *      Negative error code on error |  *      Negative error code on error | ||||||
|  */ |  */ | ||||||
| static int overlay_get_target(const void *fdt, const void *fdto, | static int overlay_get_target(const void *fdt, const void *fdto, | ||||||
|  | @ -697,7 +652,7 @@ static int get_path_len(const void *fdt, int nodeoffset) | ||||||
| 	int len = 0, namelen; | 	int len = 0, namelen; | ||||||
| 	const char *name; | 	const char *name; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	for (;;) { | 	for (;;) { | ||||||
| 		name = fdt_get_name(fdt, nodeoffset, &namelen); | 		name = fdt_get_name(fdt, nodeoffset, &namelen); | ||||||
|  | @ -778,26 +733,36 @@ static int overlay_symbol_update(void *fdt, void *fdto) | ||||||
| 		/* keep end marker to avoid strlen() */ | 		/* keep end marker to avoid strlen() */ | ||||||
| 		e = path + path_len; | 		e = path + path_len; | ||||||
| 
 | 
 | ||||||
| 		/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */ |  | ||||||
| 
 |  | ||||||
| 		if (*path != '/') | 		if (*path != '/') | ||||||
| 			return -FDT_ERR_BADVALUE; | 			return -FDT_ERR_BADVALUE; | ||||||
| 
 | 
 | ||||||
| 		/* get fragment name first */ | 		/* get fragment name first */ | ||||||
| 		s = strchr(path + 1, '/'); | 		s = strchr(path + 1, '/'); | ||||||
| 		if (!s) | 		if (!s) { | ||||||
| 			return -FDT_ERR_BADOVERLAY; | 			/* Symbol refers to something that won't end
 | ||||||
|  | 			 * up in the target tree */ | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		frag_name = path + 1; | 		frag_name = path + 1; | ||||||
| 		frag_name_len = s - path - 1; | 		frag_name_len = s - path - 1; | ||||||
| 
 | 
 | ||||||
| 		/* verify format; safe since "s" lies in \0 terminated prop */ | 		/* verify format; safe since "s" lies in \0 terminated prop */ | ||||||
| 		len = sizeof("/__overlay__/") - 1; | 		len = sizeof("/__overlay__/") - 1; | ||||||
| 		if ((e - s) < len || memcmp(s, "/__overlay__/", len)) | 		if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { | ||||||
| 			return -FDT_ERR_BADOVERLAY; | 			/* /<fragment-name>/__overlay__/<relative-subnode-path> */ | ||||||
| 
 | 			rel_path = s + len; | ||||||
| 		rel_path = s + len; | 			rel_path_len = e - rel_path; | ||||||
| 		rel_path_len = e - rel_path; | 		} else if ((e - s) == len | ||||||
|  | 			   && (memcmp(s, "/__overlay__", len - 1) == 0)) { | ||||||
|  | 			/* /<fragment-name>/__overlay__ */ | ||||||
|  | 			rel_path = ""; | ||||||
|  | 			rel_path_len = 0; | ||||||
|  | 		} else { | ||||||
|  | 			/* Symbol refers to something that won't end
 | ||||||
|  | 			 * up in the target tree */ | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		/* find the fragment index in which the symbol lies */ | 		/* find the fragment index in which the symbol lies */ | ||||||
| 		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, | 		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, | ||||||
|  | @ -863,11 +828,15 @@ static int overlay_symbol_update(void *fdt, void *fdto) | ||||||
| 
 | 
 | ||||||
| int fdt_overlay_apply(void *fdt, void *fdto) | int fdt_overlay_apply(void *fdt, void *fdto) | ||||||
| { | { | ||||||
| 	uint32_t delta = fdt_get_max_phandle(fdt); | 	uint32_t delta; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 	FDT_CHECK_HEADER(fdto); | 	FDT_RO_PROBE(fdto); | ||||||
|  | 
 | ||||||
|  | 	ret = fdt_find_max_phandle(fdt, &delta); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	ret = overlay_adjust_local_phandles(fdto, delta); | 	ret = overlay_adjust_local_phandles(fdto, delta); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  |  | ||||||
|  | @ -1,52 +1,7 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
| 
 | 
 | ||||||
|  | @ -61,7 +16,7 @@ static int fdt_nodename_eq_(const void *fdt, int offset, | ||||||
| 	int olen; | 	int olen; | ||||||
| 	const char *p = fdt_get_name(fdt, offset, &olen); | 	const char *p = fdt_get_name(fdt, offset, &olen); | ||||||
| 
 | 
 | ||||||
| 	if (!p || olen < len) | 	if (!p || (fdt_chk_extra() && olen < len)) | ||||||
| 		/* short match */ | 		/* short match */ | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
|  | @ -76,46 +31,85 @@ static int fdt_nodename_eq_(const void *fdt, int offset, | ||||||
| 		return 0; | 		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) | const char *fdt_string(const void *fdt, int stroffset) | ||||||
| { | { | ||||||
| 	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; | 	return fdt_get_string(fdt, stroffset, NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int fdt_string_eq_(const void *fdt, int stroffset, | static int fdt_string_eq_(const void *fdt, int stroffset, | ||||||
| 			  const char *s, int len) | 			  const char *s, int len) | ||||||
| { | { | ||||||
| 	const char *p = fdt_string(fdt, stroffset); | 	int slen; | ||||||
|  | 	const char *p = fdt_get_string(fdt, stroffset, &slen); | ||||||
| 
 | 
 | ||||||
| 	return (strlen(p) == len) && (memcmp(p, s, len) == 0); | 	return p && (slen == len) && (memcmp(p, s, len) == 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint32_t fdt_get_max_phandle(const void *fdt) | int fdt_find_max_phandle(const void *fdt, uint32_t *phandle) | ||||||
| { |  | ||||||
| 	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_generate_phandle(const void *fdt, uint32_t *phandle) |  | ||||||
| { | { | ||||||
| 	uint32_t max = 0; | 	uint32_t max = 0; | ||||||
| 	int offset = -1; | 	int offset = -1; | ||||||
|  | @ -137,6 +131,21 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle) | ||||||
| 			max = value; | 			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) | 	if (max == FDT_MAX_PHANDLE) | ||||||
| 		return -FDT_ERR_NOPHANDLES; | 		return -FDT_ERR_NOPHANDLES; | ||||||
| 
 | 
 | ||||||
|  | @ -146,21 +155,45 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle) | ||||||
| 	return 0; | 	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) | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) | ||||||
| { | { | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	const struct fdt_reserve_entry *re; | ||||||
| 	*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address); | 
 | ||||||
| 	*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); | 	FDT_RO_PROBE(fdt); | ||||||
|  | 	re = fdt_mem_rsv(fdt, n); | ||||||
|  | 	if (fdt_chk_extra() && !re) | ||||||
|  | 		return -FDT_ERR_BADOFFSET; | ||||||
|  | 
 | ||||||
|  | 	*address = fdt64_ld(&re->address); | ||||||
|  | 	*size = fdt64_ld(&re->size); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int fdt_num_mem_rsv(const void *fdt) | int fdt_num_mem_rsv(const void *fdt) | ||||||
| { | { | ||||||
| 	int i = 0; | 	int i; | ||||||
|  | 	const struct fdt_reserve_entry *re; | ||||||
| 
 | 
 | ||||||
| 	while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0) | 	for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { | ||||||
| 		i++; | 		if (fdt64_ld(&re->size) == 0) | ||||||
| 	return i; | 			return i; | ||||||
|  | 	} | ||||||
|  | 	return -FDT_ERR_TRUNCATED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int nextprop_(const void *fdt, int offset) | static int nextprop_(const void *fdt, int offset) | ||||||
|  | @ -192,7 +225,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, | ||||||
| { | { | ||||||
| 	int depth; | 	int depth; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	for (depth = 0; | 	for (depth = 0; | ||||||
| 	     (offset >= 0) && (depth >= 0); | 	     (offset >= 0) && (depth >= 0); | ||||||
|  | @ -218,7 +251,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) | ||||||
| 	const char *p = path; | 	const char *p = path; | ||||||
| 	int offset = 0; | 	int offset = 0; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* see if we have an alias */ | 	/* see if we have an alias */ | ||||||
| 	if (*path != '/') { | 	if (*path != '/') { | ||||||
|  | @ -268,13 +301,14 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) | ||||||
| 	const char *nameptr; | 	const char *nameptr; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	if (((err = fdt_check_header(fdt)) != 0) | 	if (fdt_chk_extra() && | ||||||
| 	    || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) | 	    (((err = fdt_ro_probe_(fdt)) < 0) | ||||||
| 			goto fail; | 	     || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))) | ||||||
|  | 		goto fail; | ||||||
| 
 | 
 | ||||||
| 	nameptr = nh->name; | 	nameptr = nh->name; | ||||||
| 
 | 
 | ||||||
| 	if (fdt_version(fdt) < 0x10) { | 	if (fdt_chk_version() && fdt_version(fdt) < 0x10) { | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * For old FDT versions, match the naming conventions of V16: | 		 * For old FDT versions, match the naming conventions of V16: | ||||||
| 		 * give only the leaf name (after all /). The actual tree | 		 * give only the leaf name (after all /). The actual tree | ||||||
|  | @ -325,7 +359,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, | ||||||
| 	int err; | 	int err; | ||||||
| 	const struct fdt_property *prop; | 	const struct fdt_property *prop; | ||||||
| 
 | 
 | ||||||
| 	if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) { | 	if (fdt_chk_basic() && (err = fdt_check_prop_offset_(fdt, offset)) < 0) { | ||||||
| 		if (lenp) | 		if (lenp) | ||||||
| 			*lenp = err; | 			*lenp = err; | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -334,7 +368,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, | ||||||
| 	prop = fdt_offset_ptr_(fdt, offset); | 	prop = fdt_offset_ptr_(fdt, offset); | ||||||
| 
 | 
 | ||||||
| 	if (lenp) | 	if (lenp) | ||||||
| 		*lenp = fdt32_to_cpu(prop->len); | 		*lenp = fdt32_ld(&prop->len); | ||||||
| 
 | 
 | ||||||
| 	return prop; | 	return prop; | ||||||
| } | } | ||||||
|  | @ -346,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, | ||||||
| 	/* Prior to version 16, properties may need realignment
 | 	/* Prior to version 16, properties may need realignment
 | ||||||
| 	 * and this API does not work. fdt_getprop_*() will, however. */ | 	 * and this API does not work. fdt_getprop_*() will, however. */ | ||||||
| 
 | 
 | ||||||
| 	if (fdt_version(fdt) < 0x10) { | 	if (fdt_chk_version() && fdt_version(fdt) < 0x10) { | ||||||
| 		if (lenp) | 		if (lenp) | ||||||
| 			*lenp = -FDT_ERR_BADVERSION; | 			*lenp = -FDT_ERR_BADVERSION; | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -367,11 +401,12 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, | ||||||
| 	     (offset = fdt_next_property_offset(fdt, offset))) { | 	     (offset = fdt_next_property_offset(fdt, offset))) { | ||||||
| 		const struct fdt_property *prop; | 		const struct fdt_property *prop; | ||||||
| 
 | 
 | ||||||
| 		if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) { | 		prop = fdt_get_property_by_offset_(fdt, offset, lenp); | ||||||
|  | 		if (fdt_chk_extra() && !prop) { | ||||||
| 			offset = -FDT_ERR_INTERNAL; | 			offset = -FDT_ERR_INTERNAL; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), | 		if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), | ||||||
| 				   name, namelen)) { | 				   name, namelen)) { | ||||||
| 			if (poffset) | 			if (poffset) | ||||||
| 				*poffset = offset; | 				*poffset = offset; | ||||||
|  | @ -392,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, | ||||||
| { | { | ||||||
| 	/* Prior to version 16, properties may need realignment
 | 	/* Prior to version 16, properties may need realignment
 | ||||||
| 	 * and this API does not work. fdt_getprop_*() will, however. */ | 	 * and this API does not work. fdt_getprop_*() will, however. */ | ||||||
| 	if (fdt_version(fdt) < 0x10) { | 	if (fdt_chk_version() && fdt_version(fdt) < 0x10) { | ||||||
| 		if (lenp) | 		if (lenp) | ||||||
| 			*lenp = -FDT_ERR_BADVERSION; | 			*lenp = -FDT_ERR_BADVERSION; | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -423,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
| 	/* Handle realignment */ | 	/* Handle realignment */ | ||||||
| 	if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && | 	if (fdt_chk_version() && fdt_version(fdt) < 0x10 && | ||||||
| 	    fdt32_to_cpu(prop->len) >= 8) | 	    (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) | ||||||
| 		return prop->data + 4; | 		return prop->data + 4; | ||||||
| 	return prop->data; | 	return prop->data; | ||||||
| } | } | ||||||
|  | @ -437,12 +472,27 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, | ||||||
| 	prop = fdt_get_property_by_offset_(fdt, offset, lenp); | 	prop = fdt_get_property_by_offset_(fdt, offset, lenp); | ||||||
| 	if (!prop) | 	if (!prop) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	if (namep) | 	if (namep) { | ||||||
| 		*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); | 		const char *name; | ||||||
|  | 		int namelen; | ||||||
|  | 
 | ||||||
|  | 		if (fdt_chk_extra()) { | ||||||
|  | 			name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff), | ||||||
|  | 					      &namelen); | ||||||
|  | 			if (!name) { | ||||||
|  | 				if (lenp) | ||||||
|  | 					*lenp = namelen; | ||||||
|  | 				return NULL; | ||||||
|  | 			} | ||||||
|  | 			*namep = name; | ||||||
|  | 		} else { | ||||||
|  | 			*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff)); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Handle realignment */ | 	/* Handle realignment */ | ||||||
| 	if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && | 	if (fdt_chk_version() && fdt_version(fdt) < 0x10 && | ||||||
| 	    fdt32_to_cpu(prop->len) >= 8) | 	    (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) | ||||||
| 		return prop->data + 4; | 		return prop->data + 4; | ||||||
| 	return prop->data; | 	return prop->data; | ||||||
| } | } | ||||||
|  | @ -467,7 +517,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) | ||||||
| 			return 0; | 			return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return fdt32_to_cpu(*php); | 	return fdt32_ld(php); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char *fdt_get_alias_namelen(const void *fdt, | const char *fdt_get_alias_namelen(const void *fdt, | ||||||
|  | @ -493,7 +543,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | ||||||
| 	int offset, depth, namelen; | 	int offset, depth, namelen; | ||||||
| 	const char *name; | 	const char *name; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	if (buflen < 2) | 	if (buflen < 2) | ||||||
| 		return -FDT_ERR_NOSPACE; | 		return -FDT_ERR_NOSPACE; | ||||||
|  | @ -545,7 +595,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, | ||||||
| 	int offset, depth; | 	int offset, depth; | ||||||
| 	int supernodeoffset = -FDT_ERR_INTERNAL; | 	int supernodeoffset = -FDT_ERR_INTERNAL; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	if (supernodedepth < 0) | 	if (supernodedepth < 0) | ||||||
| 		return -FDT_ERR_NOTFOUND; | 		return -FDT_ERR_NOTFOUND; | ||||||
|  | @ -567,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) | 	if (fdt_chk_extra()) { | ||||||
| 		return -FDT_ERR_BADOFFSET; | 		if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) | ||||||
| 	else if (offset == -FDT_ERR_BADOFFSET) | 			return -FDT_ERR_BADOFFSET; | ||||||
| 		return -FDT_ERR_BADSTRUCTURE; | 		else if (offset == -FDT_ERR_BADOFFSET) | ||||||
|  | 			return -FDT_ERR_BADSTRUCTURE; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return offset; /* error from fdt_next_node() */ | 	return offset; /* error from fdt_next_node() */ | ||||||
| } | } | ||||||
|  | @ -582,7 +634,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset) | ||||||
| 
 | 
 | ||||||
| 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); | 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return (err < 0) ? err : -FDT_ERR_INTERNAL; | 		return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL; | ||||||
| 	return nodedepth; | 	return nodedepth; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -604,7 +656,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, | ||||||
| 	const void *val; | 	const void *val; | ||||||
| 	int len; | 	int len; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* FIXME: The algorithm here is pretty horrible: we scan each
 | 	/* FIXME: The algorithm here is pretty horrible: we scan each
 | ||||||
| 	 * property of a node in fdt_getprop(), then if that didn't | 	 * property of a node in fdt_getprop(), then if that didn't | ||||||
|  | @ -630,7 +682,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) | ||||||
| 	if ((phandle == 0) || (phandle == -1)) | 	if ((phandle == 0) || (phandle == -1)) | ||||||
| 		return -FDT_ERR_BADPHANDLE; | 		return -FDT_ERR_BADPHANDLE; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* FIXME: The algorithm here is pretty horrible: we
 | 	/* FIXME: The algorithm here is pretty horrible: we
 | ||||||
| 	 * potentially scan each property of a node in | 	 * potentially scan each property of a node in | ||||||
|  | @ -783,7 +835,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, | ||||||
| { | { | ||||||
| 	int offset, err; | 	int offset, err; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* FIXME: The algorithm here is pretty horrible: we scan each
 | 	/* FIXME: The algorithm here is pretty horrible: we scan each
 | ||||||
| 	 * property of a node in fdt_node_check_compatible(), then if | 	 * property of a node in fdt_node_check_compatible(), then if | ||||||
|  | @ -802,3 +854,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, | ||||||
| 
 | 
 | ||||||
| 	return offset; /* error from fdt_next_node() */ | 	return offset; /* error from fdt_next_node() */ | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #if !defined(FDT_ASSUME_MASK) || FDT_ASSUME_MASK != 0xff | ||||||
|  | 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 | ||||||
|  |  | ||||||
|  | @ -1,52 +1,7 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
| 
 | 
 | ||||||
|  | @ -58,6 +13,8 @@ | ||||||
| static int fdt_blocks_misordered_(const void *fdt, | static int fdt_blocks_misordered_(const void *fdt, | ||||||
| 				  int mem_rsv_size, int struct_size) | 				  int mem_rsv_size, int struct_size) | ||||||
| { | { | ||||||
|  | 	if (!fdt_chk_basic()) | ||||||
|  | 		return false; | ||||||
| 	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) | 	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) | ||||||
| 		|| (fdt_off_dt_struct(fdt) < | 		|| (fdt_off_dt_struct(fdt) < | ||||||
| 		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) | 		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) | ||||||
|  | @ -67,25 +24,27 @@ static int fdt_blocks_misordered_(const void *fdt, | ||||||
| 		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); | 		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int fdt_rw_check_header_(void *fdt) | static int fdt_rw_probe_(void *fdt) | ||||||
| { | { | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	if (!fdt_chk_basic()) | ||||||
|  | 		return 0; | ||||||
|  | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	if (fdt_version(fdt) < 17) | 	if (fdt_chk_version() && fdt_version(fdt) < 17) | ||||||
| 		return -FDT_ERR_BADVERSION; | 		return -FDT_ERR_BADVERSION; | ||||||
| 	if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), | 	if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), | ||||||
| 				   fdt_size_dt_struct(fdt))) | 				   fdt_size_dt_struct(fdt))) | ||||||
| 		return -FDT_ERR_BADLAYOUT; | 		return -FDT_ERR_BADLAYOUT; | ||||||
| 	if (fdt_version(fdt) > 17) | 	if (fdt_chk_version() && fdt_version(fdt) > 17) | ||||||
| 		fdt_set_version(fdt, 17); | 		fdt_set_version(fdt, 17); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define FDT_RW_CHECK_HEADER(fdt) \ | #define FDT_RW_PROBE(fdt) \ | ||||||
| 	{ \ | 	{ \ | ||||||
| 		int err_; \ | 		int err_; \ | ||||||
| 		if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ | 		if (fdt_chk_extra() && (err_ = fdt_rw_probe_(fdt)) != 0) \ | ||||||
| 			return err_; \ | 			return err_; \ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -136,6 +95,14 @@ static int fdt_splice_struct_(void *fdt, void *p, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* Must only be used to roll back in case of error */ | ||||||
|  | static void fdt_del_last_string_(void *fdt, const char *s) | ||||||
|  | { | ||||||
|  | 	int newlen = strlen(s) + 1; | ||||||
|  | 
 | ||||||
|  | 	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int fdt_splice_string_(void *fdt, int newlen) | static int fdt_splice_string_(void *fdt, int newlen) | ||||||
| { | { | ||||||
| 	void *p = (char *)fdt | 	void *p = (char *)fdt | ||||||
|  | @ -149,7 +116,16 @@ static int fdt_splice_string_(void *fdt, int newlen) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int fdt_find_add_string_(void *fdt, const char *s) | /**
 | ||||||
|  |  * fdt_find_add_string_() - Find or allocate a string | ||||||
|  |  * | ||||||
|  |  * @fdt: pointer to the device tree to check/adjust | ||||||
|  |  * @s: string to find/add | ||||||
|  |  * @allocated: Set to 0 if the string was found, 1 if not found and so | ||||||
|  |  *	allocated. Ignored if !fdt_chk_basic() | ||||||
|  |  * @return offset of string in the string table (whether found or added) | ||||||
|  |  */ | ||||||
|  | static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) | ||||||
| { | { | ||||||
| 	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); | 	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); | ||||||
| 	const char *p; | 	const char *p; | ||||||
|  | @ -157,6 +133,9 @@ static int fdt_find_add_string_(void *fdt, const char *s) | ||||||
| 	int len = strlen(s) + 1; | 	int len = strlen(s) + 1; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
|  | 	if (fdt_chk_basic()) | ||||||
|  | 		*allocated = 0; | ||||||
|  | 
 | ||||||
| 	p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); | 	p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); | ||||||
| 	if (p) | 	if (p) | ||||||
| 		/* found it */ | 		/* found it */ | ||||||
|  | @ -167,6 +146,9 @@ static int fdt_find_add_string_(void *fdt, const char *s) | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return err; | 		return err; | ||||||
| 
 | 
 | ||||||
|  | 	if (fdt_chk_basic()) | ||||||
|  | 		*allocated = 1; | ||||||
|  | 
 | ||||||
| 	memcpy(new, s, len); | 	memcpy(new, s, len); | ||||||
| 	return (new - strtab); | 	return (new - strtab); | ||||||
| } | } | ||||||
|  | @ -176,7 +158,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) | ||||||
| 	struct fdt_reserve_entry *re; | 	struct fdt_reserve_entry *re; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); | 	re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); | ||||||
| 	err = fdt_splice_mem_rsv_(fdt, re, 0, 1); | 	err = fdt_splice_mem_rsv_(fdt, re, 0, 1); | ||||||
|  | @ -192,7 +174,7 @@ int fdt_del_mem_rsv(void *fdt, int n) | ||||||
| { | { | ||||||
| 	struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); | 	struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	if (n >= fdt_num_mem_rsv(fdt)) | 	if (n >= fdt_num_mem_rsv(fdt)) | ||||||
| 		return -FDT_ERR_NOTFOUND; | 		return -FDT_ERR_NOTFOUND; | ||||||
|  | @ -225,11 +207,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, | ||||||
| 	int nextoffset; | 	int nextoffset; | ||||||
| 	int namestroff; | 	int namestroff; | ||||||
| 	int err; | 	int err; | ||||||
|  | 	int allocated; | ||||||
| 
 | 
 | ||||||
| 	if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) | 	if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) | ||||||
| 		return nextoffset; | 		return nextoffset; | ||||||
| 
 | 
 | ||||||
| 	namestroff = fdt_find_add_string_(fdt, name); | 	namestroff = fdt_find_add_string_(fdt, name, &allocated); | ||||||
| 	if (namestroff < 0) | 	if (namestroff < 0) | ||||||
| 		return namestroff; | 		return namestroff; | ||||||
| 
 | 
 | ||||||
|  | @ -237,8 +220,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, | ||||||
| 	proplen = sizeof(**prop) + FDT_TAGALIGN(len); | 	proplen = sizeof(**prop) + FDT_TAGALIGN(len); | ||||||
| 
 | 
 | ||||||
| 	err = fdt_splice_struct_(fdt, *prop, 0, proplen); | 	err = fdt_splice_struct_(fdt, *prop, 0, proplen); | ||||||
| 	if (err) | 	if (err) { | ||||||
|  | 		/* Delete the string if we failed to add it */ | ||||||
|  | 		if (fdt_chk_basic() && allocated) | ||||||
|  | 			fdt_del_last_string_(fdt, name); | ||||||
| 		return err; | 		return err; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	(*prop)->tag = cpu_to_fdt32(FDT_PROP); | 	(*prop)->tag = cpu_to_fdt32(FDT_PROP); | ||||||
| 	(*prop)->nameoff = cpu_to_fdt32(namestroff); | 	(*prop)->nameoff = cpu_to_fdt32(namestroff); | ||||||
|  | @ -252,7 +239,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) | ||||||
| 	int oldlen, newlen; | 	int oldlen, newlen; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); | 	namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); | ||||||
| 	if (!namep) | 	if (!namep) | ||||||
|  | @ -275,7 +262,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, | ||||||
| 	struct fdt_property *prop; | 	struct fdt_property *prop; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); | 	err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); | ||||||
| 	if (err == -FDT_ERR_NOTFOUND) | 	if (err == -FDT_ERR_NOTFOUND) | ||||||
|  | @ -308,7 +295,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, | ||||||
| 	struct fdt_property *prop; | 	struct fdt_property *prop; | ||||||
| 	int err, oldlen, newlen; | 	int err, oldlen, newlen; | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); | 	prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); | ||||||
| 	if (prop) { | 	if (prop) { | ||||||
|  | @ -334,7 +321,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name) | ||||||
| 	struct fdt_property *prop; | 	struct fdt_property *prop; | ||||||
| 	int len, proplen; | 	int len, proplen; | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	prop = fdt_get_property_w(fdt, nodeoffset, name, &len); | 	prop = fdt_get_property_w(fdt, nodeoffset, name, &len); | ||||||
| 	if (!prop) | 	if (!prop) | ||||||
|  | @ -354,7 +341,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, | ||||||
| 	uint32_t tag; | 	uint32_t tag; | ||||||
| 	fdt32_t *endtag; | 	fdt32_t *endtag; | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); | 	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); | ||||||
| 	if (offset >= 0) | 	if (offset >= 0) | ||||||
|  | @ -394,7 +381,7 @@ int fdt_del_node(void *fdt, int nodeoffset) | ||||||
| { | { | ||||||
| 	int endoffset; | 	int endoffset; | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	endoffset = fdt_node_end_offset_(fdt, nodeoffset); | 	endoffset = fdt_node_end_offset_(fdt, nodeoffset); | ||||||
| 	if (endoffset < 0) | 	if (endoffset < 0) | ||||||
|  | @ -435,12 +422,12 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) | ||||||
| 	const char *fdtend = fdtstart + fdt_totalsize(fdt); | 	const char *fdtend = fdtstart + fdt_totalsize(fdt); | ||||||
| 	char *tmp; | 	char *tmp; | ||||||
| 
 | 
 | ||||||
| 	FDT_CHECK_HEADER(fdt); | 	FDT_RO_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) | 	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) | ||||||
| 		* sizeof(struct fdt_reserve_entry); | 		* sizeof(struct fdt_reserve_entry); | ||||||
| 
 | 
 | ||||||
| 	if (fdt_version(fdt) >= 17) { | 	if (!fdt_chk_version() || fdt_version(fdt) >= 17) { | ||||||
| 		struct_size = fdt_size_dt_struct(fdt); | 		struct_size = fdt_size_dt_struct(fdt); | ||||||
| 	} else { | 	} else { | ||||||
| 		struct_size = 0; | 		struct_size = 0; | ||||||
|  | @ -494,7 +481,7 @@ int fdt_pack(void *fdt) | ||||||
| { | { | ||||||
| 	int mem_rsv_size; | 	int mem_rsv_size; | ||||||
| 
 | 
 | ||||||
| 	FDT_RW_CHECK_HEADER(fdt); | 	FDT_RW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) | 	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) | ||||||
| 		* sizeof(struct fdt_reserve_entry); | 		* sizeof(struct fdt_reserve_entry); | ||||||
|  |  | ||||||
|  | @ -1,51 +1,7 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
|  | @ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = { | ||||||
| 	FDT_ERRTABENT(FDT_ERR_BADVALUE), | 	FDT_ERRTABENT(FDT_ERR_BADVALUE), | ||||||
| 	FDT_ERRTABENT(FDT_ERR_BADOVERLAY), | 	FDT_ERRTABENT(FDT_ERR_BADOVERLAY), | ||||||
| 	FDT_ERRTABENT(FDT_ERR_NOPHANDLES), | 	FDT_ERRTABENT(FDT_ERR_NOPHANDLES), | ||||||
|  | 	FDT_ERRTABENT(FDT_ERR_BADFLAGS), | ||||||
| }; | }; | ||||||
| #define FDT_ERRTABSIZE	(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) | #define FDT_ERRTABSIZE	(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,52 +1,7 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
| 
 | 
 | ||||||
|  | @ -55,21 +10,90 @@ | ||||||
| 
 | 
 | ||||||
| #include "libfdt_internal.h" | #include "libfdt_internal.h" | ||||||
| 
 | 
 | ||||||
| static int fdt_sw_check_header_(void *fdt) | static int fdt_sw_probe_(void *fdt) | ||||||
| { | { | ||||||
| 	if (fdt_magic(fdt) != FDT_SW_MAGIC) | 	if (fdt_chk_basic()) { | ||||||
| 		return -FDT_ERR_BADMAGIC; | 		if (fdt_magic(fdt) == FDT_MAGIC) | ||||||
| 	/* FIXME: should check more details about the header state */ | 			return -FDT_ERR_BADSTATE; | ||||||
|  | 		else if (fdt_magic(fdt) != FDT_SW_MAGIC) | ||||||
|  | 			return -FDT_ERR_BADMAGIC; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define FDT_SW_CHECK_HEADER(fdt) \ | #define FDT_SW_PROBE(fdt) \ | ||||||
| 	{ \ | 	{ \ | ||||||
| 		int err; \ | 		int err; \ | ||||||
| 		if ((err = fdt_sw_check_header_(fdt)) != 0) \ | 		if (fdt_chk_basic() && (err = fdt_sw_probe_(fdt)) != 0) \ | ||||||
| 			return err; \ | 			return err; \ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | /* 'memrsv' state:	Initial state after fdt_create()
 | ||||||
|  |  * | ||||||
|  |  * Allowed functions: | ||||||
|  |  *	fdt_add_reservmap_entry() | ||||||
|  |  *	fdt_finish_reservemap()		[moves to 'struct' state] | ||||||
|  |  */ | ||||||
|  | static int fdt_sw_probe_memrsv_(void *fdt) | ||||||
|  | { | ||||||
|  | 	int err = fdt_sw_probe_(fdt); | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	if (fdt_chk_extra() && fdt_off_dt_strings(fdt) != 0) | ||||||
|  | 		return -FDT_ERR_BADSTATE; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define FDT_SW_PROBE_MEMRSV(fdt) \ | ||||||
|  | 	{ \ | ||||||
|  | 		int err; \ | ||||||
|  | 		if (fdt_chk_extra() && (err = fdt_sw_probe_memrsv_(fdt)) != 0) \ | ||||||
|  | 			return err; \ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | /* 'struct' state:	Enter this state after fdt_finish_reservemap()
 | ||||||
|  |  * | ||||||
|  |  * Allowed functions: | ||||||
|  |  *	fdt_begin_node() | ||||||
|  |  *	fdt_end_node() | ||||||
|  |  *	fdt_property*() | ||||||
|  |  *	fdt_finish()			[moves to 'complete' state] | ||||||
|  |  */ | ||||||
|  | static int fdt_sw_probe_struct_(void *fdt) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	if (!fdt_chk_extra()) | ||||||
|  | 		return 0; | ||||||
|  | 	err = fdt_sw_probe_(fdt); | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) | ||||||
|  | 		return -FDT_ERR_BADSTATE; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define FDT_SW_PROBE_STRUCT(fdt) \ | ||||||
|  | 	{ \ | ||||||
|  | 		int err; \ | ||||||
|  | 		if (fdt_chk_extra() && (err = fdt_sw_probe_struct_(fdt)) != 0) \ | ||||||
|  | 			return err; \ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | static inline uint32_t sw_flags(void *fdt) | ||||||
|  | { | ||||||
|  | 	/* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */ | ||||||
|  | 	return fdt_last_comp_version(fdt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* 'complete' state:	Enter this state after fdt_finish()
 | ||||||
|  |  * | ||||||
|  |  * Allowed functions: none | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
| static void *fdt_grab_space_(void *fdt, size_t len) | static void *fdt_grab_space_(void *fdt, size_t len) | ||||||
| { | { | ||||||
| 	int offset = fdt_size_dt_struct(fdt); | 	int offset = fdt_size_dt_struct(fdt); | ||||||
|  | @ -85,38 +109,58 @@ static void *fdt_grab_space_(void *fdt, size_t len) | ||||||
| 	return fdt_offset_ptr_w_(fdt, offset); | 	return fdt_offset_ptr_w_(fdt, offset); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int fdt_create(void *buf, int bufsize) | int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) | ||||||
| { | { | ||||||
|  | 	const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header), | ||||||
|  | 					 sizeof(struct fdt_reserve_entry)); | ||||||
| 	void *fdt = buf; | 	void *fdt = buf; | ||||||
| 
 | 
 | ||||||
| 	if (bufsize < sizeof(struct fdt_header)) | 	if (bufsize < hdrsize) | ||||||
| 		return -FDT_ERR_NOSPACE; | 		return -FDT_ERR_NOSPACE; | ||||||
| 
 | 
 | ||||||
|  | 	if (flags & ~FDT_CREATE_FLAGS_ALL) | ||||||
|  | 		return -FDT_ERR_BADFLAGS; | ||||||
|  | 
 | ||||||
| 	memset(buf, 0, bufsize); | 	memset(buf, 0, bufsize); | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * magic and last_comp_version keep intermediate state during the fdt | ||||||
|  | 	 * creation process, which is replaced with the proper FDT format by | ||||||
|  | 	 * fdt_finish(). | ||||||
|  | 	 * | ||||||
|  | 	 * flags should be accessed with sw_flags(). | ||||||
|  | 	 */ | ||||||
| 	fdt_set_magic(fdt, FDT_SW_MAGIC); | 	fdt_set_magic(fdt, FDT_SW_MAGIC); | ||||||
| 	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); | 	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); | ||||||
| 	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); | 	fdt_set_last_comp_version(fdt, flags); | ||||||
|  | 
 | ||||||
| 	fdt_set_totalsize(fdt,  bufsize); | 	fdt_set_totalsize(fdt,  bufsize); | ||||||
| 
 | 
 | ||||||
| 	fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), | 	fdt_set_off_mem_rsvmap(fdt, hdrsize); | ||||||
| 					      sizeof(struct fdt_reserve_entry))); |  | ||||||
| 	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); | 	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); | ||||||
| 	fdt_set_off_dt_strings(fdt, bufsize); | 	fdt_set_off_dt_strings(fdt, 0); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int fdt_create(void *buf, int bufsize) | ||||||
|  | { | ||||||
|  | 	return fdt_create_with_flags(buf, bufsize, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int fdt_resize(void *fdt, void *buf, int bufsize) | int fdt_resize(void *fdt, void *buf, int bufsize) | ||||||
| { | { | ||||||
| 	size_t headsize, tailsize; | 	size_t headsize, tailsize; | ||||||
| 	char *oldtail, *newtail; | 	char *oldtail, *newtail; | ||||||
| 
 | 
 | ||||||
| 	FDT_SW_CHECK_HEADER(fdt); | 	FDT_SW_PROBE(fdt); | ||||||
| 
 | 
 | ||||||
| 	headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); | 	headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); | ||||||
| 	tailsize = fdt_size_dt_strings(fdt); | 	tailsize = fdt_size_dt_strings(fdt); | ||||||
| 
 | 
 | ||||||
|  | 	if (fdt_chk_extra() && (headsize + tailsize) > fdt_totalsize(fdt)) | ||||||
|  | 		return -FDT_ERR_INTERNAL; | ||||||
|  | 
 | ||||||
| 	if ((headsize + tailsize) > bufsize) | 	if ((headsize + tailsize) > bufsize) | ||||||
| 		return -FDT_ERR_NOSPACE; | 		return -FDT_ERR_NOSPACE; | ||||||
| 
 | 
 | ||||||
|  | @ -133,8 +177,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize) | ||||||
| 		memmove(buf, fdt, headsize); | 		memmove(buf, fdt, headsize); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fdt_set_off_dt_strings(buf, bufsize); |  | ||||||
| 	fdt_set_totalsize(buf, bufsize); | 	fdt_set_totalsize(buf, bufsize); | ||||||
|  | 	if (fdt_off_dt_strings(buf)) | ||||||
|  | 		fdt_set_off_dt_strings(buf, bufsize); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -144,10 +189,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) | ||||||
| 	struct fdt_reserve_entry *re; | 	struct fdt_reserve_entry *re; | ||||||
| 	int offset; | 	int offset; | ||||||
| 
 | 
 | ||||||
| 	FDT_SW_CHECK_HEADER(fdt); | 	FDT_SW_PROBE_MEMRSV(fdt); | ||||||
| 
 |  | ||||||
| 	if (fdt_size_dt_struct(fdt)) |  | ||||||
| 		return -FDT_ERR_BADSTATE; |  | ||||||
| 
 | 
 | ||||||
| 	offset = fdt_off_dt_struct(fdt); | 	offset = fdt_off_dt_struct(fdt); | ||||||
| 	if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) | 	if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) | ||||||
|  | @ -164,16 +206,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) | ||||||
| 
 | 
 | ||||||
| int fdt_finish_reservemap(void *fdt) | int fdt_finish_reservemap(void *fdt) | ||||||
| { | { | ||||||
| 	return fdt_add_reservemap_entry(fdt, 0, 0); | 	int err = fdt_add_reservemap_entry(fdt, 0, 0); | ||||||
|  | 
 | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); | ||||||
|  | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int fdt_begin_node(void *fdt, const char *name) | int fdt_begin_node(void *fdt, const char *name) | ||||||
| { | { | ||||||
| 	struct fdt_node_header *nh; | 	struct fdt_node_header *nh; | ||||||
| 	int namelen = strlen(name) + 1; | 	int namelen; | ||||||
| 
 | 
 | ||||||
| 	FDT_SW_CHECK_HEADER(fdt); | 	FDT_SW_PROBE_STRUCT(fdt); | ||||||
| 
 | 
 | ||||||
|  | 	namelen = strlen(name) + 1; | ||||||
| 	nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); | 	nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); | ||||||
| 	if (! nh) | 	if (! nh) | ||||||
| 		return -FDT_ERR_NOSPACE; | 		return -FDT_ERR_NOSPACE; | ||||||
|  | @ -187,7 +236,7 @@ int fdt_end_node(void *fdt) | ||||||
| { | { | ||||||
| 	fdt32_t *en; | 	fdt32_t *en; | ||||||
| 
 | 
 | ||||||
| 	FDT_SW_CHECK_HEADER(fdt); | 	FDT_SW_PROBE_STRUCT(fdt); | ||||||
| 
 | 
 | ||||||
| 	en = fdt_grab_space_(fdt, FDT_TAGSIZE); | 	en = fdt_grab_space_(fdt, FDT_TAGSIZE); | ||||||
| 	if (! en) | 	if (! en) | ||||||
|  | @ -197,19 +246,13 @@ int fdt_end_node(void *fdt) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int fdt_find_add_string_(void *fdt, const char *s) | static int fdt_add_string_(void *fdt, const char *s) | ||||||
| { | { | ||||||
| 	char *strtab = (char *)fdt + fdt_totalsize(fdt); | 	char *strtab = (char *)fdt + fdt_totalsize(fdt); | ||||||
| 	const char *p; |  | ||||||
| 	int strtabsize = fdt_size_dt_strings(fdt); | 	int strtabsize = fdt_size_dt_strings(fdt); | ||||||
| 	int len = strlen(s) + 1; | 	int len = strlen(s) + 1; | ||||||
| 	int struct_top, offset; | 	int struct_top, offset; | ||||||
| 
 | 
 | ||||||
| 	p = fdt_find_string_(strtab - strtabsize, strtabsize, s); |  | ||||||
| 	if (p) |  | ||||||
| 		return p - strtab; |  | ||||||
| 
 |  | ||||||
| 	/* Add it */ |  | ||||||
| 	offset = -strtabsize - len; | 	offset = -strtabsize - len; | ||||||
| 	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); | 	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); | ||||||
| 	if (fdt_totalsize(fdt) + offset < struct_top) | 	if (fdt_totalsize(fdt) + offset < struct_top) | ||||||
|  | @ -220,20 +263,56 @@ static int fdt_find_add_string_(void *fdt, const char *s) | ||||||
| 	return offset; | 	return offset; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* Must only be used to roll back in case of error */ | ||||||
|  | static void fdt_del_last_string_(void *fdt, const char *s) | ||||||
|  | { | ||||||
|  | 	int strtabsize = fdt_size_dt_strings(fdt); | ||||||
|  | 	int len = strlen(s) + 1; | ||||||
|  | 
 | ||||||
|  | 	fdt_set_size_dt_strings(fdt, strtabsize - len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) | ||||||
|  | { | ||||||
|  | 	char *strtab = (char *)fdt + fdt_totalsize(fdt); | ||||||
|  | 	int strtabsize = fdt_size_dt_strings(fdt); | ||||||
|  | 	const char *p; | ||||||
|  | 
 | ||||||
|  | 	*allocated = 0; | ||||||
|  | 
 | ||||||
|  | 	p = fdt_find_string_(strtab - strtabsize, strtabsize, s); | ||||||
|  | 	if (p) | ||||||
|  | 		return p - strtab; | ||||||
|  | 
 | ||||||
|  | 	*allocated = 1; | ||||||
|  | 
 | ||||||
|  | 	return fdt_add_string_(fdt, s); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) | int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) | ||||||
| { | { | ||||||
| 	struct fdt_property *prop; | 	struct fdt_property *prop; | ||||||
| 	int nameoff; | 	int nameoff; | ||||||
|  | 	int allocated; | ||||||
| 
 | 
 | ||||||
| 	FDT_SW_CHECK_HEADER(fdt); | 	FDT_SW_PROBE_STRUCT(fdt); | ||||||
| 
 | 
 | ||||||
| 	nameoff = fdt_find_add_string_(fdt, name); | 	/* String de-duplication can be slow, _NO_NAME_DEDUP skips it */ | ||||||
|  | 	if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) { | ||||||
|  | 		allocated = 1; | ||||||
|  | 		nameoff = fdt_add_string_(fdt, name); | ||||||
|  | 	} else { | ||||||
|  | 		nameoff = fdt_find_add_string_(fdt, name, &allocated); | ||||||
|  | 	} | ||||||
| 	if (nameoff == 0) | 	if (nameoff == 0) | ||||||
| 		return -FDT_ERR_NOSPACE; | 		return -FDT_ERR_NOSPACE; | ||||||
| 
 | 
 | ||||||
| 	prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); | 	prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); | ||||||
| 	if (! prop) | 	if (! prop) { | ||||||
|  | 		if (allocated) | ||||||
|  | 			fdt_del_last_string_(fdt, name); | ||||||
| 		return -FDT_ERR_NOSPACE; | 		return -FDT_ERR_NOSPACE; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	prop->tag = cpu_to_fdt32(FDT_PROP); | 	prop->tag = cpu_to_fdt32(FDT_PROP); | ||||||
| 	prop->nameoff = cpu_to_fdt32(nameoff); | 	prop->nameoff = cpu_to_fdt32(nameoff); | ||||||
|  | @ -262,7 +341,7 @@ int fdt_finish(void *fdt) | ||||||
| 	uint32_t tag; | 	uint32_t tag; | ||||||
| 	int offset, nextoffset; | 	int offset, nextoffset; | ||||||
| 
 | 
 | ||||||
| 	FDT_SW_CHECK_HEADER(fdt); | 	FDT_SW_PROBE_STRUCT(fdt); | ||||||
| 
 | 
 | ||||||
| 	/* Add terminator */ | 	/* Add terminator */ | ||||||
| 	end = fdt_grab_space_(fdt, sizeof(*end)); | 	end = fdt_grab_space_(fdt, sizeof(*end)); | ||||||
|  | @ -295,6 +374,10 @@ int fdt_finish(void *fdt) | ||||||
| 
 | 
 | ||||||
| 	/* Finally, adjust the header */ | 	/* Finally, adjust the header */ | ||||||
| 	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); | 	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); | ||||||
|  | 
 | ||||||
|  | 	/* And fix up fields that were keeping intermediate state. */ | ||||||
|  | 	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); | ||||||
| 	fdt_set_magic(fdt, FDT_MAGIC); | 	fdt_set_magic(fdt, FDT_MAGIC); | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,52 +1,7 @@ | ||||||
|  | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
 | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,54 +1,9 @@ | ||||||
|  | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ | ||||||
| #ifndef LIBFDT_H | #ifndef LIBFDT_H | ||||||
| #define LIBFDT_H | #define LIBFDT_H | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include "libfdt_env.h" | #include "libfdt_env.h" | ||||||
|  | @ -90,8 +45,9 @@ | ||||||
| 
 | 
 | ||||||
| /* Error codes: codes for bad device tree blobs */ | /* Error codes: codes for bad device tree blobs */ | ||||||
| #define FDT_ERR_TRUNCATED	8 | #define FDT_ERR_TRUNCATED	8 | ||||||
| 	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
 | 	/* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
 | ||||||
| 	 * ends without an FDT_END tag. */ | 	 * terminated (overflows, goes outside allowed bounds, or | ||||||
|  | 	 * isn't properly terminated).  */ | ||||||
| #define FDT_ERR_BADMAGIC	9 | #define FDT_ERR_BADMAGIC	9 | ||||||
| 	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
 | 	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
 | ||||||
| 	 * device tree at all - it is missing the flattened device | 	 * device tree at all - it is missing the flattened device | ||||||
|  | @ -137,7 +93,11 @@ | ||||||
| 	/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
 | 	/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
 | ||||||
| 	 * phandle available anymore without causing an overflow */ | 	 * phandle available anymore without causing an overflow */ | ||||||
| 
 | 
 | ||||||
| #define FDT_ERR_MAX		17 | #define FDT_ERR_BADFLAGS	18 | ||||||
|  | 	/* FDT_ERR_BADFLAGS: The function was passed a flags field that
 | ||||||
|  | 	 * contains invalid flags or an invalid combination of flags. */ | ||||||
|  | 
 | ||||||
|  | #define FDT_ERR_MAX		18 | ||||||
| 
 | 
 | ||||||
| /* constants */ | /* constants */ | ||||||
| #define FDT_MAX_PHANDLE 0xfffffffe | #define FDT_MAX_PHANDLE 0xfffffffe | ||||||
|  | @ -157,6 +117,61 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) | ||||||
| 
 | 
 | ||||||
| uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); | uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Alignment helpers: | ||||||
|  |  *     These helpers access words from a device tree blob.  They're | ||||||
|  |  *     built to work even with unaligned pointers on platforms (ike | ||||||
|  |  *     ARM) that don't like unaligned loads and stores | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | static inline uint32_t fdt32_ld(const fdt32_t *p) | ||||||
|  | { | ||||||
|  | 	const uint8_t *bp = (const uint8_t *)p; | ||||||
|  | 
 | ||||||
|  | 	return ((uint32_t)bp[0] << 24) | ||||||
|  | 		| ((uint32_t)bp[1] << 16) | ||||||
|  | 		| ((uint32_t)bp[2] << 8) | ||||||
|  | 		| bp[3]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void fdt32_st(void *property, uint32_t value) | ||||||
|  | { | ||||||
|  | 	uint8_t *bp = (uint8_t *)property; | ||||||
|  | 
 | ||||||
|  | 	bp[0] = value >> 24; | ||||||
|  | 	bp[1] = (value >> 16) & 0xff; | ||||||
|  | 	bp[2] = (value >> 8) & 0xff; | ||||||
|  | 	bp[3] = value & 0xff; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline uint64_t fdt64_ld(const fdt64_t *p) | ||||||
|  | { | ||||||
|  | 	const uint8_t *bp = (const uint8_t *)p; | ||||||
|  | 
 | ||||||
|  | 	return ((uint64_t)bp[0] << 56) | ||||||
|  | 		| ((uint64_t)bp[1] << 48) | ||||||
|  | 		| ((uint64_t)bp[2] << 40) | ||||||
|  | 		| ((uint64_t)bp[3] << 32) | ||||||
|  | 		| ((uint64_t)bp[4] << 24) | ||||||
|  | 		| ((uint64_t)bp[5] << 16) | ||||||
|  | 		| ((uint64_t)bp[6] << 8) | ||||||
|  | 		| bp[7]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void fdt64_st(void *property, uint64_t value) | ||||||
|  | { | ||||||
|  | 	uint8_t *bp = (uint8_t *)property; | ||||||
|  | 
 | ||||||
|  | 	bp[0] = value >> 56; | ||||||
|  | 	bp[1] = (value >> 48) & 0xff; | ||||||
|  | 	bp[2] = (value >> 40) & 0xff; | ||||||
|  | 	bp[3] = (value >> 32) & 0xff; | ||||||
|  | 	bp[4] = (value >> 24) & 0xff; | ||||||
|  | 	bp[5] = (value >> 16) & 0xff; | ||||||
|  | 	bp[6] = (value >> 8) & 0xff; | ||||||
|  | 	bp[7] = value & 0xff; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**********************************************************************/ | /**********************************************************************/ | ||||||
| /* Traversal functions                                                */ | /* Traversal functions                                                */ | ||||||
| /**********************************************************************/ | /**********************************************************************/ | ||||||
|  | @ -199,7 +214,7 @@ int fdt_next_subnode(const void *fdt, int offset); | ||||||
|  *		... |  *		... | ||||||
|  *	} |  *	} | ||||||
|  * |  * | ||||||
|  *	if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { |  *	if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) { | ||||||
|  *		Error handling |  *		Error handling | ||||||
|  *	} |  *	} | ||||||
|  * |  * | ||||||
|  | @ -217,7 +232,7 @@ int fdt_next_subnode(const void *fdt, int offset); | ||||||
| /* General functions                                                  */ | /* General functions                                                  */ | ||||||
| /**********************************************************************/ | /**********************************************************************/ | ||||||
| #define fdt_get_header(fdt, field) \ | #define fdt_get_header(fdt, field) \ | ||||||
| 	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) | 	(fdt32_ld(&((const struct fdt_header *)(fdt))->field)) | ||||||
| #define fdt_magic(fdt)			(fdt_get_header(fdt, magic)) | #define fdt_magic(fdt)			(fdt_get_header(fdt, magic)) | ||||||
| #define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize)) | #define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize)) | ||||||
| #define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct)) | #define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct)) | ||||||
|  | @ -248,18 +263,32 @@ fdt_set_hdr_(size_dt_struct); | ||||||
| #undef fdt_set_hdr_ | #undef fdt_set_hdr_ | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * fdt_check_header - sanity check a device tree or possible device tree |  * fdt_header_size - return the size of the tree's header | ||||||
|  |  * @fdt: pointer to a flattened device tree | ||||||
|  |  */ | ||||||
|  | size_t fdt_header_size(const void *fdt); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * fdt_header_size_ - internal function which takes a version number | ||||||
|  |  */ | ||||||
|  | size_t fdt_header_size_(uint32_t version); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * fdt_check_header - sanity check a device tree header | ||||||
|  | 
 | ||||||
|  * @fdt: pointer to data which might be a flattened device tree |  * @fdt: pointer to data which might be a flattened device tree | ||||||
|  * |  * | ||||||
|  * fdt_check_header() checks that the given buffer contains what |  * fdt_check_header() checks that the given buffer contains what | ||||||
|  * appears to be a flattened device tree with sane information in its |  * appears to be a flattened device tree, and that the header contains | ||||||
|  * header. |  * valid information (to the extent that can be determined from the | ||||||
|  |  * header alone). | ||||||
|  * |  * | ||||||
|  * returns: |  * returns: | ||||||
|  *     0, if the buffer appears to contain a valid device tree |  *     0, if the buffer appears to contain a valid device tree | ||||||
|  *     -FDT_ERR_BADMAGIC, |  *     -FDT_ERR_BADMAGIC, | ||||||
|  *     -FDT_ERR_BADVERSION, |  *     -FDT_ERR_BADVERSION, | ||||||
|  *     -FDT_ERR_BADSTATE, standard meanings, as above |  *     -FDT_ERR_BADSTATE, | ||||||
|  |  *     -FDT_ERR_TRUNCATED, standard meanings, as above | ||||||
|  */ |  */ | ||||||
| int fdt_check_header(const void *fdt); | int fdt_check_header(const void *fdt); | ||||||
| 
 | 
 | ||||||
|  | @ -288,6 +317,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize); | ||||||
| /* Read-only functions                                                */ | /* Read-only functions                                                */ | ||||||
| /**********************************************************************/ | /**********************************************************************/ | ||||||
| 
 | 
 | ||||||
|  | int fdt_check_full(const void *fdt, size_t bufsize); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * fdt_get_string - retrieve a string from the strings block of a device tree | ||||||
|  |  * @fdt: pointer to the device tree blob | ||||||
|  |  * @stroffset: offset of the string within the strings block (native endian) | ||||||
|  |  * @lenp: optional pointer to return the string's length | ||||||
|  |  * | ||||||
|  |  * fdt_get_string() retrieves a pointer to a single string from the | ||||||
|  |  * strings block of the device tree blob at fdt, and optionally also | ||||||
|  |  * returns the string's length in *lenp. | ||||||
|  |  * | ||||||
|  |  * returns: | ||||||
|  |  *     a pointer to the string, on success | ||||||
|  |  *     NULL, if stroffset is out of bounds, or doesn't point to a valid string | ||||||
|  |  */ | ||||||
|  | const char *fdt_get_string(const void *fdt, int stroffset, int *lenp); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * fdt_string - retrieve a string from the strings block of a device tree |  * fdt_string - retrieve a string from the strings block of a device tree | ||||||
|  * @fdt: pointer to the device tree blob |  * @fdt: pointer to the device tree blob | ||||||
|  | @ -298,10 +345,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize); | ||||||
|  * |  * | ||||||
|  * returns: |  * returns: | ||||||
|  *     a pointer to the string, on success |  *     a pointer to the string, on success | ||||||
|  *     NULL, if stroffset is out of bounds |  *     NULL, if stroffset is out of bounds, or doesn't point to a valid string | ||||||
|  */ |  */ | ||||||
| const char *fdt_string(const void *fdt, int stroffset); | const char *fdt_string(const void *fdt, int stroffset); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * fdt_find_max_phandle - find and return the highest phandle in a tree | ||||||
|  |  * @fdt: pointer to the device tree blob | ||||||
|  |  * @phandle: return location for the highest phandle value found in the tree | ||||||
|  |  * | ||||||
|  |  * fdt_find_max_phandle() finds the highest phandle value in the given device | ||||||
|  |  * tree. The value returned in @phandle is only valid if the function returns | ||||||
|  |  * success. | ||||||
|  |  * | ||||||
|  |  * returns: | ||||||
|  |  *     0 on success or a negative error code on failure | ||||||
|  |  */ | ||||||
|  | int fdt_find_max_phandle(const void *fdt, uint32_t *phandle); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * fdt_get_max_phandle - retrieves the highest phandle in a tree |  * fdt_get_max_phandle - retrieves the highest phandle in a tree | ||||||
|  * @fdt: pointer to the device tree blob |  * @fdt: pointer to the device tree blob | ||||||
|  | @ -310,12 +371,24 @@ const char *fdt_string(const void *fdt, int stroffset); | ||||||
|  * device tree. This will ignore badly formatted phandles, or phandles |  * device tree. This will ignore badly formatted phandles, or phandles | ||||||
|  * with a value of 0 or -1. |  * with a value of 0 or -1. | ||||||
|  * |  * | ||||||
|  |  * This function is deprecated in favour of fdt_find_max_phandle(). | ||||||
|  |  * | ||||||
|  * returns: |  * returns: | ||||||
|  *      the highest phandle on success |  *      the highest phandle on success | ||||||
|  *      0, if no phandle was found in the device tree |  *      0, if no phandle was found in the device tree | ||||||
|  *      -1, if an error occurred |  *      -1, if an error occurred | ||||||
|  */ |  */ | ||||||
| uint32_t fdt_get_max_phandle(const void *fdt); | static inline uint32_t fdt_get_max_phandle(const void *fdt) | ||||||
|  | { | ||||||
|  | 	uint32_t phandle; | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	err = fdt_find_max_phandle(fdt, &phandle); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return (uint32_t)-1; | ||||||
|  | 
 | ||||||
|  | 	return phandle; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * fdt_generate_phandle - return a new, unused phandle for a device tree blob |  * fdt_generate_phandle - return a new, unused phandle for a device tree blob | ||||||
|  | @ -522,7 +595,7 @@ int fdt_next_property_offset(const void *fdt, int offset); | ||||||
|  *		... |  *		... | ||||||
|  *	} |  *	} | ||||||
|  * |  * | ||||||
|  *	if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { |  *	if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) { | ||||||
|  *		Error handling |  *		Error handling | ||||||
|  *	} |  *	} | ||||||
|  * |  * | ||||||
|  | @ -625,7 +698,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, | ||||||
| /**
 | /**
 | ||||||
|  * fdt_getprop_by_offset - retrieve the value of a property at a given offset |  * fdt_getprop_by_offset - retrieve the value of a property at a given offset | ||||||
|  * @fdt: pointer to the device tree blob |  * @fdt: pointer to the device tree blob | ||||||
|  * @ffset: offset of the property to read |  * @offset: offset of the property to read | ||||||
|  * @namep: pointer to a string variable (will be overwritten) or NULL |  * @namep: pointer to a string variable (will be overwritten) or NULL | ||||||
|  * @lenp: pointer to an integer variable (will be overwritten) or NULL |  * @lenp: pointer to an integer variable (will be overwritten) or NULL | ||||||
|  * |  * | ||||||
|  | @ -734,7 +807,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); | ||||||
| /**
 | /**
 | ||||||
|  * fdt_get_alias_namelen - get alias based on substring |  * fdt_get_alias_namelen - get alias based on substring | ||||||
|  * @fdt: pointer to the device tree blob |  * @fdt: pointer to the device tree blob | ||||||
|  * @name: name of the alias to look up |  * @name: name of the alias th look up | ||||||
|  * @namelen: number of characters of name to consider |  * @namelen: number of characters of name to consider | ||||||
|  * |  * | ||||||
|  * Identical to fdt_get_alias(), but only examine the first namelen |  * Identical to fdt_get_alias(), but only examine the first namelen | ||||||
|  | @ -1316,7 +1389,45 @@ int fdt_nop_node(void *fdt, int nodeoffset); | ||||||
| /* Sequential write functions                                         */ | /* Sequential write functions                                         */ | ||||||
| /**********************************************************************/ | /**********************************************************************/ | ||||||
| 
 | 
 | ||||||
|  | /* fdt_create_with_flags flags */ | ||||||
|  | #define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1 | ||||||
|  | 	/* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
 | ||||||
|  | 	 * names in the fdt. This can result in faster creation times, but | ||||||
|  | 	 * a larger fdt. */ | ||||||
|  | 
 | ||||||
|  | #define FDT_CREATE_FLAGS_ALL	(FDT_CREATE_FLAG_NO_NAME_DEDUP) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * fdt_create_with_flags - begin creation of a new fdt | ||||||
|  |  * @fdt: pointer to memory allocated where fdt will be created | ||||||
|  |  * @bufsize: size of the memory space at fdt | ||||||
|  |  * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0. | ||||||
|  |  * | ||||||
|  |  * fdt_create_with_flags() begins the process of creating a new fdt with | ||||||
|  |  * the sequential write interface. | ||||||
|  |  * | ||||||
|  |  * fdt creation process must end with fdt_finished() to produce a valid fdt. | ||||||
|  |  * | ||||||
|  |  * returns: | ||||||
|  |  *	0, on success | ||||||
|  |  *	-FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt | ||||||
|  |  *	-FDT_ERR_BADFLAGS, flags is not valid | ||||||
|  |  */ | ||||||
|  | int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * fdt_create - begin creation of a new fdt | ||||||
|  |  * @fdt: pointer to memory allocated where fdt will be created | ||||||
|  |  * @bufsize: size of the memory space at fdt | ||||||
|  |  * | ||||||
|  |  * fdt_create() is equivalent to fdt_create_with_flags() with flags=0. | ||||||
|  |  * | ||||||
|  |  * returns: | ||||||
|  |  *	0, on success | ||||||
|  |  *	-FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt | ||||||
|  |  */ | ||||||
| int fdt_create(void *buf, int bufsize); | int fdt_create(void *buf, int bufsize); | ||||||
|  | 
 | ||||||
| int fdt_resize(void *fdt, void *buf, int bufsize); | int fdt_resize(void *fdt, void *buf, int bufsize); | ||||||
| int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); | int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); | ||||||
| int fdt_finish_reservemap(void *fdt); | int fdt_finish_reservemap(void *fdt); | ||||||
|  | @ -1787,6 +1898,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, | ||||||
| #define fdt_appendprop_string(fdt, nodeoffset, name, str) \ | #define fdt_appendprop_string(fdt, nodeoffset, name, str) \ | ||||||
| 	fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) | 	fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * fdt_appendprop_addrrange - append a address range property | ||||||
|  |  * @fdt: pointer to the device tree blob | ||||||
|  |  * @parent: offset of the parent node | ||||||
|  |  * @nodeoffset: offset of the node to add a property at | ||||||
|  |  * @name: name of property | ||||||
|  |  * @addr: start address of a given range | ||||||
|  |  * @size: size of a given range | ||||||
|  |  * | ||||||
|  |  * fdt_appendprop_addrrange() appends an address range value (start | ||||||
|  |  * address and size) to the value of the named property in the given | ||||||
|  |  * node, or creates a new property with that value if it does not | ||||||
|  |  * already exist. | ||||||
|  |  * If "name" is not specified, a default "reg" is used. | ||||||
|  |  * Cell sizes are determined by parent's #address-cells and #size-cells. | ||||||
|  |  * | ||||||
|  |  * This function may insert data into the blob, and will therefore | ||||||
|  |  * change the offsets of some existing nodes. | ||||||
|  |  * | ||||||
|  |  * returns: | ||||||
|  |  *	0, on success | ||||||
|  |  *	-FDT_ERR_BADLAYOUT, | ||||||
|  |  *	-FDT_ERR_BADMAGIC, | ||||||
|  |  *	-FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid | ||||||
|  |  *		#address-cells property | ||||||
|  |  *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag | ||||||
|  |  *	-FDT_ERR_BADSTATE, | ||||||
|  |  *	-FDT_ERR_BADSTRUCTURE, | ||||||
|  |  *	-FDT_ERR_BADVERSION, | ||||||
|  |  *	-FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size | ||||||
|  |  *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to | ||||||
|  |  *		contain a new property | ||||||
|  |  *	-FDT_ERR_TRUNCATED, standard meanings | ||||||
|  |  */ | ||||||
|  | int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, | ||||||
|  | 			     const char *name, uint64_t addr, uint64_t size); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * fdt_delprop - delete a property |  * fdt_delprop - delete a property | ||||||
|  * @fdt: pointer to the device tree blob |  * @fdt: pointer to the device tree blob | ||||||
|  |  | ||||||
|  | @ -1,55 +1,10 @@ | ||||||
|  | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ | ||||||
| #ifndef LIBFDT_ENV_H | #ifndef LIBFDT_ENV_H | ||||||
| #define LIBFDT_ENV_H | #define LIBFDT_ENV_H | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * Copyright 2012 Kim Phillips, Freescale Semiconductor. |  * Copyright 2012 Kim Phillips, Freescale Semiconductor. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  | @ -57,6 +12,7 @@ | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <limits.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __CHECKER__ | #ifdef __CHECKER__ | ||||||
| #define FDT_FORCE __attribute__((force)) | #define FDT_FORCE __attribute__((force)) | ||||||
|  |  | ||||||
|  | @ -1,65 +1,24 @@ | ||||||
|  | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ | ||||||
| #ifndef LIBFDT_INTERNAL_H | #ifndef LIBFDT_INTERNAL_H | ||||||
| #define LIBFDT_INTERNAL_H | #define LIBFDT_INTERNAL_H | ||||||
| /*
 | /*
 | ||||||
|  * libfdt - Flat Device Tree manipulation |  * libfdt - Flat Device Tree manipulation | ||||||
|  * Copyright (C) 2006 David Gibson, IBM Corporation. |  * Copyright (C) 2006 David Gibson, IBM Corporation. | ||||||
|  * |  | ||||||
|  * libfdt is dual licensed: you can use it either under the terms of |  | ||||||
|  * the GPL, or the BSD license, at your option. |  | ||||||
|  * |  | ||||||
|  *  a) This library is free software; you can redistribute it and/or |  | ||||||
|  *     modify it under the terms of the GNU General Public License as |  | ||||||
|  *     published by the Free Software Foundation; either version 2 of the |  | ||||||
|  *     License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  *     This library is distributed in the hope that it will be useful, |  | ||||||
|  *     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  *     GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  *     You should have received a copy of the GNU General Public |  | ||||||
|  *     License along with this library; if not, write to the Free |  | ||||||
|  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |  | ||||||
|  *     MA 02110-1301 USA |  | ||||||
|  * |  | ||||||
|  * Alternatively, |  | ||||||
|  * |  | ||||||
|  *  b) Redistribution and use in source and binary forms, with or |  | ||||||
|  *     without modification, are permitted provided that the following |  | ||||||
|  *     conditions are met: |  | ||||||
|  * |  | ||||||
|  *     1. Redistributions of source code must retain the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer. |  | ||||||
|  *     2. Redistributions in binary form must reproduce the above |  | ||||||
|  *        copyright notice, this list of conditions and the following |  | ||||||
|  *        disclaimer in the documentation and/or other materials |  | ||||||
|  *        provided with the distribution. |  | ||||||
|  * |  | ||||||
|  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |  | ||||||
|  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |  | ||||||
|  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
|  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
|  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
|  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |  | ||||||
|  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |  | ||||||
|  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |  | ||||||
|  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |  | ||||||
|  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |  | ||||||
|  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |  | ||||||
|  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  */ | ||||||
| #include <fdt.h> | #include <fdt.h> | ||||||
| 
 | 
 | ||||||
| #define FDT_ALIGN(x, a)		(((x) + (a) - 1) & ~((a) - 1)) | #define FDT_ALIGN(x, a)		(((x) + (a) - 1) & ~((a) - 1)) | ||||||
| #define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE)) | #define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE)) | ||||||
| 
 | 
 | ||||||
| #define FDT_CHECK_HEADER(fdt) \ | int fdt_ro_probe_(const void *fdt); | ||||||
| 	{ \ | #define FDT_RO_PROBE(fdt)					\ | ||||||
| 		int err_; \ | 	{							\ | ||||||
| 		if ((err_ = fdt_check_header(fdt)) != 0) \ | 		int totalsize_;					\ | ||||||
| 			return err_; \ | 		if (fdt_chk_basic()) {				\ | ||||||
|  | 			totalsize_ = fdt_ro_probe_(fdt);	\ | ||||||
|  | 			if (totalsize_ < 0)			\ | ||||||
|  | 				return totalsize_;		\ | ||||||
|  | 		}						\ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| int fdt_check_node_offset_(const void *fdt, int offset); | int fdt_check_node_offset_(const void *fdt, int offset); | ||||||
|  | @ -92,4 +51,87 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) | ||||||
| 
 | 
 | ||||||
| #define FDT_SW_MAGIC		(~FDT_MAGIC) | #define FDT_SW_MAGIC		(~FDT_MAGIC) | ||||||
| 
 | 
 | ||||||
|  | /**********************************************************************/ | ||||||
|  | /* Checking controls                                                  */ | ||||||
|  | /**********************************************************************/ | ||||||
|  | 
 | ||||||
|  | #ifndef FDT_ASSUME_MASK | ||||||
|  | #define FDT_ASSUME_MASK 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Defines assumptions which can be enabled. Each of these can be enabled | ||||||
|  |  * individually. For maximum saftey, don't enable any assumptions! | ||||||
|  |  * | ||||||
|  |  * For minimal code size and no safety, use FDT_ASSUME_PERFECT at your own risk. | ||||||
|  |  * You should have another method of validating the device tree, such as a | ||||||
|  |  * signature or hash check before using libfdt. | ||||||
|  |  * | ||||||
|  |  * For situations where security is not a concern it may be safe to enable | ||||||
|  |  * FDT_ASSUME_FRIENDLY. | ||||||
|  |  */ | ||||||
|  | enum { | ||||||
|  | 	/*
 | ||||||
|  | 	 * This does essentially no checks. Only the latest device-tree | ||||||
|  | 	 * version is correctly handled. Incosistencies or errors in the device | ||||||
|  | 	 * tree may cause undefined behaviour or crashes. | ||||||
|  | 	 * | ||||||
|  | 	 * If an error occurs when modifying the tree it may leave the tree in | ||||||
|  | 	 * an intermediate (but valid) state. As an example, adding a property | ||||||
|  | 	 * where there is insufficient space may result in the property name | ||||||
|  | 	 * being added to the string table even though the property itself is | ||||||
|  | 	 * not added to the struct section. | ||||||
|  | 	 * | ||||||
|  | 	 * Only use this if you have a fully validated device tree with | ||||||
|  | 	 * the latest supported version and wish to minimise code size. | ||||||
|  | 	 */ | ||||||
|  | 	FDT_ASSUME_PERFECT	= 0xff, | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * This assumes that the device tree is sane. i.e. header metadata | ||||||
|  | 	 * and basic hierarchy are correct. | ||||||
|  | 	 * | ||||||
|  | 	 * These checks will be sufficient if you have a valid device tree with | ||||||
|  | 	 * no internal inconsistencies. With this assumption, libfdt will | ||||||
|  | 	 * generally not return -FDT_ERR_INTERNAL, -FDT_ERR_BADLAYOUT, etc. | ||||||
|  | 	 */ | ||||||
|  | 	FDT_ASSUME_SANE		= 1 << 0, | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * This disables checks for device-tree version and removes all code | ||||||
|  | 	 * which handles older versions. | ||||||
|  | 	 * | ||||||
|  | 	 * Only enable this if you know you have a device tree with the latest | ||||||
|  | 	 * version. | ||||||
|  | 	 */ | ||||||
|  | 	FDT_ASSUME_LATEST	= 1 << 1, | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * This disables any extensive checking of parameters and the device | ||||||
|  | 	 * tree, making various assumptions about correctness. Normal device | ||||||
|  | 	 * trees produced by libfdt and the compiler should be handled safely. | ||||||
|  | 	 * Malicious device trees and complete garbage may cause libfdt to | ||||||
|  | 	 * behave badly or crash. | ||||||
|  | 	 */ | ||||||
|  | 	FDT_ASSUME_FRIENDLY	= 1 << 2, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** fdt_chk_basic() - see if basic checking of params and DT data is enabled */ | ||||||
|  | static inline bool fdt_chk_basic(void) | ||||||
|  | { | ||||||
|  | 	return !(FDT_ASSUME_MASK & FDT_ASSUME_SANE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** fdt_chk_version() - see if we need to handle old versions of the DT */ | ||||||
|  | static inline bool fdt_chk_version(void) | ||||||
|  | { | ||||||
|  | 	return !(FDT_ASSUME_MASK & FDT_ASSUME_LATEST); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** fdt_chk_extra() - see if extra checking is enabled */ | ||||||
|  | static inline bool fdt_chk_extra(void) | ||||||
|  | { | ||||||
|  | 	return !(FDT_ASSUME_MASK & FDT_ASSUME_FRIENDLY); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #endif /* LIBFDT_INTERNAL_H */ | #endif /* LIBFDT_INTERNAL_H */ | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ int fdt_remove_unused_strings(const void *old, void *new) | ||||||
| 	const char *str; | 	const char *str; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	int tag = FDT_PROP; | 	int tag = FDT_PROP; | ||||||
|  | 	int allocated; | ||||||
| 
 | 
 | ||||||
| 	/* Make a copy and remove the strings */ | 	/* Make a copy and remove the strings */ | ||||||
| 	memcpy(new, old, size); | 	memcpy(new, old, size); | ||||||
|  | @ -25,7 +26,7 @@ int fdt_remove_unused_strings(const void *old, void *new) | ||||||
| 		new_prop = (struct fdt_property *)(unsigned long) | 		new_prop = (struct fdt_property *)(unsigned long) | ||||||
| 			fdt_get_property_by_offset(new, offset, NULL); | 			fdt_get_property_by_offset(new, offset, NULL); | ||||||
| 		str = fdt_string(old, fdt32_to_cpu(old_prop->nameoff)); | 		str = fdt_string(old, fdt32_to_cpu(old_prop->nameoff)); | ||||||
| 		ret = fdt_find_add_string_(new, str); | 		ret = fdt_find_add_string_(new, str, &allocated); | ||||||
| 		if (ret < 0) | 		if (ret < 0) | ||||||
| 			return ret; | 			return ret; | ||||||
| 		new_prop->nameoff = cpu_to_fdt32(ret); | 		new_prop->nameoff = cpu_to_fdt32(ret); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue