Annotation of elwix/tools/uboot_mkimage/lib/libfdt/fdt_rw.c, revision 1.1
1.1 ! misho 1: /*
! 2: * libfdt - Flat Device Tree manipulation
! 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.
! 50: */
! 51: #include "libfdt_env.h"
! 52:
! 53: #ifndef USE_HOSTCC
! 54: #include <fdt.h>
! 55: #include <libfdt.h>
! 56: #else
! 57: #include "fdt_host.h"
! 58: #endif
! 59:
! 60: #include "libfdt_internal.h"
! 61:
! 62: static int _fdt_blocks_misordered(const void *fdt,
! 63: int mem_rsv_size, int struct_size)
! 64: {
! 65: return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
! 66: || (fdt_off_dt_struct(fdt) <
! 67: (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
! 68: || (fdt_off_dt_strings(fdt) <
! 69: (fdt_off_dt_struct(fdt) + struct_size))
! 70: || (fdt_totalsize(fdt) <
! 71: (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
! 72: }
! 73:
! 74: static int _fdt_rw_check_header(void *fdt)
! 75: {
! 76: FDT_CHECK_HEADER(fdt);
! 77:
! 78: if (fdt_version(fdt) < 17)
! 79: return -FDT_ERR_BADVERSION;
! 80: if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
! 81: fdt_size_dt_struct(fdt)))
! 82: return -FDT_ERR_BADLAYOUT;
! 83: if (fdt_version(fdt) > 17)
! 84: fdt_set_version(fdt, 17);
! 85:
! 86: return 0;
! 87: }
! 88:
! 89: #define FDT_RW_CHECK_HEADER(fdt) \
! 90: { \
! 91: int err; \
! 92: if ((err = _fdt_rw_check_header(fdt)) != 0) \
! 93: return err; \
! 94: }
! 95:
! 96: static inline int _fdt_data_size(void *fdt)
! 97: {
! 98: return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
! 99: }
! 100:
! 101: static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
! 102: {
! 103: char *p = splicepoint;
! 104: char *end = (char *)fdt + _fdt_data_size(fdt);
! 105:
! 106: if (((p + oldlen) < p) || ((p + oldlen) > end))
! 107: return -FDT_ERR_BADOFFSET;
! 108: if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
! 109: return -FDT_ERR_NOSPACE;
! 110: memmove(p + newlen, p + oldlen, end - p - oldlen);
! 111: return 0;
! 112: }
! 113:
! 114: static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
! 115: int oldn, int newn)
! 116: {
! 117: int delta = (newn - oldn) * sizeof(*p);
! 118: int err;
! 119: err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
! 120: if (err)
! 121: return err;
! 122: fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
! 123: fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
! 124: return 0;
! 125: }
! 126:
! 127: static int _fdt_splice_struct(void *fdt, void *p,
! 128: int oldlen, int newlen)
! 129: {
! 130: int delta = newlen - oldlen;
! 131: int err;
! 132:
! 133: if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
! 134: return err;
! 135:
! 136: fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
! 137: fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
! 138: return 0;
! 139: }
! 140:
! 141: static int _fdt_splice_string(void *fdt, int newlen)
! 142: {
! 143: void *p = (char *)fdt
! 144: + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
! 145: int err;
! 146:
! 147: if ((err = _fdt_splice(fdt, p, 0, newlen)))
! 148: return err;
! 149:
! 150: fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
! 151: return 0;
! 152: }
! 153:
! 154: static int _fdt_find_add_string(void *fdt, const char *s)
! 155: {
! 156: char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
! 157: const char *p;
! 158: char *new;
! 159: int len = strlen(s) + 1;
! 160: int err;
! 161:
! 162: p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
! 163: if (p)
! 164: /* found it */
! 165: return (p - strtab);
! 166:
! 167: new = strtab + fdt_size_dt_strings(fdt);
! 168: err = _fdt_splice_string(fdt, len);
! 169: if (err)
! 170: return err;
! 171:
! 172: memcpy(new, s, len);
! 173: return (new - strtab);
! 174: }
! 175:
! 176: int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
! 177: {
! 178: struct fdt_reserve_entry *re;
! 179: int err;
! 180:
! 181: FDT_RW_CHECK_HEADER(fdt);
! 182:
! 183: re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
! 184: err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
! 185: if (err)
! 186: return err;
! 187:
! 188: re->address = cpu_to_fdt64(address);
! 189: re->size = cpu_to_fdt64(size);
! 190: return 0;
! 191: }
! 192:
! 193: int fdt_del_mem_rsv(void *fdt, int n)
! 194: {
! 195: struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
! 196: int err;
! 197:
! 198: FDT_RW_CHECK_HEADER(fdt);
! 199:
! 200: if (n >= fdt_num_mem_rsv(fdt))
! 201: return -FDT_ERR_NOTFOUND;
! 202:
! 203: err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
! 204: if (err)
! 205: return err;
! 206: return 0;
! 207: }
! 208:
! 209: static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
! 210: int len, struct fdt_property **prop)
! 211: {
! 212: int oldlen;
! 213: int err;
! 214:
! 215: *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
! 216: if (! (*prop))
! 217: return oldlen;
! 218:
! 219: if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
! 220: FDT_TAGALIGN(len))))
! 221: return err;
! 222:
! 223: (*prop)->len = cpu_to_fdt32(len);
! 224: return 0;
! 225: }
! 226:
! 227: static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
! 228: int len, struct fdt_property **prop)
! 229: {
! 230: int proplen;
! 231: int nextoffset;
! 232: int namestroff;
! 233: int err;
! 234:
! 235: if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
! 236: return nextoffset;
! 237:
! 238: namestroff = _fdt_find_add_string(fdt, name);
! 239: if (namestroff < 0)
! 240: return namestroff;
! 241:
! 242: *prop = _fdt_offset_ptr_w(fdt, nextoffset);
! 243: proplen = sizeof(**prop) + FDT_TAGALIGN(len);
! 244:
! 245: err = _fdt_splice_struct(fdt, *prop, 0, proplen);
! 246: if (err)
! 247: return err;
! 248:
! 249: (*prop)->tag = cpu_to_fdt32(FDT_PROP);
! 250: (*prop)->nameoff = cpu_to_fdt32(namestroff);
! 251: (*prop)->len = cpu_to_fdt32(len);
! 252: return 0;
! 253: }
! 254:
! 255: int fdt_set_name(void *fdt, int nodeoffset, const char *name)
! 256: {
! 257: char *namep;
! 258: int oldlen, newlen;
! 259: int err;
! 260:
! 261: FDT_RW_CHECK_HEADER(fdt);
! 262:
! 263: namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
! 264: if (!namep)
! 265: return oldlen;
! 266:
! 267: newlen = strlen(name);
! 268:
! 269: err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
! 270: FDT_TAGALIGN(newlen+1));
! 271: if (err)
! 272: return err;
! 273:
! 274: memcpy(namep, name, newlen+1);
! 275: return 0;
! 276: }
! 277:
! 278: int fdt_setprop(void *fdt, int nodeoffset, const char *name,
! 279: const void *val, int len)
! 280: {
! 281: struct fdt_property *prop;
! 282: int err;
! 283:
! 284: FDT_RW_CHECK_HEADER(fdt);
! 285:
! 286: err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
! 287: if (err == -FDT_ERR_NOTFOUND)
! 288: err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
! 289: if (err)
! 290: return err;
! 291:
! 292: memcpy(prop->data, val, len);
! 293: return 0;
! 294: }
! 295:
! 296: int fdt_delprop(void *fdt, int nodeoffset, const char *name)
! 297: {
! 298: struct fdt_property *prop;
! 299: int len, proplen;
! 300:
! 301: FDT_RW_CHECK_HEADER(fdt);
! 302:
! 303: prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
! 304: if (! prop)
! 305: return len;
! 306:
! 307: proplen = sizeof(*prop) + FDT_TAGALIGN(len);
! 308: return _fdt_splice_struct(fdt, prop, proplen, 0);
! 309: }
! 310:
! 311: int fdt_add_subnode_namelen(void *fdt, int parentoffset,
! 312: const char *name, int namelen)
! 313: {
! 314: struct fdt_node_header *nh;
! 315: int offset, nextoffset;
! 316: int nodelen;
! 317: int err;
! 318: uint32_t tag;
! 319: uint32_t *endtag;
! 320:
! 321: FDT_RW_CHECK_HEADER(fdt);
! 322:
! 323: offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
! 324: if (offset >= 0)
! 325: return -FDT_ERR_EXISTS;
! 326: else if (offset != -FDT_ERR_NOTFOUND)
! 327: return offset;
! 328:
! 329: /* Try to place the new node after the parent's properties */
! 330: fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
! 331: do {
! 332: offset = nextoffset;
! 333: tag = fdt_next_tag(fdt, offset, &nextoffset);
! 334: } while ((tag == FDT_PROP) || (tag == FDT_NOP));
! 335:
! 336: nh = _fdt_offset_ptr_w(fdt, offset);
! 337: nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
! 338:
! 339: err = _fdt_splice_struct(fdt, nh, 0, nodelen);
! 340: if (err)
! 341: return err;
! 342:
! 343: nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
! 344: memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
! 345: memcpy(nh->name, name, namelen);
! 346: endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
! 347: *endtag = cpu_to_fdt32(FDT_END_NODE);
! 348:
! 349: return offset;
! 350: }
! 351:
! 352: int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
! 353: {
! 354: return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
! 355: }
! 356:
! 357: int fdt_del_node(void *fdt, int nodeoffset)
! 358: {
! 359: int endoffset;
! 360:
! 361: FDT_RW_CHECK_HEADER(fdt);
! 362:
! 363: endoffset = _fdt_node_end_offset(fdt, nodeoffset);
! 364: if (endoffset < 0)
! 365: return endoffset;
! 366:
! 367: return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
! 368: endoffset - nodeoffset, 0);
! 369: }
! 370:
! 371: static void _fdt_packblocks(const char *old, char *new,
! 372: int mem_rsv_size, int struct_size)
! 373: {
! 374: int mem_rsv_off, struct_off, strings_off;
! 375:
! 376: mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
! 377: struct_off = mem_rsv_off + mem_rsv_size;
! 378: strings_off = struct_off + struct_size;
! 379:
! 380: memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
! 381: fdt_set_off_mem_rsvmap(new, mem_rsv_off);
! 382:
! 383: memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
! 384: fdt_set_off_dt_struct(new, struct_off);
! 385: fdt_set_size_dt_struct(new, struct_size);
! 386:
! 387: memmove(new + strings_off, old + fdt_off_dt_strings(old),
! 388: fdt_size_dt_strings(old));
! 389: fdt_set_off_dt_strings(new, strings_off);
! 390: fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
! 391: }
! 392:
! 393: int fdt_open_into(const void *fdt, void *buf, int bufsize)
! 394: {
! 395: int err;
! 396: int mem_rsv_size, struct_size;
! 397: int newsize;
! 398: const char *fdtstart = fdt;
! 399: const char *fdtend = fdtstart + fdt_totalsize(fdt);
! 400: char *tmp;
! 401:
! 402: FDT_CHECK_HEADER(fdt);
! 403:
! 404: mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
! 405: * sizeof(struct fdt_reserve_entry);
! 406:
! 407: if (fdt_version(fdt) >= 17) {
! 408: struct_size = fdt_size_dt_struct(fdt);
! 409: } else {
! 410: struct_size = 0;
! 411: while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
! 412: ;
! 413: if (struct_size < 0)
! 414: return struct_size;
! 415: }
! 416:
! 417: if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
! 418: /* no further work necessary */
! 419: err = fdt_move(fdt, buf, bufsize);
! 420: if (err)
! 421: return err;
! 422: fdt_set_version(buf, 17);
! 423: fdt_set_size_dt_struct(buf, struct_size);
! 424: fdt_set_totalsize(buf, bufsize);
! 425: return 0;
! 426: }
! 427:
! 428: /* Need to reorder */
! 429: newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
! 430: + struct_size + fdt_size_dt_strings(fdt);
! 431:
! 432: if (bufsize < newsize)
! 433: return -FDT_ERR_NOSPACE;
! 434:
! 435: /* First attempt to build converted tree at beginning of buffer */
! 436: tmp = buf;
! 437: /* But if that overlaps with the old tree... */
! 438: if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
! 439: /* Try right after the old tree instead */
! 440: tmp = (char *)(uintptr_t)fdtend;
! 441: if ((tmp + newsize) > ((char *)buf + bufsize))
! 442: return -FDT_ERR_NOSPACE;
! 443: }
! 444:
! 445: _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
! 446: memmove(buf, tmp, newsize);
! 447:
! 448: fdt_set_magic(buf, FDT_MAGIC);
! 449: fdt_set_totalsize(buf, bufsize);
! 450: fdt_set_version(buf, 17);
! 451: fdt_set_last_comp_version(buf, 16);
! 452: fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
! 453:
! 454: return 0;
! 455: }
! 456:
! 457: int fdt_pack(void *fdt)
! 458: {
! 459: int mem_rsv_size;
! 460:
! 461: FDT_RW_CHECK_HEADER(fdt);
! 462:
! 463: mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
! 464: * sizeof(struct fdt_reserve_entry);
! 465: _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
! 466: fdt_set_totalsize(fdt, _fdt_data_size(fdt));
! 467:
! 468: return 0;
! 469: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>