18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * libfdt - Flat Device Tree manipulation 48c2ecf20Sopenharmony_ci * Copyright (C) 2006 David Gibson, IBM Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include "libfdt_env.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <fdt.h> 98c2ecf20Sopenharmony_ci#include <libfdt.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "libfdt_internal.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic int fdt_sw_probe_(void *fdt) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci if (!can_assume(VALID_INPUT)) { 168c2ecf20Sopenharmony_ci if (fdt_magic(fdt) == FDT_MAGIC) 178c2ecf20Sopenharmony_ci return -FDT_ERR_BADSTATE; 188c2ecf20Sopenharmony_ci else if (fdt_magic(fdt) != FDT_SW_MAGIC) 198c2ecf20Sopenharmony_ci return -FDT_ERR_BADMAGIC; 208c2ecf20Sopenharmony_ci } 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci return 0; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define FDT_SW_PROBE(fdt) \ 268c2ecf20Sopenharmony_ci { \ 278c2ecf20Sopenharmony_ci int err; \ 288c2ecf20Sopenharmony_ci if ((err = fdt_sw_probe_(fdt)) != 0) \ 298c2ecf20Sopenharmony_ci return err; \ 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 'memrsv' state: Initial state after fdt_create() 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Allowed functions: 358c2ecf20Sopenharmony_ci * fdt_add_reservemap_entry() 368c2ecf20Sopenharmony_ci * fdt_finish_reservemap() [moves to 'struct' state] 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistatic int fdt_sw_probe_memrsv_(void *fdt) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int err = fdt_sw_probe_(fdt); 418c2ecf20Sopenharmony_ci if (err) 428c2ecf20Sopenharmony_ci return err; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) 458c2ecf20Sopenharmony_ci return -FDT_ERR_BADSTATE; 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define FDT_SW_PROBE_MEMRSV(fdt) \ 508c2ecf20Sopenharmony_ci { \ 518c2ecf20Sopenharmony_ci int err; \ 528c2ecf20Sopenharmony_ci if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ 538c2ecf20Sopenharmony_ci return err; \ 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 'struct' state: Enter this state after fdt_finish_reservemap() 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * Allowed functions: 598c2ecf20Sopenharmony_ci * fdt_begin_node() 608c2ecf20Sopenharmony_ci * fdt_end_node() 618c2ecf20Sopenharmony_ci * fdt_property*() 628c2ecf20Sopenharmony_ci * fdt_finish() [moves to 'complete' state] 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic int fdt_sw_probe_struct_(void *fdt) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci int err = fdt_sw_probe_(fdt); 678c2ecf20Sopenharmony_ci if (err) 688c2ecf20Sopenharmony_ci return err; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (!can_assume(VALID_INPUT) && 718c2ecf20Sopenharmony_ci fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) 728c2ecf20Sopenharmony_ci return -FDT_ERR_BADSTATE; 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define FDT_SW_PROBE_STRUCT(fdt) \ 778c2ecf20Sopenharmony_ci { \ 788c2ecf20Sopenharmony_ci int err; \ 798c2ecf20Sopenharmony_ci if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ 808c2ecf20Sopenharmony_ci return err; \ 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic inline uint32_t sw_flags(void *fdt) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */ 868c2ecf20Sopenharmony_ci return fdt_last_comp_version(fdt); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 'complete' state: Enter this state after fdt_finish() 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * Allowed functions: none 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void *fdt_grab_space_(void *fdt, size_t len) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci unsigned int offset = fdt_size_dt_struct(fdt); 978c2ecf20Sopenharmony_ci unsigned int spaceleft; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) 1008c2ecf20Sopenharmony_ci - fdt_size_dt_strings(fdt); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if ((offset + len < offset) || (offset + len > spaceleft)) 1038c2ecf20Sopenharmony_ci return NULL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci fdt_set_size_dt_struct(fdt, offset + len); 1068c2ecf20Sopenharmony_ci return fdt_offset_ptr_w_(fdt, offset); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), 1128c2ecf20Sopenharmony_ci sizeof(struct fdt_reserve_entry)); 1138c2ecf20Sopenharmony_ci void *fdt = buf; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (bufsize < hdrsize) 1168c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (flags & ~FDT_CREATE_FLAGS_ALL) 1198c2ecf20Sopenharmony_ci return -FDT_ERR_BADFLAGS; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci memset(buf, 0, bufsize); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* 1248c2ecf20Sopenharmony_ci * magic and last_comp_version keep intermediate state during the fdt 1258c2ecf20Sopenharmony_ci * creation process, which is replaced with the proper FDT format by 1268c2ecf20Sopenharmony_ci * fdt_finish(). 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * flags should be accessed with sw_flags(). 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci fdt_set_magic(fdt, FDT_SW_MAGIC); 1318c2ecf20Sopenharmony_ci fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 1328c2ecf20Sopenharmony_ci fdt_set_last_comp_version(fdt, flags); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci fdt_set_totalsize(fdt, bufsize); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci fdt_set_off_mem_rsvmap(fdt, hdrsize); 1378c2ecf20Sopenharmony_ci fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 1388c2ecf20Sopenharmony_ci fdt_set_off_dt_strings(fdt, 0); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciint fdt_create(void *buf, int bufsize) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci return fdt_create_with_flags(buf, bufsize, 0); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciint fdt_resize(void *fdt, void *buf, int bufsize) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci size_t headsize, tailsize; 1518c2ecf20Sopenharmony_ci char *oldtail, *newtail; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci FDT_SW_PROBE(fdt); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (bufsize < 0) 1568c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 1598c2ecf20Sopenharmony_ci tailsize = fdt_size_dt_strings(fdt); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (!can_assume(VALID_DTB) && 1628c2ecf20Sopenharmony_ci headsize + tailsize > fdt_totalsize(fdt)) 1638c2ecf20Sopenharmony_ci return -FDT_ERR_INTERNAL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if ((headsize + tailsize) > (unsigned)bufsize) 1668c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; 1698c2ecf20Sopenharmony_ci newtail = (char *)buf + bufsize - tailsize; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Two cases to avoid clobbering data if the old and new 1728c2ecf20Sopenharmony_ci * buffers partially overlap */ 1738c2ecf20Sopenharmony_ci if (buf <= fdt) { 1748c2ecf20Sopenharmony_ci memmove(buf, fdt, headsize); 1758c2ecf20Sopenharmony_ci memmove(newtail, oldtail, tailsize); 1768c2ecf20Sopenharmony_ci } else { 1778c2ecf20Sopenharmony_ci memmove(newtail, oldtail, tailsize); 1788c2ecf20Sopenharmony_ci memmove(buf, fdt, headsize); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci fdt_set_totalsize(buf, bufsize); 1828c2ecf20Sopenharmony_ci if (fdt_off_dt_strings(buf)) 1838c2ecf20Sopenharmony_ci fdt_set_off_dt_strings(buf, bufsize); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciint fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct fdt_reserve_entry *re; 1918c2ecf20Sopenharmony_ci int offset; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci FDT_SW_PROBE_MEMRSV(fdt); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci offset = fdt_off_dt_struct(fdt); 1968c2ecf20Sopenharmony_ci if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) 1978c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci re = (struct fdt_reserve_entry *)((char *)fdt + offset); 2008c2ecf20Sopenharmony_ci re->address = cpu_to_fdt64(addr); 2018c2ecf20Sopenharmony_ci re->size = cpu_to_fdt64(size); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciint fdt_finish_reservemap(void *fdt) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int err = fdt_add_reservemap_entry(fdt, 0, 0); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (err) 2138c2ecf20Sopenharmony_ci return err; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciint fdt_begin_node(void *fdt, const char *name) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct fdt_node_header *nh; 2228c2ecf20Sopenharmony_ci int namelen; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci FDT_SW_PROBE_STRUCT(fdt); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci namelen = strlen(name) + 1; 2278c2ecf20Sopenharmony_ci nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); 2288c2ecf20Sopenharmony_ci if (! nh) 2298c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 2328c2ecf20Sopenharmony_ci memcpy(nh->name, name, namelen); 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ciint fdt_end_node(void *fdt) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci fdt32_t *en; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci FDT_SW_PROBE_STRUCT(fdt); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci en = fdt_grab_space_(fdt, FDT_TAGSIZE); 2438c2ecf20Sopenharmony_ci if (! en) 2448c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci *en = cpu_to_fdt32(FDT_END_NODE); 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int fdt_add_string_(void *fdt, const char *s) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci char *strtab = (char *)fdt + fdt_totalsize(fdt); 2538c2ecf20Sopenharmony_ci unsigned int strtabsize = fdt_size_dt_strings(fdt); 2548c2ecf20Sopenharmony_ci unsigned int len = strlen(s) + 1; 2558c2ecf20Sopenharmony_ci unsigned int struct_top, offset; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci offset = strtabsize + len; 2588c2ecf20Sopenharmony_ci struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 2598c2ecf20Sopenharmony_ci if (fdt_totalsize(fdt) - offset < struct_top) 2608c2ecf20Sopenharmony_ci return 0; /* no more room :( */ 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci memcpy(strtab - offset, s, len); 2638c2ecf20Sopenharmony_ci fdt_set_size_dt_strings(fdt, strtabsize + len); 2648c2ecf20Sopenharmony_ci return -offset; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* Must only be used to roll back in case of error */ 2688c2ecf20Sopenharmony_cistatic void fdt_del_last_string_(void *fdt, const char *s) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci int strtabsize = fdt_size_dt_strings(fdt); 2718c2ecf20Sopenharmony_ci int len = strlen(s) + 1; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci fdt_set_size_dt_strings(fdt, strtabsize - len); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int fdt_find_add_string_(void *fdt, const char *s, int *allocated) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci char *strtab = (char *)fdt + fdt_totalsize(fdt); 2798c2ecf20Sopenharmony_ci int strtabsize = fdt_size_dt_strings(fdt); 2808c2ecf20Sopenharmony_ci const char *p; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci *allocated = 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci p = fdt_find_string_(strtab - strtabsize, strtabsize, s); 2858c2ecf20Sopenharmony_ci if (p) 2868c2ecf20Sopenharmony_ci return p - strtab; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci *allocated = 1; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return fdt_add_string_(fdt, s); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ciint fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct fdt_property *prop; 2968c2ecf20Sopenharmony_ci int nameoff; 2978c2ecf20Sopenharmony_ci int allocated; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci FDT_SW_PROBE_STRUCT(fdt); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */ 3028c2ecf20Sopenharmony_ci if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) { 3038c2ecf20Sopenharmony_ci allocated = 1; 3048c2ecf20Sopenharmony_ci nameoff = fdt_add_string_(fdt, name); 3058c2ecf20Sopenharmony_ci } else { 3068c2ecf20Sopenharmony_ci nameoff = fdt_find_add_string_(fdt, name, &allocated); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci if (nameoff == 0) 3098c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 3128c2ecf20Sopenharmony_ci if (! prop) { 3138c2ecf20Sopenharmony_ci if (allocated) 3148c2ecf20Sopenharmony_ci fdt_del_last_string_(fdt, name); 3158c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci prop->tag = cpu_to_fdt32(FDT_PROP); 3198c2ecf20Sopenharmony_ci prop->nameoff = cpu_to_fdt32(nameoff); 3208c2ecf20Sopenharmony_ci prop->len = cpu_to_fdt32(len); 3218c2ecf20Sopenharmony_ci *valp = prop->data; 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ciint fdt_property(void *fdt, const char *name, const void *val, int len) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci void *ptr; 3288c2ecf20Sopenharmony_ci int ret; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ret = fdt_property_placeholder(fdt, name, len, &ptr); 3318c2ecf20Sopenharmony_ci if (ret) 3328c2ecf20Sopenharmony_ci return ret; 3338c2ecf20Sopenharmony_ci memcpy(ptr, val, len); 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciint fdt_finish(void *fdt) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci char *p = (char *)fdt; 3408c2ecf20Sopenharmony_ci fdt32_t *end; 3418c2ecf20Sopenharmony_ci int oldstroffset, newstroffset; 3428c2ecf20Sopenharmony_ci uint32_t tag; 3438c2ecf20Sopenharmony_ci int offset, nextoffset; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci FDT_SW_PROBE_STRUCT(fdt); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Add terminator */ 3488c2ecf20Sopenharmony_ci end = fdt_grab_space_(fdt, sizeof(*end)); 3498c2ecf20Sopenharmony_ci if (! end) 3508c2ecf20Sopenharmony_ci return -FDT_ERR_NOSPACE; 3518c2ecf20Sopenharmony_ci *end = cpu_to_fdt32(FDT_END); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* Relocate the string table */ 3548c2ecf20Sopenharmony_ci oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); 3558c2ecf20Sopenharmony_ci newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 3568c2ecf20Sopenharmony_ci memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); 3578c2ecf20Sopenharmony_ci fdt_set_off_dt_strings(fdt, newstroffset); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* Walk the structure, correcting string offsets */ 3608c2ecf20Sopenharmony_ci offset = 0; 3618c2ecf20Sopenharmony_ci while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { 3628c2ecf20Sopenharmony_ci if (tag == FDT_PROP) { 3638c2ecf20Sopenharmony_ci struct fdt_property *prop = 3648c2ecf20Sopenharmony_ci fdt_offset_ptr_w_(fdt, offset); 3658c2ecf20Sopenharmony_ci int nameoff; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci nameoff = fdt32_to_cpu(prop->nameoff); 3688c2ecf20Sopenharmony_ci nameoff += fdt_size_dt_strings(fdt); 3698c2ecf20Sopenharmony_ci prop->nameoff = cpu_to_fdt32(nameoff); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci offset = nextoffset; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci if (nextoffset < 0) 3748c2ecf20Sopenharmony_ci return nextoffset; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* Finally, adjust the header */ 3778c2ecf20Sopenharmony_ci fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* And fix up fields that were keeping intermediate state. */ 3808c2ecf20Sopenharmony_ci fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); 3818c2ecf20Sopenharmony_ci fdt_set_magic(fdt, FDT_MAGIC); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 385