The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/libfdt/fdt_sw.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * libfdt - Flat Device Tree manipulation
    3  * Copyright (C) 2006 David Gibson, IBM Corporation.
    4  *
    5  * libfdt is dual licensed: you can use it either under the terms of
    6  * the GPL, or the BSD license, at your option.
    7  *
    8  *  a) This library is free software; you can redistribute it and/or
    9  *     modify it under the terms of the GNU General Public License as
   10  *     published by the Free Software Foundation; either version 2 of the
   11  *     License, or (at your option) any later version.
   12  *
   13  *     This library is distributed in the hope that it will be useful,
   14  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  *     GNU General Public License for more details.
   17  *
   18  *     You should have received a copy of the GNU General Public
   19  *     License along with this library; if not, write to the Free
   20  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
   21  *     MA 02110-1301 USA
   22  *
   23  * Alternatively,
   24  *
   25  *  b) Redistribution and use in source and binary forms, with or
   26  *     without modification, are permitted provided that the following
   27  *     conditions are met:
   28  *
   29  *     1. Redistributions of source code must retain the above
   30  *        copyright notice, this list of conditions and the following
   31  *        disclaimer.
   32  *     2. Redistributions in binary form must reproduce the above
   33  *        copyright notice, this list of conditions and the following
   34  *        disclaimer in the documentation and/or other materials
   35  *        provided with the distribution.
   36  *
   37  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
   38  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
   39  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   40  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   41  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   42  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   43  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   44  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   45  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   46  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   47  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   48  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   49  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   50  */
   51 #include "libfdt_env.h"
   52 
   53 #include <fdt.h>
   54 #include <libfdt.h>
   55 
   56 #include "libfdt_internal.h"
   57 
   58 static int fdt_sw_check_header_(void *fdt)
   59 {
   60         if (fdt_magic(fdt) != FDT_SW_MAGIC)
   61                 return -FDT_ERR_BADMAGIC;
   62         /* FIXME: should check more details about the header state */
   63         return 0;
   64 }
   65 
   66 #define FDT_SW_CHECK_HEADER(fdt) \
   67         { \
   68                 int err; \
   69                 if ((err = fdt_sw_check_header_(fdt)) != 0) \
   70                         return err; \
   71         }
   72 
   73 static void *fdt_grab_space_(void *fdt, size_t len)
   74 {
   75         int offset = fdt_size_dt_struct(fdt);
   76         int spaceleft;
   77 
   78         spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
   79                 - fdt_size_dt_strings(fdt);
   80 
   81         if ((offset + len < offset) || (offset + len > spaceleft))
   82                 return NULL;
   83 
   84         fdt_set_size_dt_struct(fdt, offset + len);
   85         return fdt_offset_ptr_w_(fdt, offset);
   86 }
   87 
   88 int fdt_create(void *buf, int bufsize)
   89 {
   90         void *fdt = buf;
   91 
   92         if (bufsize < sizeof(struct fdt_header))
   93                 return -FDT_ERR_NOSPACE;
   94 
   95         memset(buf, 0, bufsize);
   96 
   97         fdt_set_magic(fdt, FDT_SW_MAGIC);
   98         fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
   99         fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
  100         fdt_set_totalsize(fdt,  bufsize);
  101 
  102         fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
  103                                               sizeof(struct fdt_reserve_entry)));
  104         fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
  105         fdt_set_off_dt_strings(fdt, bufsize);
  106 
  107         return 0;
  108 }
  109 
  110 int fdt_resize(void *fdt, void *buf, int bufsize)
  111 {
  112         size_t headsize, tailsize;
  113         char *oldtail, *newtail;
  114 
  115         FDT_SW_CHECK_HEADER(fdt);
  116 
  117         headsize = fdt_off_dt_struct(fdt);
  118         tailsize = fdt_size_dt_strings(fdt);
  119 
  120         if ((headsize + tailsize) > bufsize)
  121                 return -FDT_ERR_NOSPACE;
  122 
  123         oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
  124         newtail = (char *)buf + bufsize - tailsize;
  125 
  126         /* Two cases to avoid clobbering data if the old and new
  127          * buffers partially overlap */
  128         if (buf <= fdt) {
  129                 memmove(buf, fdt, headsize);
  130                 memmove(newtail, oldtail, tailsize);
  131         } else {
  132                 memmove(newtail, oldtail, tailsize);
  133                 memmove(buf, fdt, headsize);
  134         }
  135 
  136         fdt_set_off_dt_strings(buf, bufsize);
  137         fdt_set_totalsize(buf, bufsize);
  138 
  139         return 0;
  140 }
  141 
  142 int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
  143 {
  144         struct fdt_reserve_entry *re;
  145         int offset;
  146 
  147         FDT_SW_CHECK_HEADER(fdt);
  148 
  149         if (fdt_size_dt_struct(fdt))
  150                 return -FDT_ERR_BADSTATE;
  151 
  152         offset = fdt_off_dt_struct(fdt);
  153         if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
  154                 return -FDT_ERR_NOSPACE;
  155 
  156         re = (struct fdt_reserve_entry *)((char *)fdt + offset);
  157         re->address = cpu_to_fdt64(addr);
  158         re->size = cpu_to_fdt64(size);
  159 
  160         fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
  161 
  162         return 0;
  163 }
  164 
  165 int fdt_finish_reservemap(void *fdt)
  166 {
  167         return fdt_add_reservemap_entry(fdt, 0, 0);
  168 }
  169 
  170 int fdt_begin_node(void *fdt, const char *name)
  171 {
  172         struct fdt_node_header *nh;
  173         int namelen = strlen(name) + 1;
  174 
  175         FDT_SW_CHECK_HEADER(fdt);
  176 
  177         nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
  178         if (! nh)
  179                 return -FDT_ERR_NOSPACE;
  180 
  181         nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
  182         memcpy(nh->name, name, namelen);
  183         return 0;
  184 }
  185 
  186 int fdt_end_node(void *fdt)
  187 {
  188         fdt32_t *en;
  189 
  190         FDT_SW_CHECK_HEADER(fdt);
  191 
  192         en = fdt_grab_space_(fdt, FDT_TAGSIZE);
  193         if (! en)
  194                 return -FDT_ERR_NOSPACE;
  195 
  196         *en = cpu_to_fdt32(FDT_END_NODE);
  197         return 0;
  198 }
  199 
  200 static int fdt_find_add_string_(void *fdt, const char *s)
  201 {
  202         char *strtab = (char *)fdt + fdt_totalsize(fdt);
  203         const char *p;
  204         int strtabsize = fdt_size_dt_strings(fdt);
  205         int len = strlen(s) + 1;
  206         int struct_top, offset;
  207 
  208         p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
  209         if (p)
  210                 return p - strtab;
  211 
  212         /* Add it */
  213         offset = -strtabsize - len;
  214         struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
  215         if (fdt_totalsize(fdt) + offset < struct_top)
  216                 return 0; /* no more room :( */
  217 
  218         memcpy(strtab + offset, s, len);
  219         fdt_set_size_dt_strings(fdt, strtabsize + len);
  220         return offset;
  221 }
  222 
  223 int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
  224 {
  225         struct fdt_property *prop;
  226         int nameoff;
  227 
  228         FDT_SW_CHECK_HEADER(fdt);
  229 
  230         nameoff = fdt_find_add_string_(fdt, name);
  231         if (nameoff == 0)
  232                 return -FDT_ERR_NOSPACE;
  233 
  234         prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
  235         if (! prop)
  236                 return -FDT_ERR_NOSPACE;
  237 
  238         prop->tag = cpu_to_fdt32(FDT_PROP);
  239         prop->nameoff = cpu_to_fdt32(nameoff);
  240         prop->len = cpu_to_fdt32(len);
  241         *valp = prop->data;
  242         return 0;
  243 }
  244 
  245 int fdt_property(void *fdt, const char *name, const void *val, int len)
  246 {
  247         void *ptr;
  248         int ret;
  249 
  250         ret = fdt_property_placeholder(fdt, name, len, &ptr);
  251         if (ret)
  252                 return ret;
  253         memcpy(ptr, val, len);
  254         return 0;
  255 }
  256 
  257 int fdt_finish(void *fdt)
  258 {
  259         char *p = (char *)fdt;
  260         fdt32_t *end;
  261         int oldstroffset, newstroffset;
  262         uint32_t tag;
  263         int offset, nextoffset;
  264 
  265         FDT_SW_CHECK_HEADER(fdt);
  266 
  267         /* Add terminator */
  268         end = fdt_grab_space_(fdt, sizeof(*end));
  269         if (! end)
  270                 return -FDT_ERR_NOSPACE;
  271         *end = cpu_to_fdt32(FDT_END);
  272 
  273         /* Relocate the string table */
  274         oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
  275         newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
  276         memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
  277         fdt_set_off_dt_strings(fdt, newstroffset);
  278 
  279         /* Walk the structure, correcting string offsets */
  280         offset = 0;
  281         while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
  282                 if (tag == FDT_PROP) {
  283                         struct fdt_property *prop =
  284                                 fdt_offset_ptr_w_(fdt, offset);
  285                         int nameoff;
  286 
  287                         nameoff = fdt32_to_cpu(prop->nameoff);
  288                         nameoff += fdt_size_dt_strings(fdt);
  289                         prop->nameoff = cpu_to_fdt32(nameoff);
  290                 }
  291                 offset = nextoffset;
  292         }
  293         if (nextoffset < 0)
  294                 return nextoffset;
  295 
  296         /* Finally, adjust the header */
  297         fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
  298         fdt_set_magic(fdt, FDT_MAGIC);
  299         return 0;
  300 }

Cache object: 3d7a6eae89053323503fc984b202ae7e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.