1243ce5d5SMadhukar 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 13243ce5d5SMadhukar Pappireddy static int fdt_sw_probe_(void *fdt) 14630b011fSAntonio Nino Diaz { 15243ce5d5SMadhukar Pappireddy if (!can_assume(VALID_INPUT)) { 16243ce5d5SMadhukar Pappireddy if (fdt_magic(fdt) == FDT_MAGIC) 17243ce5d5SMadhukar Pappireddy return -FDT_ERR_BADSTATE; 18243ce5d5SMadhukar Pappireddy else if (fdt_magic(fdt) != FDT_SW_MAGIC) 19630b011fSAntonio Nino Diaz return -FDT_ERR_BADMAGIC; 20243ce5d5SMadhukar Pappireddy } 21243ce5d5SMadhukar Pappireddy 22630b011fSAntonio Nino Diaz return 0; 23630b011fSAntonio Nino Diaz } 24630b011fSAntonio Nino Diaz 25243ce5d5SMadhukar Pappireddy #define FDT_SW_PROBE(fdt) \ 26630b011fSAntonio Nino Diaz { \ 27630b011fSAntonio Nino Diaz int err; \ 28243ce5d5SMadhukar Pappireddy if ((err = fdt_sw_probe_(fdt)) != 0) \ 29630b011fSAntonio Nino Diaz return err; \ 30630b011fSAntonio Nino Diaz } 31630b011fSAntonio Nino Diaz 32243ce5d5SMadhukar Pappireddy /* 'memrsv' state: Initial state after fdt_create() 33243ce5d5SMadhukar Pappireddy * 34243ce5d5SMadhukar Pappireddy * Allowed functions: 35*3b456661SAndre Przywara * fdt_add_reservemap_entry() 36243ce5d5SMadhukar Pappireddy * fdt_finish_reservemap() [moves to 'struct' state] 37243ce5d5SMadhukar Pappireddy */ 38243ce5d5SMadhukar Pappireddy static int fdt_sw_probe_memrsv_(void *fdt) 39243ce5d5SMadhukar Pappireddy { 40243ce5d5SMadhukar Pappireddy int err = fdt_sw_probe_(fdt); 41243ce5d5SMadhukar Pappireddy if (err) 42243ce5d5SMadhukar Pappireddy return err; 43243ce5d5SMadhukar Pappireddy 44243ce5d5SMadhukar Pappireddy if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) 45243ce5d5SMadhukar Pappireddy return -FDT_ERR_BADSTATE; 46243ce5d5SMadhukar Pappireddy return 0; 47243ce5d5SMadhukar Pappireddy } 48243ce5d5SMadhukar Pappireddy 49243ce5d5SMadhukar Pappireddy #define FDT_SW_PROBE_MEMRSV(fdt) \ 50243ce5d5SMadhukar Pappireddy { \ 51243ce5d5SMadhukar Pappireddy int err; \ 52243ce5d5SMadhukar Pappireddy if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ 53243ce5d5SMadhukar Pappireddy return err; \ 54243ce5d5SMadhukar Pappireddy } 55243ce5d5SMadhukar Pappireddy 56243ce5d5SMadhukar Pappireddy /* 'struct' state: Enter this state after fdt_finish_reservemap() 57243ce5d5SMadhukar Pappireddy * 58243ce5d5SMadhukar Pappireddy * Allowed functions: 59243ce5d5SMadhukar Pappireddy * fdt_begin_node() 60243ce5d5SMadhukar Pappireddy * fdt_end_node() 61243ce5d5SMadhukar Pappireddy * fdt_property*() 62243ce5d5SMadhukar Pappireddy * fdt_finish() [moves to 'complete' state] 63243ce5d5SMadhukar Pappireddy */ 64243ce5d5SMadhukar Pappireddy static int fdt_sw_probe_struct_(void *fdt) 65243ce5d5SMadhukar Pappireddy { 66243ce5d5SMadhukar Pappireddy int err = fdt_sw_probe_(fdt); 67243ce5d5SMadhukar Pappireddy if (err) 68243ce5d5SMadhukar Pappireddy return err; 69243ce5d5SMadhukar Pappireddy 70243ce5d5SMadhukar Pappireddy if (!can_assume(VALID_INPUT) && 71243ce5d5SMadhukar Pappireddy fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) 72243ce5d5SMadhukar Pappireddy return -FDT_ERR_BADSTATE; 73243ce5d5SMadhukar Pappireddy return 0; 74243ce5d5SMadhukar Pappireddy } 75243ce5d5SMadhukar Pappireddy 76243ce5d5SMadhukar Pappireddy #define FDT_SW_PROBE_STRUCT(fdt) \ 77243ce5d5SMadhukar Pappireddy { \ 78243ce5d5SMadhukar Pappireddy int err; \ 79243ce5d5SMadhukar Pappireddy if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ 80243ce5d5SMadhukar Pappireddy return err; \ 81243ce5d5SMadhukar Pappireddy } 82243ce5d5SMadhukar Pappireddy 83243ce5d5SMadhukar Pappireddy static inline uint32_t sw_flags(void *fdt) 84243ce5d5SMadhukar Pappireddy { 85243ce5d5SMadhukar Pappireddy /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */ 86243ce5d5SMadhukar Pappireddy return fdt_last_comp_version(fdt); 87243ce5d5SMadhukar Pappireddy } 88243ce5d5SMadhukar Pappireddy 89243ce5d5SMadhukar Pappireddy /* 'complete' state: Enter this state after fdt_finish() 90243ce5d5SMadhukar Pappireddy * 91243ce5d5SMadhukar Pappireddy * Allowed functions: none 92243ce5d5SMadhukar Pappireddy */ 93243ce5d5SMadhukar Pappireddy 94630b011fSAntonio Nino Diaz static void *fdt_grab_space_(void *fdt, size_t len) 95630b011fSAntonio Nino Diaz { 96*3b456661SAndre Przywara unsigned int offset = fdt_size_dt_struct(fdt); 97*3b456661SAndre Przywara unsigned 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 109243ce5d5SMadhukar Pappireddy int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) 110630b011fSAntonio Nino Diaz { 111*3b456661SAndre Przywara const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), 112243ce5d5SMadhukar Pappireddy sizeof(struct fdt_reserve_entry)); 113630b011fSAntonio Nino Diaz void *fdt = buf; 114630b011fSAntonio Nino Diaz 115243ce5d5SMadhukar Pappireddy if (bufsize < hdrsize) 116630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 117630b011fSAntonio Nino Diaz 118243ce5d5SMadhukar Pappireddy if (flags & ~FDT_CREATE_FLAGS_ALL) 119243ce5d5SMadhukar Pappireddy return -FDT_ERR_BADFLAGS; 120243ce5d5SMadhukar Pappireddy 121630b011fSAntonio Nino Diaz memset(buf, 0, bufsize); 122630b011fSAntonio Nino Diaz 123243ce5d5SMadhukar Pappireddy /* 124243ce5d5SMadhukar Pappireddy * magic and last_comp_version keep intermediate state during the fdt 125243ce5d5SMadhukar Pappireddy * creation process, which is replaced with the proper FDT format by 126243ce5d5SMadhukar Pappireddy * fdt_finish(). 127243ce5d5SMadhukar Pappireddy * 128243ce5d5SMadhukar Pappireddy * flags should be accessed with sw_flags(). 129243ce5d5SMadhukar Pappireddy */ 130630b011fSAntonio Nino Diaz fdt_set_magic(fdt, FDT_SW_MAGIC); 131630b011fSAntonio Nino Diaz fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 132243ce5d5SMadhukar Pappireddy fdt_set_last_comp_version(fdt, flags); 133243ce5d5SMadhukar Pappireddy 134630b011fSAntonio Nino Diaz fdt_set_totalsize(fdt, bufsize); 135630b011fSAntonio Nino Diaz 136243ce5d5SMadhukar Pappireddy fdt_set_off_mem_rsvmap(fdt, hdrsize); 137630b011fSAntonio Nino Diaz fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 138243ce5d5SMadhukar Pappireddy fdt_set_off_dt_strings(fdt, 0); 139630b011fSAntonio Nino Diaz 140630b011fSAntonio Nino Diaz return 0; 141630b011fSAntonio Nino Diaz } 142630b011fSAntonio Nino Diaz 143243ce5d5SMadhukar Pappireddy int fdt_create(void *buf, int bufsize) 144243ce5d5SMadhukar Pappireddy { 145243ce5d5SMadhukar Pappireddy return fdt_create_with_flags(buf, bufsize, 0); 146243ce5d5SMadhukar Pappireddy } 147243ce5d5SMadhukar 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 153243ce5d5SMadhukar Pappireddy FDT_SW_PROBE(fdt); 154630b011fSAntonio Nino Diaz 155*3b456661SAndre Przywara if (bufsize < 0) 156*3b456661SAndre Przywara return -FDT_ERR_NOSPACE; 157*3b456661SAndre Przywara 158243ce5d5SMadhukar Pappireddy headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 159630b011fSAntonio Nino Diaz tailsize = fdt_size_dt_strings(fdt); 160630b011fSAntonio Nino Diaz 161243ce5d5SMadhukar Pappireddy if (!can_assume(VALID_DTB) && 162243ce5d5SMadhukar Pappireddy headsize + tailsize > fdt_totalsize(fdt)) 163243ce5d5SMadhukar Pappireddy return -FDT_ERR_INTERNAL; 164243ce5d5SMadhukar Pappireddy 165*3b456661SAndre Przywara if ((headsize + tailsize) > (unsigned)bufsize) 166630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 167630b011fSAntonio Nino Diaz 168630b011fSAntonio Nino Diaz oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; 169630b011fSAntonio Nino Diaz newtail = (char *)buf + bufsize - tailsize; 170630b011fSAntonio Nino Diaz 171630b011fSAntonio Nino Diaz /* Two cases to avoid clobbering data if the old and new 172630b011fSAntonio Nino Diaz * buffers partially overlap */ 173630b011fSAntonio Nino Diaz if (buf <= fdt) { 174630b011fSAntonio Nino Diaz memmove(buf, fdt, headsize); 175630b011fSAntonio Nino Diaz memmove(newtail, oldtail, tailsize); 176630b011fSAntonio Nino Diaz } else { 177630b011fSAntonio Nino Diaz memmove(newtail, oldtail, tailsize); 178630b011fSAntonio Nino Diaz memmove(buf, fdt, headsize); 179630b011fSAntonio Nino Diaz } 180630b011fSAntonio Nino Diaz 18100f588bfSAntonio Nino Diaz fdt_set_totalsize(buf, bufsize); 182243ce5d5SMadhukar Pappireddy if (fdt_off_dt_strings(buf)) 183243ce5d5SMadhukar Pappireddy fdt_set_off_dt_strings(buf, bufsize); 184630b011fSAntonio Nino Diaz 185630b011fSAntonio Nino Diaz return 0; 186630b011fSAntonio Nino Diaz } 187630b011fSAntonio Nino Diaz 188630b011fSAntonio Nino Diaz int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) 189630b011fSAntonio Nino Diaz { 190630b011fSAntonio Nino Diaz struct fdt_reserve_entry *re; 191630b011fSAntonio Nino Diaz int offset; 192630b011fSAntonio Nino Diaz 193243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_MEMRSV(fdt); 194630b011fSAntonio Nino Diaz 195630b011fSAntonio Nino Diaz offset = fdt_off_dt_struct(fdt); 196630b011fSAntonio Nino Diaz if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) 197630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 198630b011fSAntonio Nino Diaz 199630b011fSAntonio Nino Diaz re = (struct fdt_reserve_entry *)((char *)fdt + offset); 200630b011fSAntonio Nino Diaz re->address = cpu_to_fdt64(addr); 201630b011fSAntonio Nino Diaz re->size = cpu_to_fdt64(size); 202630b011fSAntonio Nino Diaz 203630b011fSAntonio Nino Diaz fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); 204630b011fSAntonio Nino Diaz 205630b011fSAntonio Nino Diaz return 0; 206630b011fSAntonio Nino Diaz } 207630b011fSAntonio Nino Diaz 208630b011fSAntonio Nino Diaz int fdt_finish_reservemap(void *fdt) 209630b011fSAntonio Nino Diaz { 210243ce5d5SMadhukar Pappireddy int err = fdt_add_reservemap_entry(fdt, 0, 0); 211243ce5d5SMadhukar Pappireddy 212243ce5d5SMadhukar Pappireddy if (err) 213243ce5d5SMadhukar Pappireddy return err; 214243ce5d5SMadhukar Pappireddy 215243ce5d5SMadhukar Pappireddy fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); 216243ce5d5SMadhukar Pappireddy return 0; 217630b011fSAntonio Nino Diaz } 218630b011fSAntonio Nino Diaz 219630b011fSAntonio Nino Diaz int fdt_begin_node(void *fdt, const char *name) 220630b011fSAntonio Nino Diaz { 221630b011fSAntonio Nino Diaz struct fdt_node_header *nh; 222243ce5d5SMadhukar Pappireddy int namelen; 223630b011fSAntonio Nino Diaz 224243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_STRUCT(fdt); 225630b011fSAntonio Nino Diaz 226243ce5d5SMadhukar Pappireddy namelen = strlen(name) + 1; 227630b011fSAntonio Nino Diaz nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); 228630b011fSAntonio Nino Diaz if (! nh) 229630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 230630b011fSAntonio Nino Diaz 231630b011fSAntonio Nino Diaz nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 232630b011fSAntonio Nino Diaz memcpy(nh->name, name, namelen); 233630b011fSAntonio Nino Diaz return 0; 234630b011fSAntonio Nino Diaz } 235630b011fSAntonio Nino Diaz 236630b011fSAntonio Nino Diaz int fdt_end_node(void *fdt) 237630b011fSAntonio Nino Diaz { 238630b011fSAntonio Nino Diaz fdt32_t *en; 239630b011fSAntonio Nino Diaz 240243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_STRUCT(fdt); 241630b011fSAntonio Nino Diaz 242630b011fSAntonio Nino Diaz en = fdt_grab_space_(fdt, FDT_TAGSIZE); 243630b011fSAntonio Nino Diaz if (! en) 244630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 245630b011fSAntonio Nino Diaz 246630b011fSAntonio Nino Diaz *en = cpu_to_fdt32(FDT_END_NODE); 247630b011fSAntonio Nino Diaz return 0; 248630b011fSAntonio Nino Diaz } 249630b011fSAntonio Nino Diaz 250243ce5d5SMadhukar Pappireddy static int fdt_add_string_(void *fdt, const char *s) 251630b011fSAntonio Nino Diaz { 252630b011fSAntonio Nino Diaz char *strtab = (char *)fdt + fdt_totalsize(fdt); 253*3b456661SAndre Przywara unsigned int strtabsize = fdt_size_dt_strings(fdt); 254*3b456661SAndre Przywara unsigned int len = strlen(s) + 1; 255*3b456661SAndre Przywara unsigned int struct_top, offset; 256630b011fSAntonio Nino Diaz 257*3b456661SAndre Przywara offset = strtabsize + len; 258630b011fSAntonio Nino Diaz struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 259*3b456661SAndre Przywara if (fdt_totalsize(fdt) - offset < struct_top) 260630b011fSAntonio Nino Diaz return 0; /* no more room :( */ 261630b011fSAntonio Nino Diaz 262*3b456661SAndre Przywara memcpy(strtab - offset, s, len); 263630b011fSAntonio Nino Diaz fdt_set_size_dt_strings(fdt, strtabsize + len); 264*3b456661SAndre Przywara return -offset; 265630b011fSAntonio Nino Diaz } 266630b011fSAntonio Nino Diaz 267243ce5d5SMadhukar Pappireddy /* Must only be used to roll back in case of error */ 268243ce5d5SMadhukar Pappireddy static void fdt_del_last_string_(void *fdt, const char *s) 269243ce5d5SMadhukar Pappireddy { 270243ce5d5SMadhukar Pappireddy int strtabsize = fdt_size_dt_strings(fdt); 271243ce5d5SMadhukar Pappireddy int len = strlen(s) + 1; 272243ce5d5SMadhukar Pappireddy 273243ce5d5SMadhukar Pappireddy fdt_set_size_dt_strings(fdt, strtabsize - len); 274243ce5d5SMadhukar Pappireddy } 275243ce5d5SMadhukar Pappireddy 276243ce5d5SMadhukar Pappireddy static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) 277243ce5d5SMadhukar Pappireddy { 278243ce5d5SMadhukar Pappireddy char *strtab = (char *)fdt + fdt_totalsize(fdt); 279243ce5d5SMadhukar Pappireddy int strtabsize = fdt_size_dt_strings(fdt); 280243ce5d5SMadhukar Pappireddy const char *p; 281243ce5d5SMadhukar Pappireddy 282243ce5d5SMadhukar Pappireddy *allocated = 0; 283243ce5d5SMadhukar Pappireddy 284243ce5d5SMadhukar Pappireddy p = fdt_find_string_(strtab - strtabsize, strtabsize, s); 285243ce5d5SMadhukar Pappireddy if (p) 286243ce5d5SMadhukar Pappireddy return p - strtab; 287243ce5d5SMadhukar Pappireddy 288243ce5d5SMadhukar Pappireddy *allocated = 1; 289243ce5d5SMadhukar Pappireddy 290243ce5d5SMadhukar Pappireddy return fdt_add_string_(fdt, s); 291243ce5d5SMadhukar Pappireddy } 292243ce5d5SMadhukar Pappireddy 293630b011fSAntonio Nino Diaz int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) 294630b011fSAntonio Nino Diaz { 295630b011fSAntonio Nino Diaz struct fdt_property *prop; 296630b011fSAntonio Nino Diaz int nameoff; 297243ce5d5SMadhukar Pappireddy int allocated; 298630b011fSAntonio Nino Diaz 299243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_STRUCT(fdt); 300630b011fSAntonio Nino Diaz 301243ce5d5SMadhukar Pappireddy /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */ 302243ce5d5SMadhukar Pappireddy if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) { 303243ce5d5SMadhukar Pappireddy allocated = 1; 304243ce5d5SMadhukar Pappireddy nameoff = fdt_add_string_(fdt, name); 305243ce5d5SMadhukar Pappireddy } else { 306243ce5d5SMadhukar Pappireddy nameoff = fdt_find_add_string_(fdt, name, &allocated); 307243ce5d5SMadhukar Pappireddy } 308630b011fSAntonio Nino Diaz if (nameoff == 0) 309630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 310630b011fSAntonio Nino Diaz 311630b011fSAntonio Nino Diaz prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 312243ce5d5SMadhukar Pappireddy if (! prop) { 313243ce5d5SMadhukar Pappireddy if (allocated) 314243ce5d5SMadhukar Pappireddy fdt_del_last_string_(fdt, name); 315630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 316243ce5d5SMadhukar Pappireddy } 317630b011fSAntonio Nino Diaz 318630b011fSAntonio Nino Diaz prop->tag = cpu_to_fdt32(FDT_PROP); 319630b011fSAntonio Nino Diaz prop->nameoff = cpu_to_fdt32(nameoff); 320630b011fSAntonio Nino Diaz prop->len = cpu_to_fdt32(len); 321630b011fSAntonio Nino Diaz *valp = prop->data; 322630b011fSAntonio Nino Diaz return 0; 323630b011fSAntonio Nino Diaz } 324630b011fSAntonio Nino Diaz 325630b011fSAntonio Nino Diaz int fdt_property(void *fdt, const char *name, const void *val, int len) 326630b011fSAntonio Nino Diaz { 327630b011fSAntonio Nino Diaz void *ptr; 328630b011fSAntonio Nino Diaz int ret; 329630b011fSAntonio Nino Diaz 330630b011fSAntonio Nino Diaz ret = fdt_property_placeholder(fdt, name, len, &ptr); 331630b011fSAntonio Nino Diaz if (ret) 332630b011fSAntonio Nino Diaz return ret; 333630b011fSAntonio Nino Diaz memcpy(ptr, val, len); 334630b011fSAntonio Nino Diaz return 0; 335630b011fSAntonio Nino Diaz } 336630b011fSAntonio Nino Diaz 337630b011fSAntonio Nino Diaz int fdt_finish(void *fdt) 338630b011fSAntonio Nino Diaz { 339630b011fSAntonio Nino Diaz char *p = (char *)fdt; 340630b011fSAntonio Nino Diaz fdt32_t *end; 341630b011fSAntonio Nino Diaz int oldstroffset, newstroffset; 342630b011fSAntonio Nino Diaz uint32_t tag; 343630b011fSAntonio Nino Diaz int offset, nextoffset; 344630b011fSAntonio Nino Diaz 345243ce5d5SMadhukar Pappireddy FDT_SW_PROBE_STRUCT(fdt); 346630b011fSAntonio Nino Diaz 347630b011fSAntonio Nino Diaz /* Add terminator */ 348630b011fSAntonio Nino Diaz end = fdt_grab_space_(fdt, sizeof(*end)); 349630b011fSAntonio Nino Diaz if (! end) 350630b011fSAntonio Nino Diaz return -FDT_ERR_NOSPACE; 351630b011fSAntonio Nino Diaz *end = cpu_to_fdt32(FDT_END); 352630b011fSAntonio Nino Diaz 353630b011fSAntonio Nino Diaz /* Relocate the string table */ 354630b011fSAntonio Nino Diaz oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); 355630b011fSAntonio Nino Diaz newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 356630b011fSAntonio Nino Diaz memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); 357630b011fSAntonio Nino Diaz fdt_set_off_dt_strings(fdt, newstroffset); 358630b011fSAntonio Nino Diaz 359630b011fSAntonio Nino Diaz /* Walk the structure, correcting string offsets */ 360630b011fSAntonio Nino Diaz offset = 0; 361630b011fSAntonio Nino Diaz while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { 362630b011fSAntonio Nino Diaz if (tag == FDT_PROP) { 363630b011fSAntonio Nino Diaz struct fdt_property *prop = 364630b011fSAntonio Nino Diaz fdt_offset_ptr_w_(fdt, offset); 365630b011fSAntonio Nino Diaz int nameoff; 366630b011fSAntonio Nino Diaz 367630b011fSAntonio Nino Diaz nameoff = fdt32_to_cpu(prop->nameoff); 368630b011fSAntonio Nino Diaz nameoff += fdt_size_dt_strings(fdt); 369630b011fSAntonio Nino Diaz prop->nameoff = cpu_to_fdt32(nameoff); 370630b011fSAntonio Nino Diaz } 371630b011fSAntonio Nino Diaz offset = nextoffset; 372630b011fSAntonio Nino Diaz } 373630b011fSAntonio Nino Diaz if (nextoffset < 0) 374630b011fSAntonio Nino Diaz return nextoffset; 375630b011fSAntonio Nino Diaz 376630b011fSAntonio Nino Diaz /* Finally, adjust the header */ 377630b011fSAntonio Nino Diaz fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 378243ce5d5SMadhukar Pappireddy 379243ce5d5SMadhukar Pappireddy /* And fix up fields that were keeping intermediate state. */ 380243ce5d5SMadhukar Pappireddy fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); 381630b011fSAntonio Nino Diaz fdt_set_magic(fdt, FDT_MAGIC); 382243ce5d5SMadhukar Pappireddy 383630b011fSAntonio Nino Diaz return 0; 384630b011fSAntonio Nino Diaz } 385