fdt_sw.c revision 9537:ad5b3252dcc6
16700Snate@binkert.org/* 26700Snate@binkert.org * libfdt - Flat Device Tree manipulation 36700Snate@binkert.org * Copyright (C) 2006 David Gibson, IBM Corporation. 46700Snate@binkert.org * 56700Snate@binkert.org * Redistribution and use in source and binary forms, with or 66700Snate@binkert.org * without modification, are permitted provided that the following 76700Snate@binkert.org * conditions are met: 86700Snate@binkert.org * 96700Snate@binkert.org * 1. Redistributions of source code must retain the above 106700Snate@binkert.org * copyright notice, this list of conditions and the following 116700Snate@binkert.org * disclaimer. 126700Snate@binkert.org * 2. Redistributions in binary form must reproduce the above 136700Snate@binkert.org * copyright notice, this list of conditions and the following 146700Snate@binkert.org * disclaimer in the documentation and/or other materials 156700Snate@binkert.org * provided with the distribution. 166700Snate@binkert.org * 176700Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 186700Snate@binkert.org * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 196700Snate@binkert.org * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 206700Snate@binkert.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 216700Snate@binkert.org * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 226700Snate@binkert.org * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 236700Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 246700Snate@binkert.org * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 256700Snate@binkert.org * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 266700Snate@binkert.org * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 276700Snate@binkert.org * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 286285Snate@binkert.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 296285Snate@binkert.org * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 306285Snate@binkert.org */ 316881SBrad.Beckmann@amd.com#include <fdt.h> 326285Snate@binkert.org#include <libfdt.h> 336876Ssteve.reinhardt@amd.com 346876Ssteve.reinhardt@amd.com#include "libfdt_env.h" 356285Snate@binkert.org#include "libfdt_internal.h" 366876Ssteve.reinhardt@amd.com 376876Ssteve.reinhardt@amd.comstatic int _fdt_sw_check_header(void *fdt) 386876Ssteve.reinhardt@amd.com{ 396876Ssteve.reinhardt@amd.com if (fdt_magic(fdt) != FDT_SW_MAGIC) 406876Ssteve.reinhardt@amd.com return -FDT_ERR_BADMAGIC; 416876Ssteve.reinhardt@amd.com /* FIXME: should check more details about the header state */ 426876Ssteve.reinhardt@amd.com return 0; 436876Ssteve.reinhardt@amd.com} 446881SBrad.Beckmann@amd.com 456881SBrad.Beckmann@amd.com#define FDT_SW_CHECK_HEADER(fdt) \ 467054Snate@binkert.org { \ 476881SBrad.Beckmann@amd.com int err; \ 486881SBrad.Beckmann@amd.com if ((err = _fdt_sw_check_header(fdt)) != 0) \ 496876Ssteve.reinhardt@amd.com return err; \ 506876Ssteve.reinhardt@amd.com } 516881SBrad.Beckmann@amd.com 526881SBrad.Beckmann@amd.comstatic void *_fdt_grab_space(void *fdt, size_t len) 536881SBrad.Beckmann@amd.com{ 546285Snate@binkert.org int offset = fdt_size_dt_struct(fdt); 556285Snate@binkert.org int spaceleft; 567054Snate@binkert.org 577054Snate@binkert.org spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) 586285Snate@binkert.org - fdt_size_dt_strings(fdt); 597054Snate@binkert.org 606285Snate@binkert.org if ((offset + len < offset) || (offset + len > spaceleft)) 616493STushar.Krishna@amd.com return NULL; 627054Snate@binkert.org 637054Snate@binkert.org fdt_set_size_dt_struct(fdt, offset + len); 646493STushar.Krishna@amd.com return _fdt_offset_ptr_w(fdt, offset); 657054Snate@binkert.org} 667054Snate@binkert.org 677054Snate@binkert.orgint fdt_create(void *buf, int bufsize) 687054Snate@binkert.org{ 697054Snate@binkert.org void *fdt = buf; 707054Snate@binkert.org 717054Snate@binkert.org if (bufsize < sizeof(struct fdt_header)) 727054Snate@binkert.org return -FDT_ERR_NOSPACE; 737054Snate@binkert.org 747548SBrad.Beckmann@amd.com memset(buf, 0, bufsize); 757054Snate@binkert.org 767054Snate@binkert.org fdt_set_magic(fdt, FDT_SW_MAGIC); 777054Snate@binkert.org fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 787054Snate@binkert.org fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); 797054Snate@binkert.org fdt_set_totalsize(fdt, bufsize); 807054Snate@binkert.org 817054Snate@binkert.org fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), 827054Snate@binkert.org sizeof(struct fdt_reserve_entry))); 837054Snate@binkert.org fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 847054Snate@binkert.org fdt_set_off_dt_strings(fdt, bufsize); 857054Snate@binkert.org 867054Snate@binkert.org return 0; 877054Snate@binkert.org} 887054Snate@binkert.org 897054Snate@binkert.orgint fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) 907054Snate@binkert.org{ 917054Snate@binkert.org struct fdt_reserve_entry *re; 926493STushar.Krishna@amd.com int offset; 937054Snate@binkert.org 947454Snate@binkert.org FDT_SW_CHECK_HEADER(fdt); 957054Snate@binkert.org 967054Snate@binkert.org if (fdt_size_dt_struct(fdt)) 977054Snate@binkert.org return -FDT_ERR_BADSTATE; 987054Snate@binkert.org 99 offset = fdt_off_dt_struct(fdt); 100 if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) 101 return -FDT_ERR_NOSPACE; 102 103 re = (struct fdt_reserve_entry *)((char *)fdt + offset); 104 re->address = cpu_to_fdt64(addr); 105 re->size = cpu_to_fdt64(size); 106 107 fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); 108 109 return 0; 110} 111 112int fdt_finish_reservemap(void *fdt) 113{ 114 return fdt_add_reservemap_entry(fdt, 0, 0); 115} 116 117int fdt_begin_node(void *fdt, const char *name) 118{ 119 struct fdt_node_header *nh; 120 int namelen = strlen(name) + 1; 121 122 FDT_SW_CHECK_HEADER(fdt); 123 124 nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); 125 if (! nh) 126 return -FDT_ERR_NOSPACE; 127 128 nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 129 memcpy(nh->name, name, namelen); 130 return 0; 131} 132 133int fdt_end_node(void *fdt) 134{ 135 fdt32_t *en; 136 137 FDT_SW_CHECK_HEADER(fdt); 138 139 en = _fdt_grab_space(fdt, FDT_TAGSIZE); 140 if (! en) 141 return -FDT_ERR_NOSPACE; 142 143 *en = cpu_to_fdt32(FDT_END_NODE); 144 return 0; 145} 146 147static int _fdt_find_add_string(void *fdt, const char *s) 148{ 149 char *strtab = (char *)fdt + fdt_totalsize(fdt); 150 const char *p; 151 int strtabsize = fdt_size_dt_strings(fdt); 152 int len = strlen(s) + 1; 153 int struct_top, offset; 154 155 p = _fdt_find_string(strtab - strtabsize, strtabsize, s); 156 if (p) 157 return p - strtab; 158 159 /* Add it */ 160 offset = -strtabsize - len; 161 struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 162 if (fdt_totalsize(fdt) + offset < struct_top) 163 return 0; /* no more room :( */ 164 165 memcpy(strtab + offset, s, len); 166 fdt_set_size_dt_strings(fdt, strtabsize + len); 167 return offset; 168} 169 170int fdt_property(void *fdt, const char *name, const void *val, int len) 171{ 172 struct fdt_property *prop; 173 int nameoff; 174 175 FDT_SW_CHECK_HEADER(fdt); 176 177 nameoff = _fdt_find_add_string(fdt, name); 178 if (nameoff == 0) 179 return -FDT_ERR_NOSPACE; 180 181 prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 182 if (! prop) 183 return -FDT_ERR_NOSPACE; 184 185 prop->tag = cpu_to_fdt32(FDT_PROP); 186 prop->nameoff = cpu_to_fdt32(nameoff); 187 prop->len = cpu_to_fdt32(len); 188 memcpy(prop->data, val, len); 189 return 0; 190} 191 192int fdt_finish(void *fdt) 193{ 194 char *p = (char *)fdt; 195 fdt32_t *end; 196 int oldstroffset, newstroffset; 197 uint32_t tag; 198 int offset, nextoffset; 199 200 FDT_SW_CHECK_HEADER(fdt); 201 202 /* Add terminator */ 203 end = _fdt_grab_space(fdt, sizeof(*end)); 204 if (! end) 205 return -FDT_ERR_NOSPACE; 206 *end = cpu_to_fdt32(FDT_END); 207 208 /* Relocate the string table */ 209 oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); 210 newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 211 memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); 212 fdt_set_off_dt_strings(fdt, newstroffset); 213 214 /* Walk the structure, correcting string offsets */ 215 offset = 0; 216 while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { 217 if (tag == FDT_PROP) { 218 struct fdt_property *prop = 219 _fdt_offset_ptr_w(fdt, offset); 220 int nameoff; 221 222 nameoff = fdt32_to_cpu(prop->nameoff); 223 nameoff += fdt_size_dt_strings(fdt); 224 prop->nameoff = cpu_to_fdt32(nameoff); 225 } 226 offset = nextoffset; 227 } 228 if (nextoffset < 0) 229 return nextoffset; 230 231 /* Finally, adjust the header */ 232 fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 233 fdt_set_magic(fdt, FDT_MAGIC); 234 return 0; 235} 236