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