Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  fdt_rw.c   Sprache: C

 
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
 * libfdt - Flat Device Tree manipulation
 * Copyright (C) 2006 David Gibson, IBM Corporation.
 */

#include "libfdt_env.h"

#include <fdt.h>
#include <libfdt.h>

#include "libfdt_internal.h"

static int fdt_blocks_misordered_(const void *fdt,
      int mem_rsv_size, int struct_size)
{
 return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
  || (fdt_off_dt_struct(fdt) <
      (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
  || (fdt_off_dt_strings(fdt) <
      (fdt_off_dt_struct(fdt) + struct_size))
  || (fdt_totalsize(fdt) <
      (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}

static int fdt_rw_probe_(void *fdt)
{
 if (can_assume(VALID_DTB))
  return 0;
 FDT_RO_PROBE(fdt);

 if (!can_assume(LATEST) && fdt_version(fdt) < 17)
  return -FDT_ERR_BADVERSION;
 if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
       fdt_size_dt_struct(fdt)))
  return -FDT_ERR_BADLAYOUT;
 if (!can_assume(LATEST) && fdt_version(fdt) > 17)
  fdt_set_version(fdt, 17);

 return 0;
}

#define FDT_RW_PROBE(fdt) \
 { \
  int err_; \
  if ((err_ = fdt_rw_probe_(fdt)) != 0) \
   return err_; \
 }

static inline unsigned int fdt_data_size_(void *fdt)
{
 return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}

static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{
 char *p = splicepoint;
 unsigned int dsize = fdt_data_size_(fdt);
 size_t soff = p - (char *)fdt;

 if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
  return -FDT_ERR_BADOFFSET;
 if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen))
  return -FDT_ERR_BADOFFSET;
 if (dsize - oldlen + newlen > fdt_totalsize(fdt))
  return -FDT_ERR_NOSPACE;
 memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
 return 0;
}

static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
          int oldn, int newn)
{
 int delta = (newn - oldn) * sizeof(*p);
 int err;
 err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
 if (err)
  return err;
 fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
 fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
 return 0;
}

static int fdt_splice_struct_(void *fdt, void *p,
         int oldlen, int newlen)
{
 int delta = newlen - oldlen;
 int err;

 if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
  return err;

 fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
 fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
 return 0;
}

/* Must only be used to roll back in case of error */
static void fdt_del_last_string_(void *fdt, const char *s)
{
 int newlen = strlen(s) + 1;

 fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
}

static int fdt_splice_string_(void *fdt, int newlen)
{
 void *p = (char *)fdt
  + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
 int err;

 if ((err = fdt_splice_(fdt, p, 0, newlen)))
  return err;

 fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
 return 0;
}

/**
 * fdt_find_add_string_() - Find or allocate a string
 *
 * @fdt: pointer to the device tree to check/adjust
 * @s: string to find/add
 * @allocated: Set to 0 if the string was found, 1 if not found and so
 * allocated. Ignored if can_assume(NO_ROLLBACK)
 * @return offset of string in the string table (whether found or added)
 */

static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
{
 char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
 const char *p;
 char *new;
 int len = strlen(s) + 1;
 int err;

 if (!can_assume(NO_ROLLBACK))
  *allocated = 0;

 p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
 if (p)
  /* found it */
  return (p - strtab);

 new = strtab + fdt_size_dt_strings(fdt);
 err = fdt_splice_string_(fdt, len);
 if (err)
  return err;

 if (!can_assume(NO_ROLLBACK))
  *allocated = 1;

 memcpy(new, s, len);
 return (new - strtab);
}

int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
{
 struct fdt_reserve_entry *re;
 int err;

 FDT_RW_PROBE(fdt);

 re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
 err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
 if (err)
  return err;

 re->address = cpu_to_fdt64(address);
 re->size = cpu_to_fdt64(size);
 return 0;
}

