From 243ce5d5e574a92b5cc92b6e257471fb390d87f7 Mon Sep 17 00:00:00 2001 From: Madhukar Pappireddy Date: Mon, 15 Jun 2020 17:19:09 -0500 Subject: [PATCH] Upgrade libfdt source files This version corresponds to the following commit <7be250b> libfdt: Correct condition for reordering blocks Also, updated the Juno romlib jumptable with fdt APIs. Change-Id: Ib6d28c1aea81c2144a263958f0792cc4daea7a1f Signed-off-by: Madhukar Pappireddy --- include/lib/libfdt/fdt.h | 49 +----- include/lib/libfdt/libfdt.h | 290 +++++++++++++++++++++++++------- include/lib/libfdt/libfdt_env.h | 49 +----- lib/libfdt/fdt.c | 186 +++++++++++++------- lib/libfdt/fdt_addresses.c | 133 ++++++++------- lib/libfdt/fdt_empty_tree.c | 47 +----- lib/libfdt/fdt_overlay.c | 91 ++++------ lib/libfdt/fdt_ro.c | 280 +++++++++++++++++++----------- lib/libfdt/fdt_rw.c | 133 +++++++-------- lib/libfdt/fdt_strerror.c | 47 +----- lib/libfdt/fdt_sw.c | 241 +++++++++++++++++--------- lib/libfdt/fdt_wip.c | 47 +----- lib/libfdt/libfdt_internal.h | 180 ++++++++++++++------ plat/arm/board/juno/jmptbl.i | 2 + 14 files changed, 996 insertions(+), 779 deletions(-) diff --git a/include/lib/libfdt/fdt.h b/include/lib/libfdt/fdt.h index ef7c86b6d..eb9edb72f 100644 --- a/include/lib/libfdt/fdt.h +++ b/include/lib/libfdt/fdt.h @@ -1,55 +1,10 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ #ifndef FDT_H #define FDT_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * 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 __ASSEMBLER__ @@ -90,7 +45,7 @@ struct fdt_property { char data[0]; }; -#endif /* !__ASSEMBLER__ */ +#endif /* !__ASSEMBLER__*/ #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ #define FDT_TAGSIZE sizeof(fdt32_t) diff --git a/include/lib/libfdt/libfdt.h b/include/lib/libfdt/libfdt.h index c8c00fa86..48f375c9c 100644 --- a/include/lib/libfdt/libfdt.h +++ b/include/lib/libfdt/libfdt.h @@ -1,54 +1,9 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ #ifndef LIBFDT_H #define LIBFDT_H /* * libfdt - Flat Device Tree manipulation * 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 @@ -90,8 +45,9 @@ /* Error codes: codes for bad device tree blobs */ #define FDT_ERR_TRUNCATED 8 - /* FDT_ERR_TRUNCATED: Structure block of the given device tree - * ends without an FDT_END tag. */ + /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly + * terminated (overflows, goes outside allowed bounds, or + * isn't properly terminated). */ #define FDT_ERR_BADMAGIC 9 /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a * device tree at all - it is missing the flattened device @@ -137,7 +93,15 @@ /* FDT_ERR_NOPHANDLES: The device tree doesn't have any * 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 */ +#define FDT_MAX_PHANDLE 0xfffffffe + /* Valid values for phandles range from 1 to 2^32-2. */ /**********************************************************************/ /* Low-level functions (you probably don't need these) */ @@ -153,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); +/* + * 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 */ /**********************************************************************/ @@ -195,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 * } * @@ -213,7 +232,7 @@ int fdt_next_subnode(const void *fdt, int offset); /* General functions */ /**********************************************************************/ #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_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) @@ -244,18 +263,32 @@ fdt_set_hdr_(size_dt_struct); #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_check_header() checks that the given buffer contains what - * appears to be a flattened device tree with sane information in its - * header. + * appears to be a flattened device tree, and that the header contains + * valid information (to the extent that can be determined from the + * header alone). * * returns: * 0, if the buffer appears to contain a valid device tree * -FDT_ERR_BADMAGIC, * -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); @@ -284,6 +317,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize); /* 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: pointer to the device tree blob @@ -294,10 +345,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize); * * returns: * 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); +/** + * 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 @@ -306,12 +371,39 @@ 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 * -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: pointer to the device tree blob + * @phandle: return location for the new phandle + * + * Walks the device tree blob and looks for the highest phandle value. On + * success, the new, unused phandle value (one higher than the previously + * highest phandle value in the device tree blob) will be returned in the + * @phandle parameter. + * + * Returns: + * 0 on success or a negative error-code on failure + */ +int fdt_generate_phandle(const void *fdt, uint32_t *phandle); /** * fdt_num_mem_rsv - retrieve the number of memory reserve map entries @@ -503,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 * } * @@ -606,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: 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 * @lenp: pointer to an integer variable (will be overwritten) or NULL * @@ -1090,7 +1182,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * * returns: * 0 <= n < FDT_MAX_NCELLS, on success - * 2, if the node has no #address-cells property + * 1, if the node has no #size-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #size-cells property * -FDT_ERR_BADMAGIC, @@ -1297,7 +1389,45 @@ int fdt_nop_node(void *fdt, int nodeoffset); /* 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_resize(void *fdt, void *buf, int bufsize); int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); int fdt_finish_reservemap(void *fdt); @@ -1313,10 +1443,13 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) fdt64_t tmp = cpu_to_fdt64(val); return fdt_property(fdt, name, &tmp, sizeof(tmp)); } + +#ifndef SWIG /* Not available in Python */ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { return fdt_property_u32(fdt, name, val); } +#endif /** * fdt_property_placeholder - add a new property and return a ptr to its value @@ -1765,6 +1898,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, #define fdt_appendprop_string(fdt, nodeoffset, name, str) \ 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: pointer to the device tree blob diff --git a/include/lib/libfdt/libfdt_env.h b/include/lib/libfdt/libfdt_env.h index bd2474628..73b6d4045 100644 --- a/include/lib/libfdt/libfdt_env.h +++ b/include/lib/libfdt/libfdt_env.h @@ -1,61 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ #ifndef LIBFDT_ENV_H #define LIBFDT_ENV_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * 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 #include #include #include #include +#include #ifdef __CHECKER__ #define FDT_FORCE __attribute__((force)) diff --git a/lib/libfdt/fdt.c b/lib/libfdt/fdt.c index 7855a1787..c28fcc115 100644 --- a/lib/libfdt/fdt.c +++ b/lib/libfdt/fdt.c @@ -1,52 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * 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" @@ -55,22 +10,125 @@ #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 (can_assume(VALID_DTB)) + return totalsize; + if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ - if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; + if (!can_assume(LATEST)) { + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + 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) { /* Unfinished sequential-write blob */ - if (fdt_size_dt_struct(fdt) == 0) + if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0) return -FDT_ERR_BADSTATE; } else { 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 can_assume(LATEST) ? FDT_V17_SIZE : + fdt_header_size_(fdt_version(fdt)); +} + +int fdt_check_header(const void *fdt) +{ + size_t hdrsize; + + if (fdt_magic(fdt) != FDT_MAGIC) + return -FDT_ERR_BADMAGIC; + if (!can_assume(LATEST)) { + 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 (!can_assume(VALID_DTB)) { + + 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 (!can_assume(VALID_DTB)) { + /* Bounds check structure block */ + if (!can_assume(LATEST) && 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; } @@ -78,12 +136,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { unsigned absoffset = offset + fdt_off_dt_struct(fdt); - if ((absoffset < offset) - || ((absoffset + len) < absoffset) - || (absoffset + len) > fdt_totalsize(fdt)) - return NULL; + if (!can_assume(VALID_INPUT)) + if ((absoffset < offset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; - if (fdt_version(fdt) >= 0x11) + if (can_assume(LATEST) || fdt_version(fdt) >= 0x11) if (((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; @@ -100,7 +159,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) *nextoffset = -FDT_ERR_TRUNCATED; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); - if (!tagp) + if (!can_assume(VALID_DTB) && !tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; @@ -112,18 +171,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); - if (!p) + if (!can_assume(VALID_DTB) && !p) return FDT_END; /* premature end */ break; case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); - if (!lenp) + if (!can_assume(VALID_DTB) && !lenp) return FDT_END; /* premature end */ /* skip-name offset, length and value */ offset += sizeof(struct fdt_property) - FDT_TAGSIZE + fdt32_to_cpu(*lenp); - if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && + if (!can_assume(LATEST) && + fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && ((offset - fdt32_to_cpu(*lenp)) % 8) != 0) offset += 4; break; @@ -146,6 +206,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) int fdt_check_node_offset_(const void *fdt, int offset) { + if (can_assume(VALID_INPUT)) + return offset; if ((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) return -FDT_ERR_BADOFFSET; @@ -244,7 +306,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) int fdt_move(const void *fdt, void *buf, int bufsize) { - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (fdt_totalsize(fdt) > bufsize) return -FDT_ERR_NOSPACE; diff --git a/lib/libfdt/fdt_addresses.c b/lib/libfdt/fdt_addresses.c index eff4dbcc7..9a82cd0ba 100644 --- a/lib/libfdt/fdt_addresses.c +++ b/lib/libfdt/fdt_addresses.c @@ -1,52 +1,8 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2014 David Gibson - * - * 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. + * Copyright (C) 2018 embedded brains GmbH */ #include "libfdt_env.h" @@ -55,42 +11,91 @@ #include "libfdt_internal.h" -int fdt_address_cells(const void *fdt, int nodeoffset) +static int fdt_cells(const void *fdt, int nodeoffset, const char *name) { - const fdt32_t *ac; - int val; + const fdt32_t *c; + uint32_t val; int len; - ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); - if (!ac) - return 2; + c = fdt_getprop(fdt, nodeoffset, name, &len); + if (!c) + return len; - if (len != sizeof(*ac)) + if (len != sizeof(*c)) return -FDT_ERR_BADNCELLS; - val = fdt32_to_cpu(*ac); - if ((val <= 0) || (val > FDT_MAX_NCELLS)) + val = fdt32_to_cpu(*c); + if (val > FDT_MAX_NCELLS) return -FDT_ERR_BADNCELLS; + return (int)val; +} + +int fdt_address_cells(const void *fdt, int nodeoffset) +{ + int val; + + val = fdt_cells(fdt, nodeoffset, "#address-cells"); + if (val == 0) + return -FDT_ERR_BADNCELLS; + if (val == -FDT_ERR_NOTFOUND) + return 2; return val; } int fdt_size_cells(const void *fdt, int nodeoffset) { - const fdt32_t *sc; int val; - int len; - sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); - if (!sc) - return 2; + val = fdt_cells(fdt, nodeoffset, "#size-cells"); + if (val == -FDT_ERR_NOTFOUND) + return 1; + 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; - if (len != sizeof(*sc)) + 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; + } - val = fdt32_to_cpu(*sc); - if ((val < 0) || (val > FDT_MAX_NCELLS)) + /* 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 val; + return fdt_appendprop(fdt, nodeoffset, name, data, + (addr_cells + size_cells) * sizeof(fdt32_t)); } diff --git a/lib/libfdt/fdt_empty_tree.c b/lib/libfdt/fdt_empty_tree.c index f2ae9b77c..49d54d44b 100644 --- a/lib/libfdt/fdt_empty_tree.c +++ b/lib/libfdt/fdt_empty_tree.c @@ -1,52 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * 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" diff --git a/lib/libfdt/fdt_overlay.c b/lib/libfdt/fdt_overlay.c index bf75388ec..b310e49a6 100644 --- a/lib/libfdt/fdt_overlay.c +++ b/lib/libfdt/fdt_overlay.c @@ -1,53 +1,8 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2016 Free Electrons * 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" @@ -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) * * 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) * * returns: - * the targetted node offset in the base device tree + * the targeted node offset in the base device tree * Negative error code on error */ 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; const char *name; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); for (;;) { 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() */ e = path + path_len; - /* format: //__overlay__/ */ - if (*path != '/') return -FDT_ERR_BADVALUE; /* get fragment name first */ s = strchr(path + 1, '/'); - if (!s) - return -FDT_ERR_BADOVERLAY; + if (!s) { + /* Symbol refers to something that won't end + * up in the target tree */ + continue; + } frag_name = path + 1; frag_name_len = s - path - 1; /* verify format; safe since "s" lies in \0 terminated prop */ len = sizeof("/__overlay__/") - 1; - if ((e - s) < len || memcmp(s, "/__overlay__/", len)) - return -FDT_ERR_BADOVERLAY; - - rel_path = s + len; - rel_path_len = e - rel_path; + if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { + /* //__overlay__/ */ + rel_path = s + len; + rel_path_len = e - rel_path - 1; + } else if ((e - s) == len + && (memcmp(s, "/__overlay__", len - 1) == 0)) { + /* //__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 */ 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) { - uint32_t delta = fdt_get_max_phandle(fdt); + uint32_t delta; int ret; - FDT_CHECK_HEADER(fdt); - FDT_CHECK_HEADER(fdto); + FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdto); + + ret = fdt_find_max_phandle(fdt, &delta); + if (ret) + goto err; ret = overlay_adjust_local_phandles(fdto, delta); if (ret) diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c index dfb3236da..e03570a56 100644 --- a/lib/libfdt/fdt_ro.c +++ b/lib/libfdt/fdt_ro.c @@ -1,52 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * 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" @@ -76,60 +31,169 @@ static int fdt_nodename_eq_(const void *fdt, int offset, 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 (can_assume(VALID_INPUT)) { + 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 (can_assume(LATEST) || fdt_version(fdt) >= 17) { + if (stroffset >= fdt_size_dt_strings(fdt)) + goto fail; + if ((fdt_size_dt_strings(fdt) - stroffset) < len) + len = fdt_size_dt_strings(fdt) - stroffset; + } + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + if ((stroffset >= 0) + || (stroffset < -fdt_size_dt_strings(fdt))) + goto fail; + if ((-stroffset) < len) + len = -stroffset; + } else { + err = -FDT_ERR_INTERNAL; + goto fail; + } + + s = (const char *)fdt + absoffset; + n = memchr(s, '\0', len); + if (!n) { + /* missing terminating NULL */ + err = -FDT_ERR_TRUNCATED; + goto fail; + } + + if (lenp) + *lenp = n - s; + return s; + +fail: + if (lenp) + *lenp = err; + return NULL; +} + const char *fdt_string(const void *fdt, int stroffset) { - return (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, 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; + 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; } +int fdt_generate_phandle(const void *fdt, uint32_t *phandle) +{ + uint32_t max; + int err; + + err = fdt_find_max_phandle(fdt, &max); + if (err < 0) + return err; + + if (max == FDT_MAX_PHANDLE) + return -FDT_ERR_NOPHANDLES; + + if (phandle) + *phandle = max + 1; + + return 0; +} + +static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) +{ + int offset = n * sizeof(struct fdt_reserve_entry); + int absoffset = fdt_off_mem_rsvmap(fdt) + offset; + + if (!can_assume(VALID_INPUT)) { + 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) { - FDT_CHECK_HEADER(fdt); - *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address); - *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); + const struct fdt_reserve_entry *re; + + FDT_RO_PROBE(fdt); + re = fdt_mem_rsv(fdt, n); + if (!can_assume(VALID_INPUT) && !re) + return -FDT_ERR_BADOFFSET; + + *address = fdt64_ld(&re->address); + *size = fdt64_ld(&re->size); return 0; } 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) - i++; - return i; + for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { + if (fdt64_ld(&re->size) == 0) + return i; + } + return -FDT_ERR_TRUNCATED; } static int nextprop_(const void *fdt, int offset) @@ -161,7 +225,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, { int depth; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); for (depth = 0; (offset >= 0) && (depth >= 0); @@ -187,7 +251,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) const char *p = path; int offset = 0; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* see if we have an alias */ if (*path != '/') { @@ -237,13 +301,13 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) const char *nameptr; int err; - if (((err = fdt_check_header(fdt)) != 0) + if (((err = fdt_ro_probe_(fdt)) < 0) || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) goto fail; nameptr = nh->name; - if (fdt_version(fdt) < 0x10) { + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { /* * For old FDT versions, match the naming conventions of V16: * give only the leaf name (after all /). The actual tree @@ -294,7 +358,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, int err; const struct fdt_property *prop; - if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) { + if (!can_assume(VALID_INPUT) && + (err = fdt_check_prop_offset_(fdt, offset)) < 0) { if (lenp) *lenp = err; return NULL; @@ -303,7 +368,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, prop = fdt_offset_ptr_(fdt, offset); if (lenp) - *lenp = fdt32_to_cpu(prop->len); + *lenp = fdt32_ld(&prop->len); return prop; } @@ -315,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, /* Prior to version 16, properties may need realignment * and this API does not work. fdt_getprop_*() will, however. */ - if (fdt_version(fdt) < 0x10) { + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { if (lenp) *lenp = -FDT_ERR_BADVERSION; return NULL; @@ -336,11 +401,12 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, (offset = fdt_next_property_offset(fdt, offset))) { 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 (!can_assume(LIBFDT_FLAWLESS) && !prop) { offset = -FDT_ERR_INTERNAL; break; } - if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), + if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), name, namelen)) { if (poffset) *poffset = offset; @@ -361,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, { /* Prior to version 16, properties may need realignment * and this API does not work. fdt_getprop_*() will, however. */ - if (fdt_version(fdt) < 0x10) { + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { if (lenp) *lenp = -FDT_ERR_BADVERSION; return NULL; @@ -392,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, return NULL; /* Handle realignment */ - if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && - fdt32_to_cpu(prop->len) >= 8) + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && + (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -406,12 +472,27 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, prop = fdt_get_property_by_offset_(fdt, offset, lenp); if (!prop) return NULL; - if (namep) - *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + if (namep) { + const char *name; + int namelen; + + if (!can_assume(VALID_INPUT)) { + 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_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && - fdt32_to_cpu(prop->len) >= 8) + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && + (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -436,7 +517,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) return 0; } - return fdt32_to_cpu(*php); + return fdt32_ld(php); } const char *fdt_get_alias_namelen(const void *fdt, @@ -462,7 +543,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) int offset, depth, namelen; const char *name; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (buflen < 2) return -FDT_ERR_NOSPACE; @@ -514,7 +595,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int offset, depth; int supernodeoffset = -FDT_ERR_INTERNAL; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (supernodedepth < 0) return -FDT_ERR_NOTFOUND; @@ -536,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, } } - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; + if (!can_assume(VALID_INPUT)) { + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + } return offset; /* error from fdt_next_node() */ } @@ -551,7 +634,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset) err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); if (err) - return (err < 0) ? err : -FDT_ERR_INTERNAL; + return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err : + -FDT_ERR_INTERNAL; return nodedepth; } @@ -573,7 +657,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const void *val; int len; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_getprop(), then if that didn't @@ -599,7 +683,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we * potentially scan each property of a node in @@ -752,7 +836,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, { int offset, err; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_node_check_compatible(), then if diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c index 9b829051e..93e4a2b56 100644 --- a/lib/libfdt/fdt_rw.c +++ b/lib/libfdt/fdt_rw.c @@ -1,52 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * 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" @@ -67,29 +22,31 @@ static int fdt_blocks_misordered_(const void *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 (can_assume(VALID_DTB)) + return 0; + FDT_RO_PROBE(fdt); - if (fdt_version(fdt) < 17) + if (!can_assume(LATEST) && fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), fdt_size_dt_struct(fdt))) return -FDT_ERR_BADLAYOUT; - if (fdt_version(fdt) > 17) + if (!can_assume(LATEST) && fdt_version(fdt) > 17) fdt_set_version(fdt, 17); return 0; } -#define FDT_RW_CHECK_HEADER(fdt) \ +#define FDT_RW_PROBE(fdt) \ { \ int err_; \ - if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ + if ((err_ = fdt_rw_probe_(fdt)) != 0) \ return err_; \ } -static inline int fdt_data_size_(void *fdt) +static inline unsigned int fdt_data_size_(void *fdt) { return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); } @@ -97,15 +54,16 @@ static inline int fdt_data_size_(void *fdt) static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) { char *p = splicepoint; - char *end = (char *)fdt + fdt_data_size_(fdt); + unsigned int dsize = fdt_data_size_(fdt); + size_t soff = p - (char *)fdt; - if (((p + oldlen) < p) || ((p + oldlen) > end)) + if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) return -FDT_ERR_BADOFFSET; - if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) + if ((p < (char *)fdt) || (dsize + newlen < oldlen)) return -FDT_ERR_BADOFFSET; - if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) + if (dsize - oldlen + newlen > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; - memmove(p + newlen, p + oldlen, end - p - oldlen); + memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen)); return 0; } @@ -136,6 +94,14 @@ static int fdt_splice_struct_(void *fdt, void *p, 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) { void *p = (char *)fdt @@ -149,7 +115,16 @@ static int fdt_splice_string_(void *fdt, int newlen) 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 can_assume(NO_ROLLBACK) + * @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); const char *p; @@ -157,6 +132,9 @@ static int fdt_find_add_string_(void *fdt, const char *s) int len = strlen(s) + 1; int err; + if (!can_assume(NO_ROLLBACK)) + *allocated = 0; + p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); if (p) /* found it */ @@ -167,6 +145,9 @@ static int fdt_find_add_string_(void *fdt, const char *s) if (err) return err; + if (!can_assume(NO_ROLLBACK)) + *allocated = 1; + memcpy(new, s, len); return (new - strtab); } @@ -176,7 +157,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) struct fdt_reserve_entry *re; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); err = fdt_splice_mem_rsv_(fdt, re, 0, 1); @@ -192,7 +173,7 @@ int fdt_del_mem_rsv(void *fdt, int 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)) return -FDT_ERR_NOTFOUND; @@ -225,11 +206,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, int nextoffset; int namestroff; int err; + int allocated; if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) return nextoffset; - namestroff = fdt_find_add_string_(fdt, name); + namestroff = fdt_find_add_string_(fdt, name, &allocated); if (namestroff < 0) return namestroff; @@ -237,8 +219,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, proplen = sizeof(**prop) + FDT_TAGALIGN(len); err = fdt_splice_struct_(fdt, *prop, 0, proplen); - if (err) + if (err) { + /* Delete the string if we failed to add it */ + if (!can_assume(NO_ROLLBACK) && allocated) + fdt_del_last_string_(fdt, name); return err; + } (*prop)->tag = cpu_to_fdt32(FDT_PROP); (*prop)->nameoff = cpu_to_fdt32(namestroff); @@ -252,7 +238,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) int oldlen, newlen; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); if (!namep) @@ -275,7 +261,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, struct fdt_property *prop; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); if (err == -FDT_ERR_NOTFOUND) @@ -308,7 +294,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, struct fdt_property *prop; int err, oldlen, newlen; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (prop) { @@ -334,7 +320,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name) struct fdt_property *prop; int len, proplen; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (!prop) @@ -354,7 +340,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, uint32_t tag; fdt32_t *endtag; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); if (offset >= 0) @@ -394,7 +380,7 @@ int fdt_del_node(void *fdt, int nodeoffset) { int endoffset; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); endoffset = fdt_node_end_offset_(fdt, nodeoffset); if (endoffset < 0) @@ -435,12 +421,12 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) const char *fdtend = fdtstart + fdt_totalsize(fdt); char *tmp; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); - if (fdt_version(fdt) >= 17) { + if (can_assume(LATEST) || fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); } else { struct_size = 0; @@ -450,7 +436,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) return struct_size; } - if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { + if (can_assume(LIBFDT_ORDER) || + !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { /* no further work necessary */ err = fdt_move(fdt, buf, bufsize); if (err) @@ -494,7 +481,7 @@ int fdt_pack(void *fdt) { int mem_rsv_size; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); diff --git a/lib/libfdt/fdt_strerror.c b/lib/libfdt/fdt_strerror.c index 9677a1887..768db66ea 100644 --- a/lib/libfdt/fdt_strerror.c +++ b/lib/libfdt/fdt_strerror.c @@ -1,51 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * 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" @@ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADVALUE), FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_NOPHANDLES), + FDT_ERRTABENT(FDT_ERR_BADFLAGS), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) diff --git a/lib/libfdt/fdt_sw.c b/lib/libfdt/fdt_sw.c index 6d33cc29d..26759d5df 100644 --- a/lib/libfdt/fdt_sw.c +++ b/lib/libfdt/fdt_sw.c @@ -1,52 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * 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" @@ -55,21 +10,87 @@ #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) - return -FDT_ERR_BADMAGIC; - /* FIXME: should check more details about the header state */ + if (!can_assume(VALID_INPUT)) { + if (fdt_magic(fdt) == FDT_MAGIC) + return -FDT_ERR_BADSTATE; + else if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + } + return 0; } -#define FDT_SW_CHECK_HEADER(fdt) \ +#define FDT_SW_PROBE(fdt) \ { \ int err; \ - if ((err = fdt_sw_check_header_(fdt)) != 0) \ + if ((err = fdt_sw_probe_(fdt)) != 0) \ 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 (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) + return -FDT_ERR_BADSTATE; + return 0; +} + +#define FDT_SW_PROBE_MEMRSV(fdt) \ + { \ + int err; \ + if ((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 = fdt_sw_probe_(fdt); + if (err) + return err; + + if (!can_assume(VALID_INPUT) && + fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) + return -FDT_ERR_BADSTATE; + return 0; +} + +#define FDT_SW_PROBE_STRUCT(fdt) \ + { \ + int err; \ + if ((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) { int offset = fdt_size_dt_struct(fdt); @@ -85,38 +106,59 @@ static void *fdt_grab_space_(void *fdt, size_t len) 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; - if (bufsize < sizeof(struct fdt_header)) + if (bufsize < hdrsize) return -FDT_ERR_NOSPACE; + if (flags & ~FDT_CREATE_FLAGS_ALL) + return -FDT_ERR_BADFLAGS; + 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_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_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry))); + fdt_set_off_mem_rsvmap(fdt, hdrsize); 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; } +int fdt_create(void *buf, int bufsize) +{ + return fdt_create_with_flags(buf, bufsize, 0); +} + int fdt_resize(void *fdt, void *buf, int bufsize) { size_t headsize, tailsize; char *oldtail, *newtail; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE(fdt); - headsize = fdt_off_dt_struct(fdt); + headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); tailsize = fdt_size_dt_strings(fdt); + if (!can_assume(VALID_DTB) && + headsize + tailsize > fdt_totalsize(fdt)) + return -FDT_ERR_INTERNAL; + if ((headsize + tailsize) > bufsize) return -FDT_ERR_NOSPACE; @@ -133,8 +175,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize) memmove(buf, fdt, headsize); } - fdt_set_off_dt_strings(buf, bufsize); fdt_set_totalsize(buf, bufsize); + if (fdt_off_dt_strings(buf)) + fdt_set_off_dt_strings(buf, bufsize); return 0; } @@ -144,10 +187,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) struct fdt_reserve_entry *re; int offset; - FDT_SW_CHECK_HEADER(fdt); - - if (fdt_size_dt_struct(fdt)) - return -FDT_ERR_BADSTATE; + FDT_SW_PROBE_MEMRSV(fdt); offset = fdt_off_dt_struct(fdt); if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) @@ -164,16 +204,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) 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) { 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)); if (! nh) return -FDT_ERR_NOSPACE; @@ -187,7 +234,7 @@ int fdt_end_node(void *fdt) { fdt32_t *en; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); en = fdt_grab_space_(fdt, FDT_TAGSIZE); if (! en) @@ -197,19 +244,13 @@ int fdt_end_node(void *fdt) 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); - const char *p; int strtabsize = fdt_size_dt_strings(fdt); int len = strlen(s) + 1; int struct_top, offset; - p = fdt_find_string_(strtab - strtabsize, strtabsize, s); - if (p) - return p - strtab; - - /* Add it */ offset = -strtabsize - len; struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); if (fdt_totalsize(fdt) + offset < struct_top) @@ -220,20 +261,56 @@ static int fdt_find_add_string_(void *fdt, const char *s) 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) { struct fdt_property *prop; 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) return -FDT_ERR_NOSPACE; 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; + } prop->tag = cpu_to_fdt32(FDT_PROP); prop->nameoff = cpu_to_fdt32(nameoff); @@ -262,7 +339,7 @@ int fdt_finish(void *fdt) uint32_t tag; int offset, nextoffset; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); /* Add terminator */ end = fdt_grab_space_(fdt, sizeof(*end)); @@ -295,6 +372,10 @@ int fdt_finish(void *fdt) /* Finally, adjust the header */ 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); + return 0; } diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c index 534c1cbbb..f64139e0b 100644 --- a/lib/libfdt/fdt_wip.c +++ b/lib/libfdt/fdt_wip.c @@ -1,52 +1,7 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * libfdt - Flat Device Tree manipulation * 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" diff --git a/lib/libfdt/libfdt_internal.h b/lib/libfdt/libfdt_internal.h index 7681e1922..d4e0bd49c 100644 --- a/lib/libfdt/libfdt_internal.h +++ b/lib/libfdt/libfdt_internal.h @@ -1,65 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ #ifndef LIBFDT_INTERNAL_H #define LIBFDT_INTERNAL_H /* * libfdt - Flat Device Tree manipulation * 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 #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) -#define FDT_CHECK_HEADER(fdt) \ - { \ - int err_; \ - if ((err_ = fdt_check_header(fdt)) != 0) \ - return err_; \ +int32_t fdt_ro_probe_(const void *fdt); +#define FDT_RO_PROBE(fdt) \ + { \ + int32_t totalsize_; \ + if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \ + return totalsize_; \ } int fdt_check_node_offset_(const void *fdt, int offset); @@ -92,4 +48,126 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) #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 safety, don't enable any assumptions! + * + * For minimal code size and no safety, use 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 + * ASSUME_SANE. + */ +enum { + /* + * This does essentially no checks. Only the latest device-tree + * version is correctly handled. Inconsistencies or errors in the device + * tree may cause undefined behaviour or crashes. Invalid parameters + * passed to libfdt may do the same. + * + * 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. + */ + ASSUME_PERFECT = 0xff, + + /* + * This assumes that the device tree is sane. i.e. header metadata + * and basic hierarchy are correct. + * + * With this assumption enabled, 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. Truncated + * device trees (e.g. those only partially loaded) can also cause + * problems. + * + * Note: Only checks that relate exclusively to the device tree itself + * (not the parameters passed to libfdt) are disabled by this + * assumption. This includes checking headers, tags and the like. + */ + ASSUME_VALID_DTB = 1 << 0, + + /* + * This builds on ASSUME_VALID_DTB and further assumes that libfdt + * functions are called with valid parameters, i.e. not trigger + * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any + * extensive checking of parameters and the device tree, making various + * assumptions about correctness. + * + * It doesn't make sense to enable this assumption unless + * ASSUME_VALID_DTB is also enabled. + */ + ASSUME_VALID_INPUT = 1 << 1, + + /* + * 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. + */ + ASSUME_LATEST = 1 << 2, + + /* + * This assumes that it is OK for a failed addition to the device tree, + * due to lack of space or some other problem, to skip any rollback + * steps (such as dropping the property name from the string table). + * This is safe to enable in most circumstances, even though it may + * leave the tree in a sub-optimal state. + */ + ASSUME_NO_ROLLBACK = 1 << 3, + + /* + * This assumes that the device tree components appear in a 'convenient' + * order, i.e. the memory reservation block first, then the structure + * block and finally the string block. + * + * This order is not specified by the device-tree specification, + * but is expected by libfdt. The device-tree compiler always created + * device trees with this order. + * + * This assumption disables a check in fdt_open_into() and removes the + * ability to fix the problem there. This is safe if you know that the + * device tree is correctly ordered. See fdt_blocks_misordered_(). + */ + ASSUME_LIBFDT_ORDER = 1 << 4, + + /* + * This assumes that libfdt itself does not have any internal bugs. It + * drops certain checks that should never be needed unless libfdt has an + * undiscovered bug. + * + * This can generally be considered safe to enable. + */ + ASSUME_LIBFDT_FLAWLESS = 1 << 5, +}; + +/** + * can_assume_() - check if a particular assumption is enabled + * + * @mask: Mask to check (ASSUME_...) + * @return true if that assumption is enabled, else false + */ +static inline bool can_assume_(int mask) +{ + return FDT_ASSUME_MASK & mask; +} + +/** helper macros for checking assumptions */ +#define can_assume(_assume) can_assume_(ASSUME_ ## _assume) + #endif /* LIBFDT_INTERNAL_H */ diff --git a/plat/arm/board/juno/jmptbl.i b/plat/arm/board/juno/jmptbl.i index 20ed2c73c..393a64816 100644 --- a/plat/arm/board/juno/jmptbl.i +++ b/plat/arm/board/juno/jmptbl.i @@ -29,6 +29,8 @@ fdt fdt_stringlist_search fdt fdt_get_alias_namelen fdt fdt_path_offset fdt fdt_path_offset_namelen +fdt fdt_address_cells +fdt fdt_size_cells fdt fdt_get_name fdt fdt_get_alias fdt fdt_node_offset_by_phandle