1 // SPDX-License-Identifier: (GPL-2.0-or-later << 2 /* 1 /* 3 * libfdt - Flat Device Tree manipulation 2 * libfdt - Flat Device Tree manipulation 4 * Copyright (C) 2006 David Gibson, IBM Corpor 3 * Copyright (C) 2006 David Gibson, IBM Corporation. >> 4 * >> 5 * libfdt is dual licensed: you can use it either under the terms of >> 6 * the GPL, or the BSD license, at your option. >> 7 * >> 8 * a) This library is free software; you can redistribute it and/or >> 9 * modify it under the terms of the GNU General Public License as >> 10 * published by the Free Software Foundation; either version 2 of the >> 11 * License, or (at your option) any later version. >> 12 * >> 13 * This library is distributed in the hope that it will be useful, >> 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of >> 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> 16 * GNU General Public License for more details. >> 17 * >> 18 * You should have received a copy of the GNU General Public >> 19 * License along with this library; if not, write to the Free >> 20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, >> 21 * MA 02110-1301 USA >> 22 * >> 23 * Alternatively, >> 24 * >> 25 * b) Redistribution and use in source and binary forms, with or >> 26 * without modification, are permitted provided that the following >> 27 * conditions are met: >> 28 * >> 29 * 1. Redistributions of source code must retain the above >> 30 * copyright notice, this list of conditions and the following >> 31 * disclaimer. >> 32 * 2. Redistributions in binary form must reproduce the above >> 33 * copyright notice, this list of conditions and the following >> 34 * disclaimer in the documentation and/or other materials >> 35 * provided with the distribution. >> 36 * >> 37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND >> 38 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, >> 39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF >> 40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >> 41 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR >> 42 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >> 43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >> 44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; >> 45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >> 46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >> 47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR >> 48 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, >> 49 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5 */ 50 */ 6 #include "libfdt_env.h" 51 #include "libfdt_env.h" 7 52 8 #include <fdt.h> 53 #include <fdt.h> 9 #include <libfdt.h> 54 #include <libfdt.h> 10 55 11 #include "libfdt_internal.h" 56 #include "libfdt_internal.h" 12 57 13 /* !! 58 int fdt_check_header(const void *fdt) 14 * Minimal sanity check for a read-only tree. << 15 * that the given buffer contains what appears << 16 * device tree with sane information in its he << 17 */ << 18 int32_t fdt_ro_probe_(const void *fdt) << 19 { 59 { 20 uint32_t totalsize = fdt_totalsize(fdt << 21 << 22 if (can_assume(VALID_DTB)) << 23 return totalsize; << 24 << 25 /* The device tree must be at an 8-byt << 26 if ((uintptr_t)fdt & 7) << 27 return -FDT_ERR_ALIGNMENT; << 28 << 29 if (fdt_magic(fdt) == FDT_MAGIC) { 60 if (fdt_magic(fdt) == FDT_MAGIC) { 30 /* Complete tree */ 61 /* Complete tree */ 31 if (!can_assume(LATEST)) { !! 62 if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) 32 if (fdt_version(fdt) < !! 63 return -FDT_ERR_BADVERSION; 33 return -FDT_ER !! 64 if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) 34 if (fdt_last_comp_vers !! 65 return -FDT_ERR_BADVERSION; 35 FDT_LA << 36 return -FDT_ER << 37 } << 38 } else if (fdt_magic(fdt) == FDT_SW_MA 66 } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { 39 /* Unfinished sequential-write 67 /* Unfinished sequential-write blob */ 40 if (!can_assume(VALID_INPUT) & !! 68 if (fdt_size_dt_struct(fdt) == 0) 41 return -FDT_ERR_BADSTA 69 return -FDT_ERR_BADSTATE; 42 } else { 70 } else { 43 return -FDT_ERR_BADMAGIC; 71 return -FDT_ERR_BADMAGIC; 44 } 72 } 45 73 46 if (totalsize < INT32_MAX) << 47 return totalsize; << 48 else << 49 return -FDT_ERR_TRUNCATED; << 50 } << 51 << 52 static int check_off_(uint32_t hdrsize, uint32 << 53 { << 54 return (off >= hdrsize) && (off <= tot << 55 } << 56 << 57 static int check_block_(uint32_t hdrsize, uint << 58 uint32_t base, uint32_ << 59 { << 60 if (!check_off_(hdrsize, totalsize, ba << 61 return 0; /* block start out o << 62 if ((base + size) < base) << 63 return 0; /* overflow */ << 64 if (!check_off_(hdrsize, totalsize, ba << 65 return 0; /* block end out of << 66 return 1; << 67 } << 68 << 69 size_t fdt_header_size_(uint32_t version) << 70 { << 71 if (version <= 1) << 72 return FDT_V1_SIZE; << 73 else if (version <= 2) << 74 return FDT_V2_SIZE; << 75 else if (version <= 3) << 76 return FDT_V3_SIZE; << 77 else if (version <= 16) << 78 return FDT_V16_SIZE; << 79 else << 80 return FDT_V17_SIZE; << 81 } << 82 << 83 size_t fdt_header_size(const void *fdt) << 84 { << 85 return can_assume(LATEST) ? FDT_V17_SI << 86 fdt_header_size_(fdt_version(f << 87 } << 88 << 89 int fdt_check_header(const void *fdt) << 90 { << 91 size_t hdrsize; << 92 << 93 /* The device tree must be at an 8-byt << 94 if ((uintptr_t)fdt & 7) << 95 return -FDT_ERR_ALIGNMENT; << 96 << 97 if (fdt_magic(fdt) != FDT_MAGIC) << 98 return -FDT_ERR_BADMAGIC; << 99 if (!can_assume(LATEST)) { << 100 if ((fdt_version(fdt) < FDT_FI << 101 || (fdt_last_comp_version( << 102 FDT_LAST_SUPPORTED_VER << 103 return -FDT_ERR_BADVER << 104 if (fdt_version(fdt) < fdt_las << 105 return -FDT_ERR_BADVER << 106 } << 107 hdrsize = fdt_header_size(fdt); << 108 if (!can_assume(VALID_DTB)) { << 109 if ((fdt_totalsize(fdt) < hdrs << 110 || (fdt_totalsize(fdt) > I << 111 return -FDT_ERR_TRUNCA << 112 << 113 /* Bounds check memrsv block * << 114 if (!check_off_(hdrsize, fdt_t << 115 fdt_off_mem_rs << 116 return -FDT_ERR_TRUNCA << 117 << 118 /* Bounds check structure bloc << 119 if (!can_assume(LATEST) && fdt << 120 if (!check_off_(hdrsiz << 121 fdt_of << 122 return -FDT_ER << 123 } else { << 124 if (!check_block_(hdrs << 125 fdt_ << 126 fdt_ << 127 return -FDT_ER << 128 } << 129 << 130 /* Bounds check strings block << 131 if (!check_block_(hdrsize, fdt << 132 fdt_off_dt_s << 133 fdt_size_dt_ << 134 return -FDT_ERR_TRUNCA << 135 } << 136 << 137 return 0; 74 return 0; 138 } 75 } 139 76 140 const void *fdt_offset_ptr(const void *fdt, in 77 const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) 141 { 78 { 142 unsigned int uoffset = offset; !! 79 unsigned absoffset = offset + fdt_off_dt_struct(fdt); 143 unsigned int absoffset = offset + fdt_ << 144 80 145 if (offset < 0) !! 81 if ((absoffset < offset) >> 82 || ((absoffset + len) < absoffset) >> 83 || (absoffset + len) > fdt_totalsize(fdt)) 146 return NULL; 84 return NULL; 147 85 148 if (!can_assume(VALID_INPUT)) !! 86 if (fdt_version(fdt) >= 0x11) 149 if ((absoffset < uoffset) !! 87 if (((offset + len) < offset) 150 || ((absoffset + len) < ab << 151 || (absoffset + len) > fdt << 152 return NULL; << 153 << 154 if (can_assume(LATEST) || fdt_version( << 155 if (((uoffset + len) < uoffset << 156 || ((offset + len) > fdt_s 88 || ((offset + len) > fdt_size_dt_struct(fdt))) 157 return NULL; 89 return NULL; 158 90 159 return fdt_offset_ptr_(fdt, offset); !! 91 return _fdt_offset_ptr(fdt, offset); 160 } 92 } 161 93 162 uint32_t fdt_next_tag(const void *fdt, int sta 94 uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) 163 { 95 { 164 const fdt32_t *tagp, *lenp; 96 const fdt32_t *tagp, *lenp; 165 uint32_t tag, len, sum; !! 97 uint32_t tag; 166 int offset = startoffset; 98 int offset = startoffset; 167 const char *p; 99 const char *p; 168 100 169 *nextoffset = -FDT_ERR_TRUNCATED; 101 *nextoffset = -FDT_ERR_TRUNCATED; 170 tagp = fdt_offset_ptr(fdt, offset, FDT 102 tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); 171 if (!can_assume(VALID_DTB) && !tagp) !! 103 if (!tagp) 172 return FDT_END; /* premature e 104 return FDT_END; /* premature end */ 173 tag = fdt32_to_cpu(*tagp); 105 tag = fdt32_to_cpu(*tagp); 174 offset += FDT_TAGSIZE; 106 offset += FDT_TAGSIZE; 175 107 176 *nextoffset = -FDT_ERR_BADSTRUCTURE; 108 *nextoffset = -FDT_ERR_BADSTRUCTURE; 177 switch (tag) { 109 switch (tag) { 178 case FDT_BEGIN_NODE: 110 case FDT_BEGIN_NODE: 179 /* skip name */ 111 /* skip name */ 180 do { 112 do { 181 p = fdt_offset_ptr(fdt 113 p = fdt_offset_ptr(fdt, offset++, 1); 182 } while (p && (*p != '\0')); 114 } while (p && (*p != '\0')); 183 if (!can_assume(VALID_DTB) && !! 115 if (!p) 184 return FDT_END; /* pre 116 return FDT_END; /* premature end */ 185 break; 117 break; 186 118 187 case FDT_PROP: 119 case FDT_PROP: 188 lenp = fdt_offset_ptr(fdt, off 120 lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); 189 if (!can_assume(VALID_DTB) && !! 121 if (!lenp) 190 return FDT_END; /* pre << 191 << 192 len = fdt32_to_cpu(*lenp); << 193 sum = len + offset; << 194 if (!can_assume(VALID_DTB) && << 195 (INT_MAX <= sum || sum < ( << 196 return FDT_END; /* pre 122 return FDT_END; /* premature end */ 197 << 198 /* skip-name offset, length an 123 /* skip-name offset, length and value */ 199 offset += sizeof(struct fdt_pr !! 124 offset += sizeof(struct fdt_property) - FDT_TAGSIZE 200 !! 125 + fdt32_to_cpu(*lenp); 201 if (!can_assume(LATEST) && << 202 fdt_version(fdt) < 0x10 && << 203 ((offset - len) % 8) != 0) << 204 offset += 4; << 205 break; 126 break; 206 127 207 case FDT_END: 128 case FDT_END: 208 case FDT_END_NODE: 129 case FDT_END_NODE: 209 case FDT_NOP: 130 case FDT_NOP: 210 break; 131 break; 211 132 212 default: 133 default: 213 return FDT_END; 134 return FDT_END; 214 } 135 } 215 136 216 if (!fdt_offset_ptr(fdt, startoffset, 137 if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) 217 return FDT_END; /* premature e 138 return FDT_END; /* premature end */ 218 139 219 *nextoffset = FDT_TAGALIGN(offset); 140 *nextoffset = FDT_TAGALIGN(offset); 220 return tag; 141 return tag; 221 } 142 } 222 143 223 int fdt_check_node_offset_(const void *fdt, in !! 144 int _fdt_check_node_offset(const void *fdt, int offset) 224 { 145 { 225 if (!can_assume(VALID_INPUT) !! 146 if ((offset < 0) || (offset % FDT_TAGSIZE) 226 && ((offset < 0) || (offset % FDT_ !! 147 || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) 227 return -FDT_ERR_BADOFFSET; << 228 << 229 if (fdt_next_tag(fdt, offset, &offset) << 230 return -FDT_ERR_BADOFFSET; 148 return -FDT_ERR_BADOFFSET; 231 149 232 return offset; 150 return offset; 233 } 151 } 234 152 235 int fdt_check_prop_offset_(const void *fdt, in !! 153 int _fdt_check_prop_offset(const void *fdt, int offset) 236 { 154 { 237 if (!can_assume(VALID_INPUT) !! 155 if ((offset < 0) || (offset % FDT_TAGSIZE) 238 && ((offset < 0) || (offset % FDT_ !! 156 || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) 239 return -FDT_ERR_BADOFFSET; << 240 << 241 if (fdt_next_tag(fdt, offset, &offset) << 242 return -FDT_ERR_BADOFFSET; 157 return -FDT_ERR_BADOFFSET; 243 158 244 return offset; 159 return offset; 245 } 160 } 246 161 247 int fdt_next_node(const void *fdt, int offset, 162 int fdt_next_node(const void *fdt, int offset, int *depth) 248 { 163 { 249 int nextoffset = 0; 164 int nextoffset = 0; 250 uint32_t tag; 165 uint32_t tag; 251 166 252 if (offset >= 0) 167 if (offset >= 0) 253 if ((nextoffset = fdt_check_no !! 168 if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) 254 return nextoffset; 169 return nextoffset; 255 170 256 do { 171 do { 257 offset = nextoffset; 172 offset = nextoffset; 258 tag = fdt_next_tag(fdt, offset 173 tag = fdt_next_tag(fdt, offset, &nextoffset); 259 174 260 switch (tag) { 175 switch (tag) { 261 case FDT_PROP: 176 case FDT_PROP: 262 case FDT_NOP: 177 case FDT_NOP: 263 break; 178 break; 264 179 265 case FDT_BEGIN_NODE: 180 case FDT_BEGIN_NODE: 266 if (depth) 181 if (depth) 267 (*depth)++; 182 (*depth)++; 268 break; 183 break; 269 184 270 case FDT_END_NODE: 185 case FDT_END_NODE: 271 if (depth && ((--(*dep 186 if (depth && ((--(*depth)) < 0)) 272 return nextoff 187 return nextoffset; 273 break; 188 break; 274 189 275 case FDT_END: 190 case FDT_END: 276 if ((nextoffset >= 0) 191 if ((nextoffset >= 0) 277 || ((nextoffset == 192 || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) 278 return -FDT_ER 193 return -FDT_ERR_NOTFOUND; 279 else 194 else 280 return nextoff 195 return nextoffset; 281 } 196 } 282 } while (tag != FDT_BEGIN_NODE); 197 } while (tag != FDT_BEGIN_NODE); 283 198 284 return offset; 199 return offset; 285 } 200 } 286 201 287 int fdt_first_subnode(const void *fdt, int off 202 int fdt_first_subnode(const void *fdt, int offset) 288 { 203 { 289 int depth = 0; 204 int depth = 0; 290 205 291 offset = fdt_next_node(fdt, offset, &d 206 offset = fdt_next_node(fdt, offset, &depth); 292 if (offset < 0 || depth != 1) 207 if (offset < 0 || depth != 1) 293 return -FDT_ERR_NOTFOUND; 208 return -FDT_ERR_NOTFOUND; 294 209 295 return offset; 210 return offset; 296 } 211 } 297 212 298 int fdt_next_subnode(const void *fdt, int offs 213 int fdt_next_subnode(const void *fdt, int offset) 299 { 214 { 300 int depth = 1; 215 int depth = 1; 301 216 302 /* 217 /* 303 * With respect to the parent, the dep 218 * With respect to the parent, the depth of the next subnode will be 304 * the same as the last. 219 * the same as the last. 305 */ 220 */ 306 do { 221 do { 307 offset = fdt_next_node(fdt, of 222 offset = fdt_next_node(fdt, offset, &depth); 308 if (offset < 0 || depth < 1) 223 if (offset < 0 || depth < 1) 309 return -FDT_ERR_NOTFOU 224 return -FDT_ERR_NOTFOUND; 310 } while (depth > 1); 225 } while (depth > 1); 311 226 312 return offset; 227 return offset; 313 } 228 } 314 229 315 const char *fdt_find_string_(const char *strta !! 230 const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) 316 { 231 { 317 int len = strlen(s) + 1; 232 int len = strlen(s) + 1; 318 const char *last = strtab + tabsize - 233 const char *last = strtab + tabsize - len; 319 const char *p; 234 const char *p; 320 235 321 for (p = strtab; p <= last; p++) 236 for (p = strtab; p <= last; p++) 322 if (memcmp(p, s, len) == 0) 237 if (memcmp(p, s, len) == 0) 323 return p; 238 return p; 324 return NULL; 239 return NULL; 325 } 240 } 326 241 327 int fdt_move(const void *fdt, void *buf, int b 242 int fdt_move(const void *fdt, void *buf, int bufsize) 328 { 243 { 329 if (!can_assume(VALID_INPUT) && bufsiz !! 244 FDT_CHECK_HEADER(fdt); 330 return -FDT_ERR_NOSPACE; << 331 << 332 FDT_RO_PROBE(fdt); << 333 245 334 if (fdt_totalsize(fdt) > (unsigned int !! 246 if (fdt_totalsize(fdt) > bufsize) 335 return -FDT_ERR_NOSPACE; 247 return -FDT_ERR_NOSPACE; 336 248 337 memmove(buf, fdt, fdt_totalsize(fdt)); 249 memmove(buf, fdt, fdt_totalsize(fdt)); 338 return 0; 250 return 0; 339 } 251 } 340 252
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.