19537Satgutier@umich.edu/* 29537Satgutier@umich.edu * libfdt - Flat Device Tree manipulation 39537Satgutier@umich.edu * Copyright (C) 2006 David Gibson, IBM Corporation. 49537Satgutier@umich.edu * 59537Satgutier@umich.edu * Redistribution and use in source and binary forms, with or 69537Satgutier@umich.edu * without modification, are permitted provided that the following 79537Satgutier@umich.edu * conditions are met: 89537Satgutier@umich.edu * 99537Satgutier@umich.edu * 1. Redistributions of source code must retain the above 109537Satgutier@umich.edu * copyright notice, this list of conditions and the following 119537Satgutier@umich.edu * disclaimer. 129537Satgutier@umich.edu * 2. Redistributions in binary form must reproduce the above 139537Satgutier@umich.edu * copyright notice, this list of conditions and the following 149537Satgutier@umich.edu * disclaimer in the documentation and/or other materials 159537Satgutier@umich.edu * provided with the distribution. 169537Satgutier@umich.edu * 179537Satgutier@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 189537Satgutier@umich.edu * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 199537Satgutier@umich.edu * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 209537Satgutier@umich.edu * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 219537Satgutier@umich.edu * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 229537Satgutier@umich.edu * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 239537Satgutier@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 249537Satgutier@umich.edu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 259537Satgutier@umich.edu * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 269537Satgutier@umich.edu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 279537Satgutier@umich.edu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 289537Satgutier@umich.edu * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 299537Satgutier@umich.edu * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 309537Satgutier@umich.edu */ 319537Satgutier@umich.edu#include <fdt.h> 329537Satgutier@umich.edu#include <libfdt.h> 339537Satgutier@umich.edu 349537Satgutier@umich.edu#include "libfdt_env.h" 359537Satgutier@umich.edu#include "libfdt_internal.h" 369537Satgutier@umich.edu 379537Satgutier@umich.edustatic int _fdt_sw_check_header(void *fdt) 389537Satgutier@umich.edu{ 399537Satgutier@umich.edu if (fdt_magic(fdt) != FDT_SW_MAGIC) 409537Satgutier@umich.edu return -FDT_ERR_BADMAGIC; 419537Satgutier@umich.edu /* FIXME: should check more details about the header state */ 429537Satgutier@umich.edu return 0; 439537Satgutier@umich.edu} 449537Satgutier@umich.edu 459537Satgutier@umich.edu#define FDT_SW_CHECK_HEADER(fdt) \ 469537Satgutier@umich.edu { \ 479537Satgutier@umich.edu int err; \ 489537Satgutier@umich.edu if ((err = _fdt_sw_check_header(fdt)) != 0) \ 499537Satgutier@umich.edu return err; \ 509537Satgutier@umich.edu } 519537Satgutier@umich.edu 529537Satgutier@umich.edustatic void *_fdt_grab_space(void *fdt, size_t len) 539537Satgutier@umich.edu{ 549537Satgutier@umich.edu int offset = fdt_size_dt_struct(fdt); 559537Satgutier@umich.edu int spaceleft; 569537Satgutier@umich.edu 579537Satgutier@umich.edu spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) 589537Satgutier@umich.edu - fdt_size_dt_strings(fdt); 599537Satgutier@umich.edu 609537Satgutier@umich.edu if ((offset + len < offset) || (offset + len > spaceleft)) 619537Satgutier@umich.edu return NULL; 629537Satgutier@umich.edu 639537Satgutier@umich.edu fdt_set_size_dt_struct(fdt, offset + len); 649537Satgutier@umich.edu return _fdt_offset_ptr_w(fdt, offset); 659537Satgutier@umich.edu} 669537Satgutier@umich.edu 679537Satgutier@umich.eduint fdt_create(void *buf, int bufsize) 689537Satgutier@umich.edu{ 699537Satgutier@umich.edu void *fdt = buf; 709537Satgutier@umich.edu 719537Satgutier@umich.edu if (bufsize < sizeof(struct fdt_header)) 729537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 739537Satgutier@umich.edu 749537Satgutier@umich.edu memset(buf, 0, bufsize); 759537Satgutier@umich.edu 769537Satgutier@umich.edu fdt_set_magic(fdt, FDT_SW_MAGIC); 779537Satgutier@umich.edu fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 789537Satgutier@umich.edu fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); 799537Satgutier@umich.edu fdt_set_totalsize(fdt, bufsize); 809537Satgutier@umich.edu 819537Satgutier@umich.edu fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), 829537Satgutier@umich.edu sizeof(struct fdt_reserve_entry))); 839537Satgutier@umich.edu fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 849537Satgutier@umich.edu fdt_set_off_dt_strings(fdt, bufsize); 859537Satgutier@umich.edu 869537Satgutier@umich.edu return 0; 879537Satgutier@umich.edu} 889537Satgutier@umich.edu 899537Satgutier@umich.eduint fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) 909537Satgutier@umich.edu{ 919537Satgutier@umich.edu struct fdt_reserve_entry *re; 929537Satgutier@umich.edu int offset; 939537Satgutier@umich.edu 949537Satgutier@umich.edu FDT_SW_CHECK_HEADER(fdt); 959537Satgutier@umich.edu 969537Satgutier@umich.edu if (fdt_size_dt_struct(fdt)) 979537Satgutier@umich.edu return -FDT_ERR_BADSTATE; 989537Satgutier@umich.edu 999537Satgutier@umich.edu offset = fdt_off_dt_struct(fdt); 1009537Satgutier@umich.edu if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) 1019537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 1029537Satgutier@umich.edu 1039537Satgutier@umich.edu re = (struct fdt_reserve_entry *)((char *)fdt + offset); 1049537Satgutier@umich.edu re->address = cpu_to_fdt64(addr); 1059537Satgutier@umich.edu re->size = cpu_to_fdt64(size); 1069537Satgutier@umich.edu 1079537Satgutier@umich.edu fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); 1089537Satgutier@umich.edu 1099537Satgutier@umich.edu return 0; 1109537Satgutier@umich.edu} 1119537Satgutier@umich.edu 1129537Satgutier@umich.eduint fdt_finish_reservemap(void *fdt) 1139537Satgutier@umich.edu{ 1149537Satgutier@umich.edu return fdt_add_reservemap_entry(fdt, 0, 0); 1159537Satgutier@umich.edu} 1169537Satgutier@umich.edu 1179537Satgutier@umich.eduint fdt_begin_node(void *fdt, const char *name) 1189537Satgutier@umich.edu{ 1199537Satgutier@umich.edu struct fdt_node_header *nh; 1209537Satgutier@umich.edu int namelen = strlen(name) + 1; 1219537Satgutier@umich.edu 1229537Satgutier@umich.edu FDT_SW_CHECK_HEADER(fdt); 1239537Satgutier@umich.edu 1249537Satgutier@umich.edu nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); 1259537Satgutier@umich.edu if (! nh) 1269537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 1279537Satgutier@umich.edu 1289537Satgutier@umich.edu nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 1299537Satgutier@umich.edu memcpy(nh->name, name, namelen); 1309537Satgutier@umich.edu return 0; 1319537Satgutier@umich.edu} 1329537Satgutier@umich.edu 1339537Satgutier@umich.eduint fdt_end_node(void *fdt) 1349537Satgutier@umich.edu{ 1359537Satgutier@umich.edu fdt32_t *en; 1369537Satgutier@umich.edu 1379537Satgutier@umich.edu FDT_SW_CHECK_HEADER(fdt); 1389537Satgutier@umich.edu 1399537Satgutier@umich.edu en = _fdt_grab_space(fdt, FDT_TAGSIZE); 1409537Satgutier@umich.edu if (! en) 1419537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 1429537Satgutier@umich.edu 1439537Satgutier@umich.edu *en = cpu_to_fdt32(FDT_END_NODE); 1449537Satgutier@umich.edu return 0; 1459537Satgutier@umich.edu} 1469537Satgutier@umich.edu 1479537Satgutier@umich.edustatic int _fdt_find_add_string(void *fdt, const char *s) 1489537Satgutier@umich.edu{ 1499537Satgutier@umich.edu char *strtab = (char *)fdt + fdt_totalsize(fdt); 1509537Satgutier@umich.edu const char *p; 1519537Satgutier@umich.edu int strtabsize = fdt_size_dt_strings(fdt); 1529537Satgutier@umich.edu int len = strlen(s) + 1; 1539537Satgutier@umich.edu int struct_top, offset; 1549537Satgutier@umich.edu 1559537Satgutier@umich.edu p = _fdt_find_string(strtab - strtabsize, strtabsize, s); 1569537Satgutier@umich.edu if (p) 1579537Satgutier@umich.edu return p - strtab; 1589537Satgutier@umich.edu 1599537Satgutier@umich.edu /* Add it */ 1609537Satgutier@umich.edu offset = -strtabsize - len; 1619537Satgutier@umich.edu struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 1629537Satgutier@umich.edu if (fdt_totalsize(fdt) + offset < struct_top) 1639537Satgutier@umich.edu return 0; /* no more room :( */ 1649537Satgutier@umich.edu 1659537Satgutier@umich.edu memcpy(strtab + offset, s, len); 1669537Satgutier@umich.edu fdt_set_size_dt_strings(fdt, strtabsize + len); 1679537Satgutier@umich.edu return offset; 1689537Satgutier@umich.edu} 1699537Satgutier@umich.edu 1709537Satgutier@umich.eduint fdt_property(void *fdt, const char *name, const void *val, int len) 1719537Satgutier@umich.edu{ 1729537Satgutier@umich.edu struct fdt_property *prop; 1739537Satgutier@umich.edu int nameoff; 1749537Satgutier@umich.edu 1759537Satgutier@umich.edu FDT_SW_CHECK_HEADER(fdt); 1769537Satgutier@umich.edu 1779537Satgutier@umich.edu nameoff = _fdt_find_add_string(fdt, name); 1789537Satgutier@umich.edu if (nameoff == 0) 1799537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 1809537Satgutier@umich.edu 1819537Satgutier@umich.edu prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 1829537Satgutier@umich.edu if (! prop) 1839537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 1849537Satgutier@umich.edu 1859537Satgutier@umich.edu prop->tag = cpu_to_fdt32(FDT_PROP); 1869537Satgutier@umich.edu prop->nameoff = cpu_to_fdt32(nameoff); 1879537Satgutier@umich.edu prop->len = cpu_to_fdt32(len); 1889537Satgutier@umich.edu memcpy(prop->data, val, len); 1899537Satgutier@umich.edu return 0; 1909537Satgutier@umich.edu} 1919537Satgutier@umich.edu 1929537Satgutier@umich.eduint fdt_finish(void *fdt) 1939537Satgutier@umich.edu{ 1949537Satgutier@umich.edu char *p = (char *)fdt; 1959537Satgutier@umich.edu fdt32_t *end; 1969537Satgutier@umich.edu int oldstroffset, newstroffset; 1979537Satgutier@umich.edu uint32_t tag; 1989537Satgutier@umich.edu int offset, nextoffset; 1999537Satgutier@umich.edu 2009537Satgutier@umich.edu FDT_SW_CHECK_HEADER(fdt); 2019537Satgutier@umich.edu 2029537Satgutier@umich.edu /* Add terminator */ 2039537Satgutier@umich.edu end = _fdt_grab_space(fdt, sizeof(*end)); 2049537Satgutier@umich.edu if (! end) 2059537Satgutier@umich.edu return -FDT_ERR_NOSPACE; 2069537Satgutier@umich.edu *end = cpu_to_fdt32(FDT_END); 2079537Satgutier@umich.edu 2089537Satgutier@umich.edu /* Relocate the string table */ 2099537Satgutier@umich.edu oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); 2109537Satgutier@umich.edu newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 2119537Satgutier@umich.edu memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); 2129537Satgutier@umich.edu fdt_set_off_dt_strings(fdt, newstroffset); 2139537Satgutier@umich.edu 2149537Satgutier@umich.edu /* Walk the structure, correcting string offsets */ 2159537Satgutier@umich.edu offset = 0; 2169537Satgutier@umich.edu while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { 2179537Satgutier@umich.edu if (tag == FDT_PROP) { 2189537Satgutier@umich.edu struct fdt_property *prop = 2199537Satgutier@umich.edu _fdt_offset_ptr_w(fdt, offset); 2209537Satgutier@umich.edu int nameoff; 2219537Satgutier@umich.edu 2229537Satgutier@umich.edu nameoff = fdt32_to_cpu(prop->nameoff); 2239537Satgutier@umich.edu nameoff += fdt_size_dt_strings(fdt); 2249537Satgutier@umich.edu prop->nameoff = cpu_to_fdt32(nameoff); 2259537Satgutier@umich.edu } 2269537Satgutier@umich.edu offset = nextoffset; 2279537Satgutier@umich.edu } 2289537Satgutier@umich.edu if (nextoffset < 0) 2299537Satgutier@umich.edu return nextoffset; 2309537Satgutier@umich.edu 2319537Satgutier@umich.edu /* Finally, adjust the header */ 2329537Satgutier@umich.edu fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 2339537Satgutier@umich.edu fdt_set_magic(fdt, FDT_MAGIC); 2349537Satgutier@umich.edu return 0; 2359537Satgutier@umich.edu} 236