1*243ce5d5SMadhukar Pappireddy // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2630b011fSAntonio Nino Diaz /* 3630b011fSAntonio Nino Diaz * libfdt - Flat Device Tree manipulation 4630b011fSAntonio Nino Diaz * Copyright (C) 2006 David Gibson, IBM Corporation. 5630b011fSAntonio Nino Diaz */ 6630b011fSAntonio Nino Diaz #include "libfdt_env.h" 7630b011fSAntonio Nino Diaz 8630b011fSAntonio Nino Diaz #include <fdt.h> 9630b011fSAntonio Nino Diaz #include <libfdt.h> 10630b011fSAntonio Nino Diaz 11630b011fSAntonio Nino Diaz #include "libfdt_internal.h" 12630b011fSAntonio Nino Diaz 13*243ce5d5SMadhukar Pappireddy static int fdt_sw_probe_(void *fdt) 14630b011fSAntonio Nino Diaz { 15*243ce5d5SMadhukar Pappireddy if (!can_assume(VALID_INPUT)) { 16*243ce5d5SMadhukar Pappireddy if (fdt_magic(fdt) == FDT_MAGIC) 17*243ce5d5SMadhukar Pappireddy return -FDT_ERR_BADSTATE; 18*243ce5d5SMadhukar Pappireddy else if (fdt_magic(fdt) != FDT_SW_MAGIC) 19630b011fSAntonio Nino Diaz return -FDT_ERR_BADMAGIC; 20*243ce5d5SMadhukar Pappireddy } 21*243ce5d5SMadhukar Pappireddy 22630b011fSAntonio Nino Diaz return 0; 23630b011fSAntonio Nino Diaz } 24630b011fSAntonio Nino Diaz 25*243ce5d5SMadhukar Pappireddy #define FDT_SW_PROBE(fdt) \ 26630b011fSAntonio Nino Diaz { \ 27630b011fSAntonio Nino Diaz int err; \ 28*243ce5d5SMadhukar Pappireddy if ((err = fdt_sw_probe_(fdt)) != 0) \ 29630b011fSAntonio Nino Diaz return err; \ 30630b011fSAntonio Nino Diaz } 31630b011fSAntonio Nino Diaz 32*243ce5d5SMadhukar Pappireddy /* 'memrsv' state: Initial state after fdt_create() 33*243ce5d5SMadhukar Pappireddy * 34*243ce5d5SMadhukar Pappireddy * Allowed functions: 35*243ce5d5SMadhukar Pappireddy * fdt_add_reservmap_entry() 36*243ce5d5SMadhukar Pappireddy * fdt_finish_reservemap() [moves to 'struct' state] 37*243ce5d5SMadhukar Pappireddy */ 38*243ce5d5SMadhukar Pappireddy static int fdt_sw_probe_memrsv_(void *fdt) 39*243ce5d5SMadhukar Pappireddy { 40*243ce5d5SMadhukar Pappireddy int err = fdt_sw_probe_(fdt); 41*243ce5d5SMadhukar Pappireddy if (err) 42*243ce5d5SMadhukar Pappireddy return err; 43*243ce5d5SMadhukar Pappireddy 44*243ce5d5SMadhukar Pappireddy if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) 45*243ce5d5SMadhukar Pappireddy return -FDT_ERR_BADSTATE; 46*243ce5d5SMadhukar Pappireddy return 0; 47*243ce5d5SMadhukar Pappireddy } 48*243ce5d5SMadhukar Pappireddy 49*243ce5d5SMadhukar Pappireddy #define FDT_SW_PROBE_MEMRSV(fdt) \ 50*243ce5d5SMadhukar Pappireddy { \ 51*243ce5d5SMadhukar Pappireddy int err; \ 52*243ce5d5SMadhukar Pappireddy if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ 53*243ce5d5SMadhukar Pappireddy return err; \ 54*243ce5d5SMadhukar Pappireddy } 55*243ce5d5SMadhukar Pappireddy 56*243ce5d5SMadhukar Pappireddy /* 'struct' state: Enter this state after fdt_finish_reservemap() 57*243ce5d5SMadhukar Pappireddy * 58*243ce5d5SMadhukar Pappireddy * Allowed functions: 59*243ce5d5SMadhukar Pappireddy * fdt_begin_node() 60*243ce5d5SMadhukar Pappireddy * fdt_end_node() 61*243ce5d5SMadhukar Pappireddy * fdt_property*() 62*243ce5d5SMadhukar Pappireddy * fdt_finish() [moves to 'complete' state] 63*243ce5d5SMadhukar Pappireddy */ 64*243ce5d5SMadhukar Pappireddy static int fdt_sw_probe_struct_(void *fdt) 65*243ce5d5SMadhukar Pappireddy { 66*243ce5d5SMadhukar Pappireddy int err = fdt_sw_probe_(fdt); 67*243ce5d5SMadhukar Pappireddy if (err) 68*243ce5d5SMadhukar Pappireddy return err; 69*243ce5d5SMadhukar Pappireddy 70*243ce5d5SMadhukar Pappireddy if (!can_assume(VALID_INPUT) && 71*243ce5d5SMadhukar Pappireddy fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) 72*243ce5d5SMadhukar Pappireddy return -FDT_ERR_BADSTATE; 73*243ce5d5SMadhukar Pappireddy return 0; 74*243ce5d5SMadhukar Pappireddy } 75*243ce5d5SMadhukar Pappireddy 76*243ce5d5SMadhukar Pappireddy #define FDT_SW_PROBE_STRUCT(fdt) \ 77*243ce5d5SMadhukar Pappireddy { \ 78*243ce5d5SMadhukar Pappireddy int err; \ 79*243ce5d5SMadhukar Pappireddy if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ 80*243ce5d5SMadhukar Pappireddy return err; \ 81*243ce5d5SMadhukar Pappireddy } 82*243ce5d5SMadhukar Pappireddy 83*243ce5d5SMadhukar Pappireddy static inline uint32_t sw_flags(void *fdt) 84*243ce5d5SMadhukar Pappireddy { 85*243ce5d5SMadhukar Pappireddy /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */ 86*243ce5d5SMadhukar Pappireddy return fdt_last_comp_version(fdt); 87*243ce5d5SMadhukar Pappireddy } 88*243ce5d5SMadhukar Pappireddy 89*243ce5d5SMadhukar Pappireddy /* 'complete' state: Enter this state after fdt_finish() 90*243ce5d5SMadhukar Pappireddy * 91*243ce5d5SMadhukar Pappireddy * Allowed functions: none 92*243ce5d5SMadhukar Pappireddy */ 93*243ce5d5SMadhukar Pappireddy 94630b011fSAntonio Nino Diaz static void *fdt_grab_space_(void *fdt, size_t len) 95630b011fSAntonio Nino Diaz { 96630b011fSAntonio Nino Diaz int offset = fdt_size_dt_struct(fdt); 97630b011fSAntonio Nino Diaz int spaceleft; 98630b011fSAntonio Nino Diaz 99630b011fSAntonio Nino Diaz spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) 100630b011fSAntonio Nino Diaz - fdt_size_dt_strings(fdt); 101630b011fSAntonio Nino Diaz 102630b011fSAntonio Nino Diaz if ((offset + len < offset) || (offset + len > spaceleft)) 103630b011fSAntonio Nino Diaz return NULL; 104630b011fSAntonio Nino Diaz 105630b011fSAntonio Nino Diaz fdt_set_size_dt_struct(fdt, offset + len); 106630b011fSAntonio Nino Diaz return fdt_offset_ptr_w_(fdt, offset); 107630b011fSAntonio Nino Diaz } 108630b011fSAntonio Nino Diaz 109*243ce5d5SMadhukar Pappireddy int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) 110630b011fSAntonio Nino Diaz { 111*243ce5d5SMadhukar Pappireddy const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header), 112*243ce5d5SMadhukar Pappireddy sizeof(struct fdt_reserve_entry)); 113630b011fSAntonio Nino Diaz void *fdt = buf; 114630b011fSAntonio Nino Diaz 115*243ce5d5SMadhukar Pappireddy if (bufsize < hdrsize) 116630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 117630b011fSAntonio Nino Diaz 118*243ce5d5SMadhukar Pappireddy if (flags & ~FDT_CREATE_FLAGS_ALL) 119*243ce5d5SMadhukar Pappireddy return -FDT_ERR_BADFLAGS; 120*243ce5d5SMadhukar Pappireddy 121630b011fSAntonio Nino Diaz memset(buf, 0, bufsize); 122630b011fSAntonio Nino Diaz 123*243ce5d5SMadhukar Pappireddy /* 124*243ce5d5SMadhukar Pappireddy * magic and last_comp_version keep intermediate state during the fdt 125*243ce5d5SMadhukar Pappireddy * creation process, which is replaced with the proper FDT format by 126*243ce5d5SMadhukar Pappireddy * fdt_finish(). 127*243ce5d5SMadhukar Pappireddy * 128*243ce5d5SMadhukar Pappireddy * flags should be accessed with sw_flags(). 129*243ce5d5SMadhukar Pappireddy */ 130630b011fSAntonio Nino Diaz fdt_set_magic(fdt, FDT_SW_MAGIC); 131630b011fSAntonio Nino Diaz fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 132*243ce5d5SMadhukar Pappireddy fdt_set_last_comp_version(fdt, flags); 133*243ce5d5SMadhukar Pappireddy 134630b011fSAntonio Nino Diaz fdt_set_totalsize(fdt, bufsize); 135630b011fSAntonio Nino Diaz 136*243ce5d5SMadhukar Pappireddy fdt_set_off_mem_rsvmap(fdt, hdrsize); 137630b011fSAntonio Nino Diaz fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 138*243ce5d5SMadhukar Pappireddy fdt_set_off_dt_strings(fdt, 0); 139630b011fSAntonio Nino Diaz 140630b011fSAntonio Nino Diaz return 0; 141630b011fSAntonio Nino Diaz } 142630b011fSAntonio Nino Diaz 143*243ce5d5SMadhukar Pappireddy int fdt_create(void *buf, int bufsize) 144*243ce5d5SMadhukar Pappireddy { 145*243ce5d5SMadhukar Pappireddy return fdt_create_with_flags(buf, bufsize, 0); 146*243ce5d5SMadhukar Pappireddy } 147*243ce5d5SMadhukar Pappireddy 148630b011fSAntonio Nino Diaz int fdt_resize(void *fdt, void *buf, int bufsize) 149630b011fSAntonio Nino Diaz { 150630b011fSAntonio Nino Diaz size_t headsize, tailsize; 151630b011fSAntonio Nino Diaz char *oldtail, *newtail; 152630b011fSAntonio Nino Diaz 153*243ce5d5SMadhukar Pappireddy FDT_SW_PROBE(fdt); 154630b011fSAntonio Nino Diaz 155*243ce5d5SMadhukar Pappireddy headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 156630b011fSAntonio Nino Diaz tailsize = fdt_size_dt_strings(fdt); 157630b011fSAntonio Nino Diaz 158*243ce5d5SMadhukar Pappireddy if (!can_assume(VALID_DTB) && 159*243ce5d5SMadhukar Pappireddy headsize + tailsize > fdt_totalsize(fdt)) 160*243ce5d5SMadhukar Pappireddy return -FDT_ERR_INTERNAL; 161*243ce5d5SMadhukar Pappireddy 162630b011fSAntonio Nino Diaz if ((headsize + tailsize) > bufsize) 163630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 164630b011fSAntonio Nino Diaz 165630b011fSAntonio Nino Diaz oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; 166630b011fSAntonio Nino Diaz newtail = (char *)buf + bufsize - tailsize; 167630b011fSAntonio Nino Diaz 168630b011fSAntonio Nino Diaz /* Two cases to avoid clobbering data if the old and new 169630b011fSAntonio Nino Diaz * buffers partially overlap */ 170630b011fSAntonio Nino Diaz if (buf <= fdt) { 171630b011fSAntonio Nino Diaz memmove(buf, fdt, headsize); 172630b011fSAntonio Nino Diaz memmove(newtail, oldtail, tailsize); 173630b011fSAntonio Nino Diaz } else { 174630b011fSAntonio Nino Diaz memmove(newtail, oldtail, tailsize); 175630b011fSAntonio Nino Diaz memmove(buf, fdt, headsize); 176630b011fSAntonio Nino Diaz } 177630b011fSAntonio Nino Diaz 17800f588bfSAntonio Nino Diaz fdt_set_totalsize(buf, bufsize); 179*243ce5d5SMadhukar Pappireddy if (fdt_off_dt_strings(buf)) 180*243ce5d5SMadhukar Pappireddy fdt_set_off_dt_strings(buf, bufsize); 181630b011fSAntonio Nino Diaz 182630b011fSAntonio Nino Diaz return 0; 183630b011fSAntonio Nino Diaz } 184630b011fSAntonio Nino Diaz 185630b011fSAntonio Nino Diaz int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) 186630b011fSAntonio Nino Diaz { 187630b011fSAntonio Nino Diaz struct fdt_reserve_entry *re; 188630b011fSAntonio Nino Diaz int offset; 189630b011fSAntonio Nino Diaz 190*243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_MEMRSV(fdt); 191630b011fSAntonio Nino Diaz 192630b011fSAntonio Nino Diaz offset = fdt_off_dt_struct(fdt); 193630b011fSAntonio Nino Diaz if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) 194630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 195630b011fSAntonio Nino Diaz 196630b011fSAntonio Nino Diaz re = (struct fdt_reserve_entry *)((char *)fdt + offset); 197630b011fSAntonio Nino Diaz re->address = cpu_to_fdt64(addr); 198630b011fSAntonio Nino Diaz re->size = cpu_to_fdt64(size); 199630b011fSAntonio Nino Diaz 200630b011fSAntonio Nino Diaz fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); 201630b011fSAntonio Nino Diaz 202630b011fSAntonio Nino Diaz return 0; 203630b011fSAntonio Nino Diaz } 204630b011fSAntonio Nino Diaz 205630b011fSAntonio Nino Diaz int fdt_finish_reservemap(void *fdt) 206630b011fSAntonio Nino Diaz { 207*243ce5d5SMadhukar Pappireddy int err = fdt_add_reservemap_entry(fdt, 0, 0); 208*243ce5d5SMadhukar Pappireddy 209*243ce5d5SMadhukar Pappireddy if (err) 210*243ce5d5SMadhukar Pappireddy return err; 211*243ce5d5SMadhukar Pappireddy 212*243ce5d5SMadhukar Pappireddy fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); 213*243ce5d5SMadhukar Pappireddy return 0; 214630b011fSAntonio Nino Diaz } 215630b011fSAntonio Nino Diaz 216630b011fSAntonio Nino Diaz int fdt_begin_node(void *fdt, const char *name) 217630b011fSAntonio Nino Diaz { 218630b011fSAntonio Nino Diaz struct fdt_node_header *nh; 219*243ce5d5SMadhukar Pappireddy int namelen; 220630b011fSAntonio Nino Diaz 221*243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_STRUCT(fdt); 222630b011fSAntonio Nino Diaz 223*243ce5d5SMadhukar Pappireddy namelen = strlen(name) + 1; 224630b011fSAntonio Nino Diaz nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); 225630b011fSAntonio Nino Diaz if (! nh) 226630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 227630b011fSAntonio Nino Diaz 228630b011fSAntonio Nino Diaz nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 229630b011fSAntonio Nino Diaz memcpy(nh->name, name, namelen); 230630b011fSAntonio Nino Diaz return 0; 231630b011fSAntonio Nino Diaz } 232630b011fSAntonio Nino Diaz 233630b011fSAntonio Nino Diaz int fdt_end_node(void *fdt) 234630b011fSAntonio Nino Diaz { 235630b011fSAntonio Nino Diaz fdt32_t *en; 236630b011fSAntonio Nino Diaz 237*243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_STRUCT(fdt); 238630b011fSAntonio Nino Diaz 239630b011fSAntonio Nino Diaz en = fdt_grab_space_(fdt, FDT_TAGSIZE); 240630b011fSAntonio Nino Diaz if (! en) 241630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 242630b011fSAntonio Nino Diaz 243630b011fSAntonio Nino Diaz *en = cpu_to_fdt32(FDT_END_NODE); 244630b011fSAntonio Nino Diaz return 0; 245630b011fSAntonio Nino Diaz } 246630b011fSAntonio Nino Diaz 247*243ce5d5SMadhukar Pappireddy static int fdt_add_string_(void *fdt, const char *s) 248630b011fSAntonio Nino Diaz { 249630b011fSAntonio Nino Diaz char *strtab = (char *)fdt + fdt_totalsize(fdt); 250630b011fSAntonio Nino Diaz int strtabsize = fdt_size_dt_strings(fdt); 251630b011fSAntonio Nino Diaz int len = strlen(s) + 1; 252630b011fSAntonio Nino Diaz int struct_top, offset; 253630b011fSAntonio Nino Diaz 254630b011fSAntonio Nino Diaz offset = -strtabsize - len; 255630b011fSAntonio Nino Diaz struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 256630b011fSAntonio Nino Diaz if (fdt_totalsize(fdt) + offset < struct_top) 257630b011fSAntonio Nino Diaz return 0; /* no more room :( */ 258630b011fSAntonio Nino Diaz 259630b011fSAntonio Nino Diaz memcpy(strtab + offset, s, len); 260630b011fSAntonio Nino Diaz fdt_set_size_dt_strings(fdt, strtabsize + len); 261630b011fSAntonio Nino Diaz return offset; 262630b011fSAntonio Nino Diaz } 263630b011fSAntonio Nino Diaz 264*243ce5d5SMadhukar Pappireddy /* Must only be used to roll back in case of error */ 265*243ce5d5SMadhukar Pappireddy static void fdt_del_last_string_(void *fdt, const char *s) 266*243ce5d5SMadhukar Pappireddy { 267*243ce5d5SMadhukar Pappireddy int strtabsize = fdt_size_dt_strings(fdt); 268*243ce5d5SMadhukar Pappireddy int len = strlen(s) + 1; 269*243ce5d5SMadhukar Pappireddy 270*243ce5d5SMadhukar Pappireddy fdt_set_size_dt_strings(fdt, strtabsize - len); 271*243ce5d5SMadhukar Pappireddy } 272*243ce5d5SMadhukar Pappireddy 273*243ce5d5SMadhukar Pappireddy static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) 274*243ce5d5SMadhukar Pappireddy { 275*243ce5d5SMadhukar Pappireddy char *strtab = (char *)fdt + fdt_totalsize(fdt); 276*243ce5d5SMadhukar Pappireddy int strtabsize = fdt_size_dt_strings(fdt); 277*243ce5d5SMadhukar Pappireddy const char *p; 278*243ce5d5SMadhukar Pappireddy 279*243ce5d5SMadhukar Pappireddy *allocated = 0; 280*243ce5d5SMadhukar Pappireddy 281*243ce5d5SMadhukar Pappireddy p = fdt_find_string_(strtab - strtabsize, strtabsize, s); 282*243ce5d5SMadhukar Pappireddy if (p) 283*243ce5d5SMadhukar Pappireddy return p - strtab; 284*243ce5d5SMadhukar Pappireddy 285*243ce5d5SMadhukar Pappireddy *allocated = 1; 286*243ce5d5SMadhukar Pappireddy 287*243ce5d5SMadhukar Pappireddy return fdt_add_string_(fdt, s); 288*243ce5d5SMadhukar Pappireddy } 289*243ce5d5SMadhukar Pappireddy 290630b011fSAntonio Nino Diaz int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) 291630b011fSAntonio Nino Diaz { 292630b011fSAntonio Nino Diaz struct fdt_property *prop; 293630b011fSAntonio Nino Diaz int nameoff; 294*243ce5d5SMadhukar Pappireddy int allocated; 295630b011fSAntonio Nino Diaz 296*243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_STRUCT(fdt); 297630b011fSAntonio Nino Diaz 298*243ce5d5SMadhukar Pappireddy /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */ 299*243ce5d5SMadhukar Pappireddy if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) { 300*243ce5d5SMadhukar Pappireddy allocated = 1; 301*243ce5d5SMadhukar Pappireddy nameoff = fdt_add_string_(fdt, name); 302*243ce5d5SMadhukar Pappireddy } else { 303*243ce5d5SMadhukar Pappireddy nameoff = fdt_find_add_string_(fdt, name, &allocated); 304*243ce5d5SMadhukar Pappireddy } 305630b011fSAntonio Nino Diaz if (nameoff == 0) 306630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 307630b011fSAntonio Nino Diaz 308630b011fSAntonio Nino Diaz prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 309*243ce5d5SMadhukar Pappireddy if (! prop) { 310*243ce5d5SMadhukar Pappireddy if (allocated) 311*243ce5d5SMadhukar Pappireddy fdt_del_last_string_(fdt, name); 312630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 313*243ce5d5SMadhukar Pappireddy } 314630b011fSAntonio Nino Diaz 315630b011fSAntonio Nino Diaz prop->tag = cpu_to_fdt32(FDT_PROP); 316630b011fSAntonio Nino Diaz prop->nameoff = cpu_to_fdt32(nameoff); 317630b011fSAntonio Nino Diaz prop->len = cpu_to_fdt32(len); 318630b011fSAntonio Nino Diaz *valp = prop->data; 319630b011fSAntonio Nino Diaz return 0; 320630b011fSAntonio Nino Diaz } 321630b011fSAntonio Nino Diaz 322630b011fSAntonio Nino Diaz int fdt_property(void *fdt, const char *name, const void *val, int len) 323630b011fSAntonio Nino Diaz { 324630b011fSAntonio Nino Diaz void *ptr; 325630b011fSAntonio Nino Diaz int ret; 326630b011fSAntonio Nino Diaz 327630b011fSAntonio Nino Diaz ret = fdt_property_placeholder(fdt, name, len, &ptr); 328630b011fSAntonio Nino Diaz if (ret) 329630b011fSAntonio Nino Diaz return ret; 330630b011fSAntonio Nino Diaz memcpy(ptr, val, len); 331630b011fSAntonio Nino Diaz return 0; 332630b011fSAntonio Nino Diaz } 333630b011fSAntonio Nino Diaz 334630b011fSAntonio Nino Diaz int fdt_finish(void *fdt) 335630b011fSAntonio Nino Diaz { 336630b011fSAntonio Nino Diaz char *p = (char *)fdt; 337630b011fSAntonio Nino Diaz fdt32_t *end; 338630b011fSAntonio Nino Diaz int oldstroffset, newstroffset; 339630b011fSAntonio Nino Diaz uint32_t tag; 340630b011fSAntonio Nino Diaz int offset, nextoffset; 341630b011fSAntonio Nino Diaz 342*243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_STRUCT(fdt); 343630b011fSAntonio Nino Diaz 344630b011fSAntonio Nino Diaz /* Add terminator */ 345630b011fSAntonio Nino Diaz end = fdt_grab_space_(fdt, sizeof(*end)); 346630b011fSAntonio Nino Diaz if (! end) 347630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 348630b011fSAntonio Nino Diaz *end = cpu_to_fdt32(FDT_END); 349630b011fSAntonio Nino Diaz 350630b011fSAntonio Nino Diaz /* Relocate the string table */ 351630b011fSAntonio Nino Diaz oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); 352630b011fSAntonio Nino Diaz newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 353630b011fSAntonio Nino Diaz memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); 354630b011fSAntonio Nino Diaz fdt_set_off_dt_strings(fdt, newstroffset); 355630b011fSAntonio Nino Diaz 356630b011fSAntonio Nino Diaz /* Walk the structure, correcting string offsets */ 357630b011fSAntonio Nino Diaz offset = 0; 358630b011fSAntonio Nino Diaz while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { 359630b011fSAntonio Nino Diaz if (tag == FDT_PROP) { 360630b011fSAntonio Nino Diaz struct fdt_property *prop = 361630b011fSAntonio Nino Diaz fdt_offset_ptr_w_(fdt, offset); 362630b011fSAntonio Nino Diaz int nameoff; 363630b011fSAntonio Nino Diaz 364630b011fSAntonio Nino Diaz nameoff = fdt32_to_cpu(prop->nameoff); 365630b011fSAntonio Nino Diaz nameoff += fdt_size_dt_strings(fdt); 366630b011fSAntonio Nino Diaz prop->nameoff = cpu_to_fdt32(nameoff); 367630b011fSAntonio Nino Diaz } 368630b011fSAntonio Nino Diaz offset = nextoffset; 369630b011fSAntonio Nino Diaz } 370630b011fSAntonio Nino Diaz if (nextoffset < 0) 371630b011fSAntonio Nino Diaz return nextoffset; 372630b011fSAntonio Nino Diaz 373630b011fSAntonio Nino Diaz /* Finally, adjust the header */ 374630b011fSAntonio Nino Diaz fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 375*243ce5d5SMadhukar Pappireddy 376*243ce5d5SMadhukar Pappireddy /* And fix up fields that were keeping intermediate state. */ 377*243ce5d5SMadhukar Pappireddy fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); 378630b011fSAntonio Nino Diaz fdt_set_magic(fdt, FDT_MAGIC); 379*243ce5d5SMadhukar Pappireddy 380630b011fSAntonio Nino Diaz return 0; 381630b011fSAntonio Nino Diaz } 382