fdt_rw.c revision 9537
19537Satgutier@umich.edu/* 29537Satgutier@umich.edu * libfdt - Flat Device Tree manipulation 39537Satgutier@umich.edu * Copyright (C) 2006 David Gibson, IBM Corporation. 49537Satgutier@umich.edu * 59537Satgutier@umich.edu * Redistribution and use in source and binary forms, with or 69537Satgutier@umich.edu * without modification, are permitted provided that the following 79537Satgutier@umich.edu * conditions are met: 89537Satgutier@umich.edu * 99537Satgutier@umich.edu * 1. Redistributions of source code must retain the above 109537Satgutier@umich.edu * copyright notice, this list of conditions and the following 119537Satgutier@umich.edu * disclaimer. 129537Satgutier@umich.edu * 2. Redistributions in binary form must reproduce the above 139537Satgutier@umich.edu * copyright notice, this list of conditions and the following 149537Satgutier@umich.edu * disclaimer in the documentation and/or other materials 159537Satgutier@umich.edu * provided with the distribution. 169537Satgutier@umich.edu * 179537Satgutier@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 189537Satgutier@umich.edu * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 199537Satgutier@umich.edu * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 209537Satgutier@umich.edu * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 219537Satgutier@umich.edu * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 229537Satgutier@umich.edu * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 239537Satgutier@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 249537Satgutier@umich.edu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 259537Satgutier@umich.edu * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 269537Satgutier@umich.edu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 279537Satgutier@umich.edu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 289537Satgutier@umich.edu * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 299537Satgutier@umich.edu * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 309537Satgutier@umich.edu */ 319537Satgutier@umich.edu#include <fdt.h> 329537Satgutier@umich.edu#include <libfdt.h> 339537Satgutier@umich.edu 349537Satgutier@umich.edu#include "libfdt_env.h" 359537Satgutier@umich.edu#include "libfdt_internal.h" 369537Satgutier@umich.edu 379537Satgutier@umich.edustatic int _fdt_blocks_misordered(const void *fdt, 389537Satgutier@umich.edu int mem_rsv_size, int struct_size) 399537Satgutier@umich.edu{ 409537Satgutier@umich.edu return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) 419537Satgutier@umich.edu || (fdt_off_dt_struct(fdt) < 429537Satgutier@umich.edu (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) 439537Satgutier@umich.edu || (fdt_off_dt_strings(fdt) < 449537Satgutier@umich.edu (fdt_off_dt_struct(fdt) + struct_size)) 459537Satgutier@umich.edu || (fdt_totalsize(fdt) < 469537Satgutier@umich.edu (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); 479537Satgutier@umich.edu} 489537Satgutier@umich.edu 499537Satgutier@umich.edustatic int _fdt_rw_check_header(void *fdt) 509537Satgutier@umich.edu{ 519537Satgutier@umich.edu FDT_CHECK_HEADER(fdt); 529537Satgutier@umich.edu 539537Satgutier@umich.edu if (fdt_version(fdt) < 17) 549537Satgutier@umich.edu return -FDT_ERR_BADVERSION; 559537Satgutier@umich.edu if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), 569537Satgutier@umich.edu fdt_size_dt_struct(fdt))) 579537Satgutier@umich.edu return -FDT_ERR_BADLAYOUT; 589537Satgutier@umich.edu if (fdt_version(fdt) > 17) 599537Satgutier@umich.edu fdt_set_version(fdt, 17); 609537Satgutier@umich.edu 619537Satgutier@umich.edu return 0; 629537Satgutier@umich.edu} 639537Satgutier@umich.edu 649537Satgutier@umich.edu#define FDT_RW_CHECK_HEADER(fdt) \ 659537Satgutier@umich.edu { \ 669537Satgutier@umich.edu int err; \ 679537Satgutier@umich.edu if ((err = _fdt_rw_check_header(fdt)) != 0) \ 689537Satgutier@umich.edu return err; \ 699537Satgutier@umich.edu } 709537Satgutier@umich.edu 719537Satgutier@umich.edustatic inline int _fdt_data_size(void *fdt) 729537Satgutier@umich.edu{ 739537Satgutier@umich.edu return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); 749537Satgutier@umich.edu} 759537Satgutier@umich.edu 769537Satgutier@umich.edustatic int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) 779537Satgutier@umich.edu{ 789537Satgutier@umich.edu char *p = splicepoint; 799537Satgutier@umich.edu char *end = (char *)fdt + _fdt_data_size(fdt); 809537Satgutier@umich.edu 819537Satgutier@umich.edu if (((p + oldlen) < p) || ((p + oldlen) > end)) 829537Satgutier@umich.edu return -FDT_ERR_BADOFFSET; 839537Satgutier@umich.edu if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) 849537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 859537Satgutier@umich.edu memmove(p + newlen, p + oldlen, end - p - oldlen); 869537Satgutier@umich.edu return 0; 879537Satgutier@umich.edu} 889537Satgutier@umich.edu 899537Satgutier@umich.edustatic int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, 909537Satgutier@umich.edu int oldn, int newn) 919537Satgutier@umich.edu{ 929537Satgutier@umich.edu int delta = (newn - oldn) * sizeof(*p); 939537Satgutier@umich.edu int err; 949537Satgutier@umich.edu err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); 959537Satgutier@umich.edu if (err) 969537Satgutier@umich.edu return err; 979537Satgutier@umich.edu fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); 989537Satgutier@umich.edu fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); 999537Satgutier@umich.edu return 0; 1009537Satgutier@umich.edu} 1019537Satgutier@umich.edu 1029537Satgutier@umich.edustatic int _fdt_splice_struct(void *fdt, void *p, 1039537Satgutier@umich.edu int oldlen, int newlen) 1049537Satgutier@umich.edu{ 1059537Satgutier@umich.edu int delta = newlen - oldlen; 1069537Satgutier@umich.edu int err; 1079537Satgutier@umich.edu 1089537Satgutier@umich.edu if ((err = _fdt_splice(fdt, p, oldlen, newlen))) 1099537Satgutier@umich.edu return err; 1109537Satgutier@umich.edu 1119537Satgutier@umich.edu fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); 1129537Satgutier@umich.edu fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); 1139537Satgutier@umich.edu return 0; 1149537Satgutier@umich.edu} 1159537Satgutier@umich.edu 1169537Satgutier@umich.edustatic int _fdt_splice_string(void *fdt, int newlen) 1179537Satgutier@umich.edu{ 1189537Satgutier@umich.edu void *p = (char *)fdt 1199537Satgutier@umich.edu + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); 1209537Satgutier@umich.edu int err; 1219537Satgutier@umich.edu 1229537Satgutier@umich.edu if ((err = _fdt_splice(fdt, p, 0, newlen))) 1239537Satgutier@umich.edu return err; 1249537Satgutier@umich.edu 1259537Satgutier@umich.edu fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); 1269537Satgutier@umich.edu return 0; 1279537Satgutier@umich.edu} 1289537Satgutier@umich.edu 1299537Satgutier@umich.edustatic int _fdt_find_add_string(void *fdt, const char *s) 1309537Satgutier@umich.edu{ 1319537Satgutier@umich.edu char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); 1329537Satgutier@umich.edu const char *p; 1339537Satgutier@umich.edu char *new; 1349537Satgutier@umich.edu int len = strlen(s) + 1; 1359537Satgutier@umich.edu int err; 1369537Satgutier@umich.edu 1379537Satgutier@umich.edu p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); 1389537Satgutier@umich.edu if (p) 1399537Satgutier@umich.edu /* found it */ 1409537Satgutier@umich.edu return (p - strtab); 1419537Satgutier@umich.edu 1429537Satgutier@umich.edu new = strtab + fdt_size_dt_strings(fdt); 1439537Satgutier@umich.edu err = _fdt_splice_string(fdt, len); 1449537Satgutier@umich.edu if (err) 1459537Satgutier@umich.edu return err; 1469537Satgutier@umich.edu 1479537Satgutier@umich.edu memcpy(new, s, len); 1489537Satgutier@umich.edu return (new - strtab); 1499537Satgutier@umich.edu} 1509537Satgutier@umich.edu 1519537Satgutier@umich.eduint fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) 1529537Satgutier@umich.edu{ 1539537Satgutier@umich.edu struct fdt_reserve_entry *re; 1549537Satgutier@umich.edu int err; 1559537Satgutier@umich.edu 1569537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 1579537Satgutier@umich.edu 1589537Satgutier@umich.edu re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); 1599537Satgutier@umich.edu err = _fdt_splice_mem_rsv(fdt, re, 0, 1); 1609537Satgutier@umich.edu if (err) 1619537Satgutier@umich.edu return err; 1629537Satgutier@umich.edu 1639537Satgutier@umich.edu re->address = cpu_to_fdt64(address); 1649537Satgutier@umich.edu re->size = cpu_to_fdt64(size); 1659537Satgutier@umich.edu return 0; 1669537Satgutier@umich.edu} 1679537Satgutier@umich.edu 1689537Satgutier@umich.eduint fdt_del_mem_rsv(void *fdt, int n) 1699537Satgutier@umich.edu{ 1709537Satgutier@umich.edu struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); 1719537Satgutier@umich.edu int err; 1729537Satgutier@umich.edu 1739537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 1749537Satgutier@umich.edu 1759537Satgutier@umich.edu if (n >= fdt_num_mem_rsv(fdt)) 1769537Satgutier@umich.edu return -FDT_ERR_NOTFOUND; 1779537Satgutier@umich.edu 1789537Satgutier@umich.edu err = _fdt_splice_mem_rsv(fdt, re, 1, 0); 1799537Satgutier@umich.edu if (err) 1809537Satgutier@umich.edu return err; 1819537Satgutier@umich.edu return 0; 1829537Satgutier@umich.edu} 1839537Satgutier@umich.edu 1849537Satgutier@umich.edustatic int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, 1859537Satgutier@umich.edu int len, struct fdt_property **prop) 1869537Satgutier@umich.edu{ 1879537Satgutier@umich.edu int oldlen; 1889537Satgutier@umich.edu int err; 1899537Satgutier@umich.edu 1909537Satgutier@umich.edu *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); 1919537Satgutier@umich.edu if (! (*prop)) 1929537Satgutier@umich.edu return oldlen; 1939537Satgutier@umich.edu 1949537Satgutier@umich.edu if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), 1959537Satgutier@umich.edu FDT_TAGALIGN(len)))) 1969537Satgutier@umich.edu return err; 1979537Satgutier@umich.edu 1989537Satgutier@umich.edu (*prop)->len = cpu_to_fdt32(len); 1999537Satgutier@umich.edu return 0; 2009537Satgutier@umich.edu} 2019537Satgutier@umich.edu 2029537Satgutier@umich.edustatic int _fdt_add_property(void *fdt, int nodeoffset, const char *name, 2039537Satgutier@umich.edu int len, struct fdt_property **prop) 2049537Satgutier@umich.edu{ 2059537Satgutier@umich.edu int proplen; 2069537Satgutier@umich.edu int nextoffset; 2079537Satgutier@umich.edu int namestroff; 2089537Satgutier@umich.edu int err; 2099537Satgutier@umich.edu 2109537Satgutier@umich.edu if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) 2119537Satgutier@umich.edu return nextoffset; 2129537Satgutier@umich.edu 2139537Satgutier@umich.edu namestroff = _fdt_find_add_string(fdt, name); 2149537Satgutier@umich.edu if (namestroff < 0) 2159537Satgutier@umich.edu return namestroff; 2169537Satgutier@umich.edu 2179537Satgutier@umich.edu *prop = _fdt_offset_ptr_w(fdt, nextoffset); 2189537Satgutier@umich.edu proplen = sizeof(**prop) + FDT_TAGALIGN(len); 2199537Satgutier@umich.edu 2209537Satgutier@umich.edu err = _fdt_splice_struct(fdt, *prop, 0, proplen); 2219537Satgutier@umich.edu if (err) 2229537Satgutier@umich.edu return err; 2239537Satgutier@umich.edu 2249537Satgutier@umich.edu (*prop)->tag = cpu_to_fdt32(FDT_PROP); 2259537Satgutier@umich.edu (*prop)->nameoff = cpu_to_fdt32(namestroff); 2269537Satgutier@umich.edu (*prop)->len = cpu_to_fdt32(len); 2279537Satgutier@umich.edu return 0; 2289537Satgutier@umich.edu} 2299537Satgutier@umich.edu 2309537Satgutier@umich.eduint fdt_set_name(void *fdt, int nodeoffset, const char *name) 2319537Satgutier@umich.edu{ 2329537Satgutier@umich.edu char *namep; 2339537Satgutier@umich.edu int oldlen, newlen; 2349537Satgutier@umich.edu int err; 2359537Satgutier@umich.edu 2369537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 2379537Satgutier@umich.edu 2389537Satgutier@umich.edu namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); 2399537Satgutier@umich.edu if (!namep) 2409537Satgutier@umich.edu return oldlen; 2419537Satgutier@umich.edu 2429537Satgutier@umich.edu newlen = strlen(name); 2439537Satgutier@umich.edu 2449537Satgutier@umich.edu err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), 2459537Satgutier@umich.edu FDT_TAGALIGN(newlen+1)); 2469537Satgutier@umich.edu if (err) 2479537Satgutier@umich.edu return err; 2489537Satgutier@umich.edu 2499537Satgutier@umich.edu memcpy(namep, name, newlen+1); 2509537Satgutier@umich.edu return 0; 2519537Satgutier@umich.edu} 2529537Satgutier@umich.edu 2539537Satgutier@umich.eduint fdt_setprop(void *fdt, int nodeoffset, const char *name, 2549537Satgutier@umich.edu const void *val, int len) 2559537Satgutier@umich.edu{ 2569537Satgutier@umich.edu struct fdt_property *prop; 2579537Satgutier@umich.edu int err; 2589537Satgutier@umich.edu 2599537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 2609537Satgutier@umich.edu 2619537Satgutier@umich.edu err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); 2629537Satgutier@umich.edu if (err == -FDT_ERR_NOTFOUND) 2639537Satgutier@umich.edu err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); 2649537Satgutier@umich.edu if (err) 2659537Satgutier@umich.edu return err; 2669537Satgutier@umich.edu 2679537Satgutier@umich.edu memcpy(prop->data, val, len); 2689537Satgutier@umich.edu return 0; 2699537Satgutier@umich.edu} 2709537Satgutier@umich.edu 2719537Satgutier@umich.eduint fdt_appendprop(void *fdt, int nodeoffset, const char *name, 2729537Satgutier@umich.edu const void *val, int len) 2739537Satgutier@umich.edu{ 2749537Satgutier@umich.edu struct fdt_property *prop; 2759537Satgutier@umich.edu int err, oldlen, newlen; 2769537Satgutier@umich.edu 2779537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 2789537Satgutier@umich.edu 2799537Satgutier@umich.edu prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); 2809537Satgutier@umich.edu if (prop) { 2819537Satgutier@umich.edu newlen = len + oldlen; 2829537Satgutier@umich.edu err = _fdt_splice_struct(fdt, prop->data, 2839537Satgutier@umich.edu FDT_TAGALIGN(oldlen), 2849537Satgutier@umich.edu FDT_TAGALIGN(newlen)); 2859537Satgutier@umich.edu if (err) 2869537Satgutier@umich.edu return err; 2879537Satgutier@umich.edu prop->len = cpu_to_fdt32(newlen); 2889537Satgutier@umich.edu memcpy(prop->data + oldlen, val, len); 2899537Satgutier@umich.edu } else { 2909537Satgutier@umich.edu err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); 2919537Satgutier@umich.edu if (err) 2929537Satgutier@umich.edu return err; 2939537Satgutier@umich.edu memcpy(prop->data, val, len); 2949537Satgutier@umich.edu } 2959537Satgutier@umich.edu return 0; 2969537Satgutier@umich.edu} 2979537Satgutier@umich.edu 2989537Satgutier@umich.eduint fdt_delprop(void *fdt, int nodeoffset, const char *name) 2999537Satgutier@umich.edu{ 3009537Satgutier@umich.edu struct fdt_property *prop; 3019537Satgutier@umich.edu int len, proplen; 3029537Satgutier@umich.edu 3039537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 3049537Satgutier@umich.edu 3059537Satgutier@umich.edu prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 3069537Satgutier@umich.edu if (! prop) 3079537Satgutier@umich.edu return len; 3089537Satgutier@umich.edu 3099537Satgutier@umich.edu proplen = sizeof(*prop) + FDT_TAGALIGN(len); 3109537Satgutier@umich.edu return _fdt_splice_struct(fdt, prop, proplen, 0); 3119537Satgutier@umich.edu} 3129537Satgutier@umich.edu 3139537Satgutier@umich.eduint fdt_add_subnode_namelen(void *fdt, int parentoffset, 3149537Satgutier@umich.edu const char *name, int namelen) 3159537Satgutier@umich.edu{ 3169537Satgutier@umich.edu struct fdt_node_header *nh; 3179537Satgutier@umich.edu int offset, nextoffset; 3189537Satgutier@umich.edu int nodelen; 3199537Satgutier@umich.edu int err; 3209537Satgutier@umich.edu uint32_t tag; 3219537Satgutier@umich.edu fdt32_t *endtag; 3229537Satgutier@umich.edu 3239537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 3249537Satgutier@umich.edu 3259537Satgutier@umich.edu offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); 3269537Satgutier@umich.edu if (offset >= 0) 3279537Satgutier@umich.edu return -FDT_ERR_EXISTS; 3289537Satgutier@umich.edu else if (offset != -FDT_ERR_NOTFOUND) 3299537Satgutier@umich.edu return offset; 3309537Satgutier@umich.edu 3319537Satgutier@umich.edu /* Try to place the new node after the parent's properties */ 3329537Satgutier@umich.edu fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ 3339537Satgutier@umich.edu do { 3349537Satgutier@umich.edu offset = nextoffset; 3359537Satgutier@umich.edu tag = fdt_next_tag(fdt, offset, &nextoffset); 3369537Satgutier@umich.edu } while ((tag == FDT_PROP) || (tag == FDT_NOP)); 3379537Satgutier@umich.edu 3389537Satgutier@umich.edu nh = _fdt_offset_ptr_w(fdt, offset); 3399537Satgutier@umich.edu nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; 3409537Satgutier@umich.edu 3419537Satgutier@umich.edu err = _fdt_splice_struct(fdt, nh, 0, nodelen); 3429537Satgutier@umich.edu if (err) 3439537Satgutier@umich.edu return err; 3449537Satgutier@umich.edu 3459537Satgutier@umich.edu nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 3469537Satgutier@umich.edu memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); 3479537Satgutier@umich.edu memcpy(nh->name, name, namelen); 3489537Satgutier@umich.edu endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); 3499537Satgutier@umich.edu *endtag = cpu_to_fdt32(FDT_END_NODE); 3509537Satgutier@umich.edu 3519537Satgutier@umich.edu return offset; 3529537Satgutier@umich.edu} 3539537Satgutier@umich.edu 3549537Satgutier@umich.eduint fdt_add_subnode(void *fdt, int parentoffset, const char *name) 3559537Satgutier@umich.edu{ 3569537Satgutier@umich.edu return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); 3579537Satgutier@umich.edu} 3589537Satgutier@umich.edu 3599537Satgutier@umich.eduint fdt_del_node(void *fdt, int nodeoffset) 3609537Satgutier@umich.edu{ 3619537Satgutier@umich.edu int endoffset; 3629537Satgutier@umich.edu 3639537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 3649537Satgutier@umich.edu 3659537Satgutier@umich.edu endoffset = _fdt_node_end_offset(fdt, nodeoffset); 3669537Satgutier@umich.edu if (endoffset < 0) 3679537Satgutier@umich.edu return endoffset; 3689537Satgutier@umich.edu 3699537Satgutier@umich.edu return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), 3709537Satgutier@umich.edu endoffset - nodeoffset, 0); 3719537Satgutier@umich.edu} 3729537Satgutier@umich.edu 3739537Satgutier@umich.edustatic void _fdt_packblocks(const char *old, char *new, 3749537Satgutier@umich.edu int mem_rsv_size, int struct_size) 3759537Satgutier@umich.edu{ 3769537Satgutier@umich.edu int mem_rsv_off, struct_off, strings_off; 3779537Satgutier@umich.edu 3789537Satgutier@umich.edu mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); 3799537Satgutier@umich.edu struct_off = mem_rsv_off + mem_rsv_size; 3809537Satgutier@umich.edu strings_off = struct_off + struct_size; 3819537Satgutier@umich.edu 3829537Satgutier@umich.edu memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); 3839537Satgutier@umich.edu fdt_set_off_mem_rsvmap(new, mem_rsv_off); 3849537Satgutier@umich.edu 3859537Satgutier@umich.edu memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); 3869537Satgutier@umich.edu fdt_set_off_dt_struct(new, struct_off); 3879537Satgutier@umich.edu fdt_set_size_dt_struct(new, struct_size); 3889537Satgutier@umich.edu 3899537Satgutier@umich.edu memmove(new + strings_off, old + fdt_off_dt_strings(old), 3909537Satgutier@umich.edu fdt_size_dt_strings(old)); 3919537Satgutier@umich.edu fdt_set_off_dt_strings(new, strings_off); 3929537Satgutier@umich.edu fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); 3939537Satgutier@umich.edu} 3949537Satgutier@umich.edu 3959537Satgutier@umich.eduint fdt_open_into(const void *fdt, void *buf, int bufsize) 3969537Satgutier@umich.edu{ 3979537Satgutier@umich.edu int err; 3989537Satgutier@umich.edu int mem_rsv_size, struct_size; 3999537Satgutier@umich.edu int newsize; 4009537Satgutier@umich.edu const char *fdtstart = fdt; 4019537Satgutier@umich.edu const char *fdtend = fdtstart + fdt_totalsize(fdt); 4029537Satgutier@umich.edu char *tmp; 4039537Satgutier@umich.edu 4049537Satgutier@umich.edu FDT_CHECK_HEADER(fdt); 4059537Satgutier@umich.edu 4069537Satgutier@umich.edu mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 4079537Satgutier@umich.edu * sizeof(struct fdt_reserve_entry); 4089537Satgutier@umich.edu 4099537Satgutier@umich.edu if (fdt_version(fdt) >= 17) { 4109537Satgutier@umich.edu struct_size = fdt_size_dt_struct(fdt); 4119537Satgutier@umich.edu } else { 4129537Satgutier@umich.edu struct_size = 0; 4139537Satgutier@umich.edu while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) 4149537Satgutier@umich.edu ; 4159537Satgutier@umich.edu if (struct_size < 0) 4169537Satgutier@umich.edu return struct_size; 4179537Satgutier@umich.edu } 4189537Satgutier@umich.edu 4199537Satgutier@umich.edu if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { 4209537Satgutier@umich.edu /* no further work necessary */ 4219537Satgutier@umich.edu err = fdt_move(fdt, buf, bufsize); 4229537Satgutier@umich.edu if (err) 4239537Satgutier@umich.edu return err; 4249537Satgutier@umich.edu fdt_set_version(buf, 17); 4259537Satgutier@umich.edu fdt_set_size_dt_struct(buf, struct_size); 4269537Satgutier@umich.edu fdt_set_totalsize(buf, bufsize); 4279537Satgutier@umich.edu return 0; 4289537Satgutier@umich.edu } 4299537Satgutier@umich.edu 4309537Satgutier@umich.edu /* Need to reorder */ 4319537Satgutier@umich.edu newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size 4329537Satgutier@umich.edu + struct_size + fdt_size_dt_strings(fdt); 4339537Satgutier@umich.edu 4349537Satgutier@umich.edu if (bufsize < newsize) 4359537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 4369537Satgutier@umich.edu 4379537Satgutier@umich.edu /* First attempt to build converted tree at beginning of buffer */ 4389537Satgutier@umich.edu tmp = buf; 4399537Satgutier@umich.edu /* But if that overlaps with the old tree... */ 4409537Satgutier@umich.edu if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { 4419537Satgutier@umich.edu /* Try right after the old tree instead */ 4429537Satgutier@umich.edu tmp = (char *)(uintptr_t)fdtend; 4439537Satgutier@umich.edu if ((tmp + newsize) > ((char *)buf + bufsize)) 4449537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 4459537Satgutier@umich.edu } 4469537Satgutier@umich.edu 4479537Satgutier@umich.edu _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); 4489537Satgutier@umich.edu memmove(buf, tmp, newsize); 4499537Satgutier@umich.edu 4509537Satgutier@umich.edu fdt_set_magic(buf, FDT_MAGIC); 4519537Satgutier@umich.edu fdt_set_totalsize(buf, bufsize); 4529537Satgutier@umich.edu fdt_set_version(buf, 17); 4539537Satgutier@umich.edu fdt_set_last_comp_version(buf, 16); 4549537Satgutier@umich.edu fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); 4559537Satgutier@umich.edu 4569537Satgutier@umich.edu return 0; 4579537Satgutier@umich.edu} 4589537Satgutier@umich.edu 4599537Satgutier@umich.eduint fdt_pack(void *fdt) 4609537Satgutier@umich.edu{ 4619537Satgutier@umich.edu int mem_rsv_size; 4629537Satgutier@umich.edu 4639537Satgutier@umich.edu FDT_RW_CHECK_HEADER(fdt); 4649537Satgutier@umich.edu 4659537Satgutier@umich.edu mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 4669537Satgutier@umich.edu * sizeof(struct fdt_reserve_entry); 4679537Satgutier@umich.edu _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); 4689537Satgutier@umich.edu fdt_set_totalsize(fdt, _fdt_data_size(fdt)); 4699537Satgutier@umich.edu 4709537Satgutier@umich.edu return 0; 4719537Satgutier@umich.edu} 472