root/scripts/dtc/libfdt/fdt_sw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fdt_sw_probe_
  2. fdt_sw_probe_memrsv_
  3. fdt_sw_probe_struct_
  4. sw_flags
  5. fdt_grab_space_
  6. fdt_create_with_flags
  7. fdt_create
  8. fdt_resize
  9. fdt_add_reservemap_entry
  10. fdt_finish_reservemap
  11. fdt_begin_node
  12. fdt_end_node
  13. fdt_add_string_
  14. fdt_del_last_string_
  15. fdt_find_add_string_
  16. fdt_property_placeholder
  17. fdt_property
  18. fdt_finish

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

/* [<][>][^][v][top][bottom][index][help] */