From: Thierry Reding <treding@xxxxxxxxxx> The fdt_get_max_phandle() function has some shortcomings. On one hand it returns a uint32_t phandle value via a signed return value. This means a caller has to explicitly cast the return value to a uint32_t and perform explicit checks against the error code (uint32_t)-1. In addition, the -1 is the only error code that can be returned, so a caller cannot tell the difference between the various failures. Fix this by adding a new fdt_find_max_phandle() function that returns an error code on failure and 0 on success, just like other APIs, and stores the maximum phandle value in an output argument on success. This also refactors fdt_get_max_phandle() to use the new function. Add a note pointing out that the new fdt_find_max_phandle() function should be preferred over fdt_get_max_phandle(). Signed-off-by: Thierry Reding <treding@xxxxxxxxxx> --- Changes in v4: - new patch libfdt/fdt_ro.c | 44 +++++++++++++++++++++++++++++--------------- libfdt/libfdt.h | 16 ++++++++++++++++ libfdt/libfdt_env.h | 1 + libfdt/version.lds | 1 + tests/get_phandle.c | 9 +++++++++ 5 files changed, 56 insertions(+), 15 deletions(-) diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index eafc14282892..1d0335ee7188 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -144,32 +144,46 @@ static int fdt_string_eq_(const void *fdt, int stroffset, 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; + uint32_t max = 0; + int offset = -1; - for (offset = fdt_next_node(fdt, -1, NULL);; - offset = fdt_next_node(fdt, offset, NULL)) { - uint32_t phandle; + while (true) { + uint32_t value; - if (offset == -FDT_ERR_NOTFOUND) - return max_phandle; + offset = fdt_next_node(fdt, offset, NULL); + if (offset < 0) { + if (offset == -FDT_ERR_NOTFOUND) + break; - if (offset < 0) - return (uint32_t)-1; + return offset; + } - phandle = fdt_get_phandle(fdt, offset); - if (phandle == (uint32_t)-1) - continue; + value = fdt_get_phandle(fdt, offset); - if (phandle > max_phandle) - max_phandle = phandle; + if (value > max) + max = value; } + if (phandle) + *phandle = max; + return 0; } +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; +} + static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) { int offset = n * sizeof(struct fdt_reserve_entry); diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h index a470d1df6d2a..6fce659fd279 100644 --- a/libfdt/libfdt.h +++ b/libfdt/libfdt.h @@ -361,6 +361,20 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp); */ 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: pointer to the device tree blob @@ -369,6 +383,8 @@ const char *fdt_string(const void *fdt, int stroffset); * device tree. This will ignore badly formatted phandles, or phandles * with a value of 0 or -1. * + * This function is deprecated in favour of fdt_find_max_phandle(). + * * returns: * the highest phandle on success * 0, if no phandle was found in the device tree diff --git a/libfdt/libfdt_env.h b/libfdt/libfdt_env.h index eb2053845c9c..4d1cdfa58547 100644 --- a/libfdt/libfdt_env.h +++ b/libfdt/libfdt_env.h @@ -52,6 +52,7 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <stdbool.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> diff --git a/libfdt/version.lds b/libfdt/version.lds index a5fe62d5c5ff..87bbb2fe54d3 100644 --- a/libfdt/version.lds +++ b/libfdt/version.lds @@ -66,6 +66,7 @@ LIBFDT_1.2 { fdt_resize; fdt_overlay_apply; fdt_get_string; + fdt_find_max_phandle; fdt_get_max_phandle; fdt_check_full; fdt_setprop_placeholder; diff --git a/tests/get_phandle.c b/tests/get_phandle.c index 22bd7b81b3f0..6973ee4caa17 100644 --- a/tests/get_phandle.c +++ b/tests/get_phandle.c @@ -46,6 +46,7 @@ int main(int argc, char *argv[]) { uint32_t max; void *fdt; + int err; test_init(argc, argv); fdt = load_blob_arg(argc, argv); @@ -54,6 +55,14 @@ int main(int argc, char *argv[]) check_phandle(fdt, "/subnode@2", PHANDLE_1); check_phandle(fdt, "/subnode@2/subsubnode@0", PHANDLE_2); + err = fdt_find_max_phandle(fdt, &max); + if (err < 0) + FAIL("fdt_find_max_phandle returned %d instead of 0\n", err); + + if (max != PHANDLE_2) + FAIL("fdt_find_max_phandle found 0x%x instead of 0x%x", max, + PHANDLE_2); + max = fdt_get_max_phandle(fdt); if (max != PHANDLE_2) FAIL("fdt_get_max_phandle returned 0x%x instead of 0x%x\n", -- 2.21.0