1*91f16700Schasinglulu // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2*91f16700Schasinglulu /* 3*91f16700Schasinglulu * libfdt - Flat Device Tree manipulation 4*91f16700Schasinglulu * Copyright (C) 2006 David Gibson, IBM Corporation. 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu #include "libfdt_env.h" 7*91f16700Schasinglulu 8*91f16700Schasinglulu #include <fdt.h> 9*91f16700Schasinglulu #include <libfdt.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include "libfdt_internal.h" 12*91f16700Schasinglulu 13*91f16700Schasinglulu static int fdt_blocks_misordered_(const void *fdt, 14*91f16700Schasinglulu int mem_rsv_size, int struct_size) 15*91f16700Schasinglulu { 16*91f16700Schasinglulu return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) 17*91f16700Schasinglulu || (fdt_off_dt_struct(fdt) < 18*91f16700Schasinglulu (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) 19*91f16700Schasinglulu || (fdt_off_dt_strings(fdt) < 20*91f16700Schasinglulu (fdt_off_dt_struct(fdt) + struct_size)) 21*91f16700Schasinglulu || (fdt_totalsize(fdt) < 22*91f16700Schasinglulu (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); 23*91f16700Schasinglulu } 24*91f16700Schasinglulu 25*91f16700Schasinglulu static int fdt_rw_probe_(void *fdt) 26*91f16700Schasinglulu { 27*91f16700Schasinglulu if (can_assume(VALID_DTB)) 28*91f16700Schasinglulu return 0; 29*91f16700Schasinglulu FDT_RO_PROBE(fdt); 30*91f16700Schasinglulu 31*91f16700Schasinglulu if (!can_assume(LATEST) && fdt_version(fdt) < 17) 32*91f16700Schasinglulu return -FDT_ERR_BADVERSION; 33*91f16700Schasinglulu if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), 34*91f16700Schasinglulu fdt_size_dt_struct(fdt))) 35*91f16700Schasinglulu return -FDT_ERR_BADLAYOUT; 36*91f16700Schasinglulu if (!can_assume(LATEST) && fdt_version(fdt) > 17) 37*91f16700Schasinglulu fdt_set_version(fdt, 17); 38*91f16700Schasinglulu 39*91f16700Schasinglulu return 0; 40*91f16700Schasinglulu } 41*91f16700Schasinglulu 42*91f16700Schasinglulu #define FDT_RW_PROBE(fdt) \ 43*91f16700Schasinglulu { \ 44*91f16700Schasinglulu int err_; \ 45*91f16700Schasinglulu if ((err_ = fdt_rw_probe_(fdt)) != 0) \ 46*91f16700Schasinglulu return err_; \ 47*91f16700Schasinglulu } 48*91f16700Schasinglulu 49*91f16700Schasinglulu static inline unsigned int fdt_data_size_(void *fdt) 50*91f16700Schasinglulu { 51*91f16700Schasinglulu return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); 52*91f16700Schasinglulu } 53*91f16700Schasinglulu 54*91f16700Schasinglulu static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) 55*91f16700Schasinglulu { 56*91f16700Schasinglulu char *p = splicepoint; 57*91f16700Schasinglulu unsigned int dsize = fdt_data_size_(fdt); 58*91f16700Schasinglulu size_t soff = p - (char *)fdt; 59*91f16700Schasinglulu 60*91f16700Schasinglulu if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) 61*91f16700Schasinglulu return -FDT_ERR_BADOFFSET; 62*91f16700Schasinglulu if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen)) 63*91f16700Schasinglulu return -FDT_ERR_BADOFFSET; 64*91f16700Schasinglulu if (dsize - oldlen + newlen > fdt_totalsize(fdt)) 65*91f16700Schasinglulu return -FDT_ERR_NOSPACE; 66*91f16700Schasinglulu memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen)); 67*91f16700Schasinglulu return 0; 68*91f16700Schasinglulu } 69*91f16700Schasinglulu 70*91f16700Schasinglulu static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p, 71*91f16700Schasinglulu int oldn, int newn) 72*91f16700Schasinglulu { 73*91f16700Schasinglulu int delta = (newn - oldn) * sizeof(*p); 74*91f16700Schasinglulu int err; 75*91f16700Schasinglulu err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); 76*91f16700Schasinglulu if (err) 77*91f16700Schasinglulu return err; 78*91f16700Schasinglulu fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); 79*91f16700Schasinglulu fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); 80*91f16700Schasinglulu return 0; 81*91f16700Schasinglulu } 82*91f16700Schasinglulu 83*91f16700Schasinglulu static int fdt_splice_struct_(void *fdt, void *p, 84*91f16700Schasinglulu int oldlen, int newlen) 85*91f16700Schasinglulu { 86*91f16700Schasinglulu int delta = newlen - oldlen; 87*91f16700Schasinglulu int err; 88*91f16700Schasinglulu 89*91f16700Schasinglulu if ((err = fdt_splice_(fdt, p, oldlen, newlen))) 90*91f16700Schasinglulu return err; 91*91f16700Schasinglulu 92*91f16700Schasinglulu fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); 93*91f16700Schasinglulu fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); 94*91f16700Schasinglulu return 0; 95*91f16700Schasinglulu } 96*91f16700Schasinglulu 97*91f16700Schasinglulu /* Must only be used to roll back in case of error */ 98*91f16700Schasinglulu static void fdt_del_last_string_(void *fdt, const char *s) 99*91f16700Schasinglulu { 100*91f16700Schasinglulu int newlen = strlen(s) + 1; 101*91f16700Schasinglulu 102*91f16700Schasinglulu fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen); 103*91f16700Schasinglulu } 104*91f16700Schasinglulu 105*91f16700Schasinglulu static int fdt_splice_string_(void *fdt, int newlen) 106*91f16700Schasinglulu { 107*91f16700Schasinglulu void *p = (char *)fdt 108*91f16700Schasinglulu + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); 109*91f16700Schasinglulu int err; 110*91f16700Schasinglulu 111*91f16700Schasinglulu if ((err = fdt_splice_(fdt, p, 0, newlen))) 112*91f16700Schasinglulu return err; 113*91f16700Schasinglulu 114*91f16700Schasinglulu fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); 115*91f16700Schasinglulu return 0; 116*91f16700Schasinglulu } 117*91f16700Schasinglulu 118*91f16700Schasinglulu /** 119*91f16700Schasinglulu * fdt_find_add_string_() - Find or allocate a string 120*91f16700Schasinglulu * 121*91f16700Schasinglulu * @fdt: pointer to the device tree to check/adjust 122*91f16700Schasinglulu * @s: string to find/add 123*91f16700Schasinglulu * @allocated: Set to 0 if the string was found, 1 if not found and so 124*91f16700Schasinglulu * allocated. Ignored if can_assume(NO_ROLLBACK) 125*91f16700Schasinglulu * @return offset of string in the string table (whether found or added) 126*91f16700Schasinglulu */ 127*91f16700Schasinglulu static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) 128*91f16700Schasinglulu { 129*91f16700Schasinglulu char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); 130*91f16700Schasinglulu const char *p; 131*91f16700Schasinglulu char *new; 132*91f16700Schasinglulu int len = strlen(s) + 1; 133*91f16700Schasinglulu int err; 134*91f16700Schasinglulu 135*91f16700Schasinglulu if (!can_assume(NO_ROLLBACK)) 136*91f16700Schasinglulu *allocated = 0; 137*91f16700Schasinglulu 138*91f16700Schasinglulu p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); 139*91f16700Schasinglulu if (p) 140*91f16700Schasinglulu /* found it */ 141*91f16700Schasinglulu return (p - strtab); 142*91f16700Schasinglulu 143*91f16700Schasinglulu new = strtab + fdt_size_dt_strings(fdt); 144*91f16700Schasinglulu err = fdt_splice_string_(fdt, len); 145*91f16700Schasinglulu if (err) 146*91f16700Schasinglulu return err; 147*91f16700Schasinglulu 148*91f16700Schasinglulu if (!can_assume(NO_ROLLBACK)) 149*91f16700Schasinglulu *allocated = 1; 150*91f16700Schasinglulu 151*91f16700Schasinglulu memcpy(new, s, len); 152*91f16700Schasinglulu return (new - strtab); 153*91f16700Schasinglulu } 154*91f16700Schasinglulu 155*91f16700Schasinglulu int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) 156*91f16700Schasinglulu { 157*91f16700Schasinglulu struct fdt_reserve_entry *re; 158*91f16700Schasinglulu int err; 159*91f16700Schasinglulu 160*91f16700Schasinglulu FDT_RW_PROBE(fdt); 161*91f16700Schasinglulu 162*91f16700Schasinglulu re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); 163*91f16700Schasinglulu err = fdt_splice_mem_rsv_(fdt, re, 0, 1); 164*91f16700Schasinglulu if (err) 165*91f16700Schasinglulu return err; 166*91f16700Schasinglulu 167*91f16700Schasinglulu re->address = cpu_to_fdt64(address); 168*91f16700Schasinglulu re->size = cpu_to_fdt64(size); 169*91f16700Schasinglulu return 0; 170*91f16700Schasinglulu } 171*91f16700Schasinglulu 172*91f16700Schasinglulu int fdt_del_mem_rsv(void *fdt, int n) 173*91f16700Schasinglulu { 174*91f16700Schasinglulu struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); 175*91f16700Schasinglulu 176*91f16700Schasinglulu FDT_RW_PROBE(fdt); 177*91f16700Schasinglulu 178*91f16700Schasinglulu if (n >= fdt_num_mem_rsv(fdt)) 179*91f16700Schasinglulu return -FDT_ERR_NOTFOUND; 180*91f16700Schasinglulu 181*91f16700Schasinglulu return fdt_splice_mem_rsv_(fdt, re, 1, 0); 182*91f16700Schasinglulu } 183*91f16700Schasinglulu 184*91f16700Schasinglulu static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, 185*91f16700Schasinglulu int len, struct fdt_property **prop) 186*91f16700Schasinglulu { 187*91f16700Schasinglulu int oldlen; 188*91f16700Schasinglulu int err; 189*91f16700Schasinglulu 190*91f16700Schasinglulu *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); 191*91f16700Schasinglulu if (!*prop) 192*91f16700Schasinglulu return oldlen; 193*91f16700Schasinglulu 194*91f16700Schasinglulu if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), 195*91f16700Schasinglulu FDT_TAGALIGN(len)))) 196*91f16700Schasinglulu return err; 197*91f16700Schasinglulu 198*91f16700Schasinglulu (*prop)->len = cpu_to_fdt32(len); 199*91f16700Schasinglulu return 0; 200*91f16700Schasinglulu } 201*91f16700Schasinglulu 202*91f16700Schasinglulu static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, 203*91f16700Schasinglulu int len, struct fdt_property **prop) 204*91f16700Schasinglulu { 205*91f16700Schasinglulu int proplen; 206*91f16700Schasinglulu int nextoffset; 207*91f16700Schasinglulu int namestroff; 208*91f16700Schasinglulu int err; 209*91f16700Schasinglulu int allocated; 210*91f16700Schasinglulu 211*91f16700Schasinglulu if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) 212*91f16700Schasinglulu return nextoffset; 213*91f16700Schasinglulu 214*91f16700Schasinglulu namestroff = fdt_find_add_string_(fdt, name, &allocated); 215*91f16700Schasinglulu if (namestroff < 0) 216*91f16700Schasinglulu return namestroff; 217*91f16700Schasinglulu 218*91f16700Schasinglulu *prop = fdt_offset_ptr_w_(fdt, nextoffset); 219*91f16700Schasinglulu proplen = sizeof(**prop) + FDT_TAGALIGN(len); 220*91f16700Schasinglulu 221*91f16700Schasinglulu err = fdt_splice_struct_(fdt, *prop, 0, proplen); 222*91f16700Schasinglulu if (err) { 223*91f16700Schasinglulu /* Delete the string if we failed to add it */ 224*91f16700Schasinglulu if (!can_assume(NO_ROLLBACK) && allocated) 225*91f16700Schasinglulu fdt_del_last_string_(fdt, name); 226*91f16700Schasinglulu return err; 227*91f16700Schasinglulu } 228*91f16700Schasinglulu 229*91f16700Schasinglulu (*prop)->tag = cpu_to_fdt32(FDT_PROP); 230*91f16700Schasinglulu (*prop)->nameoff = cpu_to_fdt32(namestroff); 231*91f16700Schasinglulu (*prop)->len = cpu_to_fdt32(len); 232*91f16700Schasinglulu return 0; 233*91f16700Schasinglulu } 234*91f16700Schasinglulu 235*91f16700Schasinglulu int fdt_set_name(void *fdt, int nodeoffset, const char *name) 236*91f16700Schasinglulu { 237*91f16700Schasinglulu char *namep; 238*91f16700Schasinglulu int oldlen, newlen; 239*91f16700Schasinglulu int err; 240*91f16700Schasinglulu 241*91f16700Schasinglulu FDT_RW_PROBE(fdt); 242*91f16700Schasinglulu 243*91f16700Schasinglulu namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); 244*91f16700Schasinglulu if (!namep) 245*91f16700Schasinglulu return oldlen; 246*91f16700Schasinglulu 247*91f16700Schasinglulu newlen = strlen(name); 248*91f16700Schasinglulu 249*91f16700Schasinglulu err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1), 250*91f16700Schasinglulu FDT_TAGALIGN(newlen+1)); 251*91f16700Schasinglulu if (err) 252*91f16700Schasinglulu return err; 253*91f16700Schasinglulu 254*91f16700Schasinglulu memcpy(namep, name, newlen+1); 255*91f16700Schasinglulu return 0; 256*91f16700Schasinglulu } 257*91f16700Schasinglulu 258*91f16700Schasinglulu int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, 259*91f16700Schasinglulu int len, void **prop_data) 260*91f16700Schasinglulu { 261*91f16700Schasinglulu struct fdt_property *prop; 262*91f16700Schasinglulu int err; 263*91f16700Schasinglulu 264*91f16700Schasinglulu FDT_RW_PROBE(fdt); 265*91f16700Schasinglulu 266*91f16700Schasinglulu err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); 267*91f16700Schasinglulu if (err == -FDT_ERR_NOTFOUND) 268*91f16700Schasinglulu err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); 269*91f16700Schasinglulu if (err) 270*91f16700Schasinglulu return err; 271*91f16700Schasinglulu 272*91f16700Schasinglulu *prop_data = prop->data; 273*91f16700Schasinglulu return 0; 274*91f16700Schasinglulu } 275*91f16700Schasinglulu 276*91f16700Schasinglulu int fdt_setprop(void *fdt, int nodeoffset, const char *name, 277*91f16700Schasinglulu const void *val, int len) 278*91f16700Schasinglulu { 279*91f16700Schasinglulu void *prop_data; 280*91f16700Schasinglulu int err; 281*91f16700Schasinglulu 282*91f16700Schasinglulu err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); 283*91f16700Schasinglulu if (err) 284*91f16700Schasinglulu return err; 285*91f16700Schasinglulu 286*91f16700Schasinglulu if (len) 287*91f16700Schasinglulu memcpy(prop_data, val, len); 288*91f16700Schasinglulu return 0; 289*91f16700Schasinglulu } 290*91f16700Schasinglulu 291*91f16700Schasinglulu int fdt_appendprop(void *fdt, int nodeoffset, const char *name, 292*91f16700Schasinglulu const void *val, int len) 293*91f16700Schasinglulu { 294*91f16700Schasinglulu struct fdt_property *prop; 295*91f16700Schasinglulu int err, oldlen, newlen; 296*91f16700Schasinglulu 297*91f16700Schasinglulu FDT_RW_PROBE(fdt); 298*91f16700Schasinglulu 299*91f16700Schasinglulu prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); 300*91f16700Schasinglulu if (prop) { 301*91f16700Schasinglulu newlen = len + oldlen; 302*91f16700Schasinglulu err = fdt_splice_struct_(fdt, prop->data, 303*91f16700Schasinglulu FDT_TAGALIGN(oldlen), 304*91f16700Schasinglulu FDT_TAGALIGN(newlen)); 305*91f16700Schasinglulu if (err) 306*91f16700Schasinglulu return err; 307*91f16700Schasinglulu prop->len = cpu_to_fdt32(newlen); 308*91f16700Schasinglulu memcpy(prop->data + oldlen, val, len); 309*91f16700Schasinglulu } else { 310*91f16700Schasinglulu err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); 311*91f16700Schasinglulu if (err) 312*91f16700Schasinglulu return err; 313*91f16700Schasinglulu memcpy(prop->data, val, len); 314*91f16700Schasinglulu } 315*91f16700Schasinglulu return 0; 316*91f16700Schasinglulu } 317*91f16700Schasinglulu 318*91f16700Schasinglulu int fdt_delprop(void *fdt, int nodeoffset, const char *name) 319*91f16700Schasinglulu { 320*91f16700Schasinglulu struct fdt_property *prop; 321*91f16700Schasinglulu int len, proplen; 322*91f16700Schasinglulu 323*91f16700Schasinglulu FDT_RW_PROBE(fdt); 324*91f16700Schasinglulu 325*91f16700Schasinglulu prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 326*91f16700Schasinglulu if (!prop) 327*91f16700Schasinglulu return len; 328*91f16700Schasinglulu 329*91f16700Schasinglulu proplen = sizeof(*prop) + FDT_TAGALIGN(len); 330*91f16700Schasinglulu return fdt_splice_struct_(fdt, prop, proplen, 0); 331*91f16700Schasinglulu } 332*91f16700Schasinglulu 333*91f16700Schasinglulu int fdt_add_subnode_namelen(void *fdt, int parentoffset, 334*91f16700Schasinglulu const char *name, int namelen) 335*91f16700Schasinglulu { 336*91f16700Schasinglulu struct fdt_node_header *nh; 337*91f16700Schasinglulu int offset, nextoffset; 338*91f16700Schasinglulu int nodelen; 339*91f16700Schasinglulu int err; 340*91f16700Schasinglulu uint32_t tag; 341*91f16700Schasinglulu fdt32_t *endtag; 342*91f16700Schasinglulu 343*91f16700Schasinglulu FDT_RW_PROBE(fdt); 344*91f16700Schasinglulu 345*91f16700Schasinglulu offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); 346*91f16700Schasinglulu if (offset >= 0) 347*91f16700Schasinglulu return -FDT_ERR_EXISTS; 348*91f16700Schasinglulu else if (offset != -FDT_ERR_NOTFOUND) 349*91f16700Schasinglulu return offset; 350*91f16700Schasinglulu 351*91f16700Schasinglulu /* Try to place the new node after the parent's properties */ 352*91f16700Schasinglulu tag = fdt_next_tag(fdt, parentoffset, &nextoffset); 353*91f16700Schasinglulu /* the fdt_subnode_offset_namelen() should ensure this never hits */ 354*91f16700Schasinglulu if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) 355*91f16700Schasinglulu return -FDT_ERR_INTERNAL; 356*91f16700Schasinglulu do { 357*91f16700Schasinglulu offset = nextoffset; 358*91f16700Schasinglulu tag = fdt_next_tag(fdt, offset, &nextoffset); 359*91f16700Schasinglulu } while ((tag == FDT_PROP) || (tag == FDT_NOP)); 360*91f16700Schasinglulu 361*91f16700Schasinglulu nh = fdt_offset_ptr_w_(fdt, offset); 362*91f16700Schasinglulu nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; 363*91f16700Schasinglulu 364*91f16700Schasinglulu err = fdt_splice_struct_(fdt, nh, 0, nodelen); 365*91f16700Schasinglulu if (err) 366*91f16700Schasinglulu return err; 367*91f16700Schasinglulu 368*91f16700Schasinglulu nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 369*91f16700Schasinglulu memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); 370*91f16700Schasinglulu memcpy(nh->name, name, namelen); 371*91f16700Schasinglulu endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); 372*91f16700Schasinglulu *endtag = cpu_to_fdt32(FDT_END_NODE); 373*91f16700Schasinglulu 374*91f16700Schasinglulu return offset; 375*91f16700Schasinglulu } 376*91f16700Schasinglulu 377*91f16700Schasinglulu int fdt_add_subnode(void *fdt, int parentoffset, const char *name) 378*91f16700Schasinglulu { 379*91f16700Schasinglulu return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); 380*91f16700Schasinglulu } 381*91f16700Schasinglulu 382*91f16700Schasinglulu int fdt_del_node(void *fdt, int nodeoffset) 383*91f16700Schasinglulu { 384*91f16700Schasinglulu int endoffset; 385*91f16700Schasinglulu 386*91f16700Schasinglulu FDT_RW_PROBE(fdt); 387*91f16700Schasinglulu 388*91f16700Schasinglulu endoffset = fdt_node_end_offset_(fdt, nodeoffset); 389*91f16700Schasinglulu if (endoffset < 0) 390*91f16700Schasinglulu return endoffset; 391*91f16700Schasinglulu 392*91f16700Schasinglulu return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset), 393*91f16700Schasinglulu endoffset - nodeoffset, 0); 394*91f16700Schasinglulu } 395*91f16700Schasinglulu 396*91f16700Schasinglulu static void fdt_packblocks_(const char *old, char *new, 397*91f16700Schasinglulu int mem_rsv_size, 398*91f16700Schasinglulu int struct_size, 399*91f16700Schasinglulu int strings_size) 400*91f16700Schasinglulu { 401*91f16700Schasinglulu int mem_rsv_off, struct_off, strings_off; 402*91f16700Schasinglulu 403*91f16700Schasinglulu mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); 404*91f16700Schasinglulu struct_off = mem_rsv_off + mem_rsv_size; 405*91f16700Schasinglulu strings_off = struct_off + struct_size; 406*91f16700Schasinglulu 407*91f16700Schasinglulu memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); 408*91f16700Schasinglulu fdt_set_off_mem_rsvmap(new, mem_rsv_off); 409*91f16700Schasinglulu 410*91f16700Schasinglulu memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); 411*91f16700Schasinglulu fdt_set_off_dt_struct(new, struct_off); 412*91f16700Schasinglulu fdt_set_size_dt_struct(new, struct_size); 413*91f16700Schasinglulu 414*91f16700Schasinglulu memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); 415*91f16700Schasinglulu fdt_set_off_dt_strings(new, strings_off); 416*91f16700Schasinglulu fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); 417*91f16700Schasinglulu } 418*91f16700Schasinglulu 419*91f16700Schasinglulu int fdt_open_into(const void *fdt, void *buf, int bufsize) 420*91f16700Schasinglulu { 421*91f16700Schasinglulu int err; 422*91f16700Schasinglulu int mem_rsv_size, struct_size; 423*91f16700Schasinglulu int newsize; 424*91f16700Schasinglulu const char *fdtstart = fdt; 425*91f16700Schasinglulu const char *fdtend = fdtstart + fdt_totalsize(fdt); 426*91f16700Schasinglulu char *tmp; 427*91f16700Schasinglulu 428*91f16700Schasinglulu FDT_RO_PROBE(fdt); 429*91f16700Schasinglulu 430*91f16700Schasinglulu mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 431*91f16700Schasinglulu * sizeof(struct fdt_reserve_entry); 432*91f16700Schasinglulu 433*91f16700Schasinglulu if (can_assume(LATEST) || fdt_version(fdt) >= 17) { 434*91f16700Schasinglulu struct_size = fdt_size_dt_struct(fdt); 435*91f16700Schasinglulu } else if (fdt_version(fdt) == 16) { 436*91f16700Schasinglulu struct_size = 0; 437*91f16700Schasinglulu while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) 438*91f16700Schasinglulu ; 439*91f16700Schasinglulu if (struct_size < 0) 440*91f16700Schasinglulu return struct_size; 441*91f16700Schasinglulu } else { 442*91f16700Schasinglulu return -FDT_ERR_BADVERSION; 443*91f16700Schasinglulu } 444*91f16700Schasinglulu 445*91f16700Schasinglulu if (can_assume(LIBFDT_ORDER) || 446*91f16700Schasinglulu !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { 447*91f16700Schasinglulu /* no further work necessary */ 448*91f16700Schasinglulu err = fdt_move(fdt, buf, bufsize); 449*91f16700Schasinglulu if (err) 450*91f16700Schasinglulu return err; 451*91f16700Schasinglulu fdt_set_version(buf, 17); 452*91f16700Schasinglulu fdt_set_size_dt_struct(buf, struct_size); 453*91f16700Schasinglulu fdt_set_totalsize(buf, bufsize); 454*91f16700Schasinglulu return 0; 455*91f16700Schasinglulu } 456*91f16700Schasinglulu 457*91f16700Schasinglulu /* Need to reorder */ 458*91f16700Schasinglulu newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size 459*91f16700Schasinglulu + struct_size + fdt_size_dt_strings(fdt); 460*91f16700Schasinglulu 461*91f16700Schasinglulu if (bufsize < newsize) 462*91f16700Schasinglulu return -FDT_ERR_NOSPACE; 463*91f16700Schasinglulu 464*91f16700Schasinglulu /* First attempt to build converted tree at beginning of buffer */ 465*91f16700Schasinglulu tmp = buf; 466*91f16700Schasinglulu /* But if that overlaps with the old tree... */ 467*91f16700Schasinglulu if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { 468*91f16700Schasinglulu /* Try right after the old tree instead */ 469*91f16700Schasinglulu tmp = (char *)(uintptr_t)fdtend; 470*91f16700Schasinglulu if ((tmp + newsize) > ((char *)buf + bufsize)) 471*91f16700Schasinglulu return -FDT_ERR_NOSPACE; 472*91f16700Schasinglulu } 473*91f16700Schasinglulu 474*91f16700Schasinglulu fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, 475*91f16700Schasinglulu fdt_size_dt_strings(fdt)); 476*91f16700Schasinglulu memmove(buf, tmp, newsize); 477*91f16700Schasinglulu 478*91f16700Schasinglulu fdt_set_magic(buf, FDT_MAGIC); 479*91f16700Schasinglulu fdt_set_totalsize(buf, bufsize); 480*91f16700Schasinglulu fdt_set_version(buf, 17); 481*91f16700Schasinglulu fdt_set_last_comp_version(buf, 16); 482*91f16700Schasinglulu fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); 483*91f16700Schasinglulu 484*91f16700Schasinglulu return 0; 485*91f16700Schasinglulu } 486*91f16700Schasinglulu 487*91f16700Schasinglulu int fdt_pack(void *fdt) 488*91f16700Schasinglulu { 489*91f16700Schasinglulu int mem_rsv_size; 490*91f16700Schasinglulu 491*91f16700Schasinglulu FDT_RW_PROBE(fdt); 492*91f16700Schasinglulu 493*91f16700Schasinglulu mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 494*91f16700Schasinglulu * sizeof(struct fdt_reserve_entry); 495*91f16700Schasinglulu fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), 496*91f16700Schasinglulu fdt_size_dt_strings(fdt)); 497*91f16700Schasinglulu fdt_set_totalsize(fdt, fdt_data_size_(fdt)); 498*91f16700Schasinglulu 499*91f16700Schasinglulu return 0; 500*91f16700Schasinglulu } 501