int fdt_del_mem_rsv(void *fdt, int n)
{
 struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);

 FDT_RW_PROBE(fdt);

 if (n >= fdt_num_mem_rsv(fdt))
  return -FDT_ERR_NOTFOUND;

 return fdt_splice_mem_rsv_(fdt, re, 1, 0);
}

static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
    int len, struct fdt_property **prop)
{
 int oldlen;
 int err;

 *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
 if (!*prop)
  return oldlen;

 if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
          FDT_TAGALIGN(len))))
  return err;

 (*prop)->len = cpu_to_fdt32(len);
 return 0;
}

static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
        int len, struct fdt_property **prop)
{
 int proplen;
 int nextoffset;
 int namestroff;
 int err;
 int allocated;

 if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
  return nextoffset;

 namestroff = fdt_find_add_string_(fdt, name, &allocated);
 if (namestroff < 0)
  return namestroff;

 *prop = fdt_offset_ptr_w_(fdt, nextoffset);
 proplen = sizeof(**prop) + FDT_TAGALIGN(len);

 err = fdt_splice_struct_(fdt, *prop, 0, proplen);
 if (err) {
  /* Delete the string if we failed to add it */
  if (!can_assume(NO_ROLLBACK) && allocated)
   fdt_del_last_string_(fdt, name);
  return err;
 }

 (*prop)->tag = cpu_to_fdt32(FDT_PROP);
 (*prop)->nameoff = cpu_to_fdt32(namestroff);
 (*prop)->len = cpu_to_fdt32(len);
 return 0;
}

int fdt_set_name(void *fdt, int nodeoffset, const char *name)
{
 char *namep;
 int oldlen, newlen;
 int err;

 FDT_RW_PROBE(fdt);

 namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
 if (!namep)
  return oldlen;

 newlen = strlen(name);

 err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
     FDT_TAGALIGN(newlen+1));
 if (err)
  return err;

 memcpy(namep, name, newlen+1);
 return 0;
}

int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
       int len, void **prop_data)
{
 struct fdt_property *prop;
 int err;

 FDT_RW_PROBE(fdt);

 err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
 if (err == -FDT_ERR_NOTFOUND)
  err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
 if (err)
  return err;

 *prop_data = prop->data;
 return 0;
}

int fdt_setprop(void *fdt, int nodeoffset, const char *name,
  const void *val, int len)
{
 void *prop_data;
 int err;

 err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
 if (err)
  return err;

 if (len)
  memcpy(prop_data, val, len);
 return 0;
}

int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
     const void *val, int len)
{
 struct fdt_property *prop;
 int err, oldlen, newlen;

 FDT_RW_PROBE(fdt);

 prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
 if (prop) {
  newlen = len + oldlen;
  err = fdt_splice_struct_(fdt, prop->data,
      FDT_TAGALIGN(oldlen),
      FDT_TAGALIGN(newlen));
  if (err)
   return err;
  prop->len = cpu_to_fdt32(newlen);
  memcpy(prop->data + oldlen, val, len);
 } else {
  err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
  if (err)
   return err;
  memcpy(prop->data, val, len);
 }
 return 0;
}

int fdt_delprop(void *fdt, int nodeoffset, const char *name)
{
 struct fdt_property *prop;
 int len, proplen;

 FDT_RW_PROBE(fdt);

 prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
 if (!prop)
  return len;

 proplen = sizeof(*prop) + FDT_TAGALIGN(len);
 return fdt_splice_struct_(fdt, prop, proplen, 0);
}

int fdt_add_subnode_namelen(void *fdt, int parentoffset,
       const char *name, int namelen)
{
 struct fdt_node_header *nh;
 int offset, nextoffset;
 int nodelen;
 int err;
 uint32_t tag;
 fdt32_t *endtag;

 FDT_RW_PROBE(fdt);

 offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
 if (offset >= 0)
  return -FDT_ERR_EXISTS;
 else if (offset != -FDT_ERR_NOTFOUND)
  return offset;

 /* Try to place the new node after the parent's properties */
 tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
 /* the fdt_subnode_offset_namelen() should ensure this never hits */
 if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE))
  return -FDT_ERR_INTERNAL;
 do {
  offset = nextoffset;
  tag = fdt_next_tag(fdt, offset, &nextoffset);
 } while ((tag == FDT_PROP) || (tag == FDT_NOP));

 nh = fdt_offset_ptr_w_(fdt, offset);
 nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;

 err = fdt_splice_struct_(fdt, nh, 0, nodelen);
 if (err)
  return err;

 nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
 memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
 memcpy(nh->name, name, namelen);
 endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
 *endtag = cpu_to_fdt32(FDT_END_NODE);

 return offset;
}

int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
{
 return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
}

int fdt_del_node(void *fdt, int nodeoffset)
{
 int endoffset;

 FDT_RW_PROBE(fdt);

 endoffset = fdt_node_end_offset_(fdt, nodeoffset);
 if (endoffset < 0)
  return endoffset;

 return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
      endoffset - nodeoffset, 0);
}

static void fdt_packblocks_(const char *old, char *new,
       int mem_rsv_size,
       int struct_size,
       int strings_size)
{
 int mem_rsv_off, struct_off, strings_off;

 mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
 struct_off = mem_rsv_off + mem_rsv_size;
 strings_off = struct_off + struct_size;

 memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
 fdt_set_off_mem_rsvmap(new, mem_rsv_off);

 memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
 fdt_set_off_dt_struct(new, struct_off);
 fdt_set_size_dt_struct(new, struct_size);

 memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size);
 fdt_set_off_dt_strings(new, strings_off);
 fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
}

int fdt_open_into(const void *fdt, void *buf, int bufsize)
{
 int err;
 int mem_rsv_size, struct_size;
 int newsize;
 const char *fdtstart = fdt;
 const char *fdtend = fdtstart + fdt_totalsize(fdt);
 char *tmp;

 FDT_RO_PROBE(fdt);

 mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
  * sizeof(struct fdt_reserve_entry);

 if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
  struct_size = fdt_size_dt_struct(fdt);
 } else if (fdt_version(fdt) == 16) {
  struct_size = 0;
  while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
   ;
  if (struct_size < 0)
   return struct_size;
 } else {
  return -FDT_ERR_BADVERSION;
 }

 if (can_assume(LIBFDT_ORDER) ||
     !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
  /* no further work necessary */
  err = fdt_move(fdt, buf, bufsize);
  if (err)
   return err;
  fdt_set_version(buf, 17);
  fdt_set_size_dt_struct(buf, struct_size);
  fdt_set_totalsize(buf, bufsize);
  return 0;
 }

 /* Need to reorder */
 newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
  + struct_size + fdt_size_dt_strings(fdt);

 if (bufsize < newsize)
  return -FDT_ERR_NOSPACE;

 /* First attempt to build converted tree at beginning of buffer */
 tmp = buf;
 /* But if that overlaps with the old tree... */
 if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
  /* Try right after the old tree instead */
  tmp = (char *)(uintptr_t)fdtend;
  if ((tmp + newsize) > ((char *)buf + bufsize))
   return -FDT_ERR_NOSPACE;
 }

 fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size,
   fdt_size_dt_strings(fdt));
 memmove(buf, tmp, newsize);

 fdt_set_magic(buf, FDT_MAGIC);
 fdt_set_totalsize(buf, bufsize);
 fdt_set_version(buf, 17);
 fdt_set_last_comp_version(buf, 16);
 fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));

 return 0;
}

int fdt_pack(void *fdt)
{
 int mem_rsv_size;

 FDT_RW_PROBE(fdt);

 mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
  * sizeof(struct fdt_reserve_entry);
 fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt),
   fdt_size_dt_strings(fdt));
 fdt_set_totalsize(fdt, fdt_data_size_(fdt));

 return 0;
}

Messung V0.5
C=98 H=99 G=98

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge