^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * libfdt - Flat Device Tree manipulation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2006 David Gibson, IBM Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include "libfdt_env.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <fdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <libfdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "libfdt_internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static int fdt_sw_probe_(void *fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) if (!can_assume(VALID_INPUT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) if (fdt_magic(fdt) == FDT_MAGIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) return -FDT_ERR_BADSTATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) else if (fdt_magic(fdt) != FDT_SW_MAGIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) return -FDT_ERR_BADMAGIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define FDT_SW_PROBE(fdt) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) int err; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) if ((err = fdt_sw_probe_(fdt)) != 0) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return err; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* 'memrsv' state: Initial state after fdt_create()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Allowed functions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * fdt_add_reservemap_entry()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * fdt_finish_reservemap() [moves to 'struct' state]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static int fdt_sw_probe_memrsv_(void *fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int err = fdt_sw_probe_(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return -FDT_ERR_BADSTATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define FDT_SW_PROBE_MEMRSV(fdt) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int err; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return err; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* 'struct' state: Enter this state after fdt_finish_reservemap()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Allowed functions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * fdt_begin_node()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * fdt_end_node()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * fdt_property*()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * fdt_finish() [moves to 'complete' state]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int fdt_sw_probe_struct_(void *fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int err = fdt_sw_probe_(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (!can_assume(VALID_INPUT) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return -FDT_ERR_BADSTATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define FDT_SW_PROBE_STRUCT(fdt) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int err; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return err; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static inline uint32_t sw_flags(void *fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return fdt_last_comp_version(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* 'complete' state: Enter this state after fdt_finish()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * Allowed functions: none
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static void *fdt_grab_space_(void *fdt, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned int offset = fdt_size_dt_struct(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) unsigned int spaceleft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) - fdt_size_dt_strings(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if ((offset + len < offset) || (offset + len > spaceleft))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) fdt_set_size_dt_struct(fdt, offset + len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return fdt_offset_ptr_w_(fdt, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) sizeof(struct fdt_reserve_entry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) void *fdt = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (bufsize < hdrsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (flags & ~FDT_CREATE_FLAGS_ALL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return -FDT_ERR_BADFLAGS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) memset(buf, 0, bufsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * magic and last_comp_version keep intermediate state during the fdt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * creation process, which is replaced with the proper FDT format by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * fdt_finish().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * flags should be accessed with sw_flags().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) fdt_set_magic(fdt, FDT_SW_MAGIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) fdt_set_last_comp_version(fdt, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) fdt_set_totalsize(fdt, bufsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) fdt_set_off_mem_rsvmap(fdt, hdrsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) fdt_set_off_dt_strings(fdt, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int fdt_create(void *buf, int bufsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return fdt_create_with_flags(buf, bufsize, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) int fdt_resize(void *fdt, void *buf, int bufsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) size_t headsize, tailsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) char *oldtail, *newtail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) FDT_SW_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (bufsize < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) tailsize = fdt_size_dt_strings(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (!can_assume(VALID_DTB) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) headsize + tailsize > fdt_totalsize(fdt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return -FDT_ERR_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if ((headsize + tailsize) > (unsigned)bufsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) newtail = (char *)buf + bufsize - tailsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* Two cases to avoid clobbering data if the old and new
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * buffers partially overlap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (buf <= fdt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) memmove(buf, fdt, headsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) memmove(newtail, oldtail, tailsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) memmove(newtail, oldtail, tailsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) memmove(buf, fdt, headsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) fdt_set_totalsize(buf, bufsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (fdt_off_dt_strings(buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) fdt_set_off_dt_strings(buf, bufsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct fdt_reserve_entry *re;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) FDT_SW_PROBE_MEMRSV(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) offset = fdt_off_dt_struct(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) re = (struct fdt_reserve_entry *)((char *)fdt + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) re->address = cpu_to_fdt64(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) re->size = cpu_to_fdt64(size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) int fdt_finish_reservemap(void *fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) int err = fdt_add_reservemap_entry(fdt, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) int fdt_begin_node(void *fdt, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) struct fdt_node_header *nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) int namelen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) FDT_SW_PROBE_STRUCT(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) namelen = strlen(name) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (! nh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) memcpy(nh->name, name, namelen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) int fdt_end_node(void *fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) fdt32_t *en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) FDT_SW_PROBE_STRUCT(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) en = fdt_grab_space_(fdt, FDT_TAGSIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (! en)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) *en = cpu_to_fdt32(FDT_END_NODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static int fdt_add_string_(void *fdt, const char *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) char *strtab = (char *)fdt + fdt_totalsize(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) unsigned int strtabsize = fdt_size_dt_strings(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) unsigned int len = strlen(s) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) unsigned int struct_top, offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) offset = strtabsize + len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (fdt_totalsize(fdt) - offset < struct_top)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return 0; /* no more room :( */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) memcpy(strtab - offset, s, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) fdt_set_size_dt_strings(fdt, strtabsize + len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return -offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* Must only be used to roll back in case of error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static void fdt_del_last_string_(void *fdt, const char *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int strtabsize = fdt_size_dt_strings(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) int len = strlen(s) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) fdt_set_size_dt_strings(fdt, strtabsize - len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) char *strtab = (char *)fdt + fdt_totalsize(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) int strtabsize = fdt_size_dt_strings(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) const char *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) *allocated = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return p - strtab;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) *allocated = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return fdt_add_string_(fdt, s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct fdt_property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) int nameoff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) int allocated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) FDT_SW_PROBE_STRUCT(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) allocated = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) nameoff = fdt_add_string_(fdt, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) nameoff = fdt_find_add_string_(fdt, name, &allocated);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (nameoff == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (! prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (allocated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) fdt_del_last_string_(fdt, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) prop->tag = cpu_to_fdt32(FDT_PROP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) prop->nameoff = cpu_to_fdt32(nameoff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) prop->len = cpu_to_fdt32(len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) *valp = prop->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) int fdt_property(void *fdt, const char *name, const void *val, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) void *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) ret = fdt_property_placeholder(fdt, name, len, &ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) memcpy(ptr, val, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) int fdt_finish(void *fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) char *p = (char *)fdt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) fdt32_t *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) int oldstroffset, newstroffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) uint32_t tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) int offset, nextoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) FDT_SW_PROBE_STRUCT(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) /* Add terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) end = fdt_grab_space_(fdt, sizeof(*end));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (! end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) *end = cpu_to_fdt32(FDT_END);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /* Relocate the string table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) fdt_set_off_dt_strings(fdt, newstroffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) /* Walk the structure, correcting string offsets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (tag == FDT_PROP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) struct fdt_property *prop =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) fdt_offset_ptr_w_(fdt, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) int nameoff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) nameoff = fdt32_to_cpu(prop->nameoff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) nameoff += fdt_size_dt_strings(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) prop->nameoff = cpu_to_fdt32(nameoff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) offset = nextoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (nextoffset < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return nextoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) /* Finally, adjust the header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /* And fix up fields that were keeping intermediate state. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) fdt_set_magic(fdt, FDT_MAGIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }