]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/FdtLib/fdt_sw.c
EmbeddedPkg/FdtLib: Update FdtLib to v1.4.5
[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
a0992390
PB
110int fdt_resize(void *fdt, void *buf, int bufsize)\r
111{\r
112 size_t headsize, tailsize;\r
113 char *oldtail, *newtail;\r
114\r
115 FDT_SW_CHECK_HEADER(fdt);\r
116\r
117 headsize = fdt_off_dt_struct(fdt);\r
118 tailsize = fdt_size_dt_strings(fdt);\r
119\r
120 if ((headsize + tailsize) > bufsize)\r
121 return -FDT_ERR_NOSPACE;\r
122\r
123 oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;\r
124 newtail = (char *)buf + bufsize - tailsize;\r
125\r
126 /* Two cases to avoid clobbering data if the old and new\r
127 * buffers partially overlap */\r
128 if (buf <= fdt) {\r
129 memmove(buf, fdt, headsize);\r
130 memmove(newtail, oldtail, tailsize);\r
131 } else {\r
132 memmove(newtail, oldtail, tailsize);\r
133 memmove(buf, fdt, headsize);\r
134 }\r
135\r
136 fdt_set_off_dt_strings(buf, bufsize);\r
137 fdt_set_totalsize(buf, bufsize);\r
138\r
139 return 0;\r
140}\r
141\r
1e57a462 142int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)\r
143{\r
144 struct fdt_reserve_entry *re;\r
145 int offset;\r
146\r
147 FDT_SW_CHECK_HEADER(fdt);\r
148\r
149 if (fdt_size_dt_struct(fdt))\r
150 return -FDT_ERR_BADSTATE;\r
151\r
152 offset = fdt_off_dt_struct(fdt);\r
153 if ((offset + sizeof(*re)) > fdt_totalsize(fdt))\r
154 return -FDT_ERR_NOSPACE;\r
155\r
156 re = (struct fdt_reserve_entry *)((char *)fdt + offset);\r
157 re->address = cpu_to_fdt64(addr);\r
158 re->size = cpu_to_fdt64(size);\r
159\r
160 fdt_set_off_dt_struct(fdt, offset + sizeof(*re));\r
161\r
162 return 0;\r
163}\r
164\r
165int fdt_finish_reservemap(void *fdt)\r
166{\r
167 return fdt_add_reservemap_entry(fdt, 0, 0);\r
168}\r
169\r
170int fdt_begin_node(void *fdt, const char *name)\r
171{\r
172 struct fdt_node_header *nh;\r
173 int namelen = strlen(name) + 1;\r
174\r
175 FDT_SW_CHECK_HEADER(fdt);\r
176\r
177 nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));\r
178 if (! nh)\r
179 return -FDT_ERR_NOSPACE;\r
180\r
181 nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);\r
182 memcpy(nh->name, name, namelen);\r
183 return 0;\r
184}\r
185\r
186int fdt_end_node(void *fdt)\r
187{\r
3e8576dd 188 fdt32_t *en;\r
1e57a462 189\r
190 FDT_SW_CHECK_HEADER(fdt);\r
191\r
192 en = _fdt_grab_space(fdt, FDT_TAGSIZE);\r
193 if (! en)\r
194 return -FDT_ERR_NOSPACE;\r
195\r
196 *en = cpu_to_fdt32(FDT_END_NODE);\r
197 return 0;\r
198}\r
199\r
200static int _fdt_find_add_string(void *fdt, const char *s)\r
201{\r
202 char *strtab = (char *)fdt + fdt_totalsize(fdt);\r
203 const char *p;\r
204 int strtabsize = fdt_size_dt_strings(fdt);\r
205 int len = strlen(s) + 1;\r
206 int struct_top, offset;\r
207\r
208 p = _fdt_find_string(strtab - strtabsize, strtabsize, s);\r
209 if (p)\r
210 return p - strtab;\r
211\r
212 /* Add it */\r
213 offset = -strtabsize - len;\r
214 struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);\r
215 if (fdt_totalsize(fdt) + offset < struct_top)\r
216 return 0; /* no more room :( */\r
217\r
218 memcpy(strtab + offset, s, len);\r
219 fdt_set_size_dt_strings(fdt, strtabsize + len);\r
220 return offset;\r
221}\r
222\r
a0992390 223int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)\r
1e57a462 224{\r
225 struct fdt_property *prop;\r
226 int nameoff;\r
227\r
228 FDT_SW_CHECK_HEADER(fdt);\r
229\r
230 nameoff = _fdt_find_add_string(fdt, name);\r
231 if (nameoff == 0)\r
232 return -FDT_ERR_NOSPACE;\r
233\r
234 prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));\r
235 if (! prop)\r
236 return -FDT_ERR_NOSPACE;\r
237\r
238 prop->tag = cpu_to_fdt32(FDT_PROP);\r
239 prop->nameoff = cpu_to_fdt32(nameoff);\r
240 prop->len = cpu_to_fdt32(len);\r
a0992390
PB
241 *valp = prop->data;\r
242 return 0;\r
243}\r
244\r
245int fdt_property(void *fdt, const char *name, const void *val, int len)\r
246{\r
247 void *ptr;\r
248 int ret;\r
249\r
250 ret = fdt_property_placeholder(fdt, name, len, &ptr);\r
251 if (ret)\r
252 return ret;\r
253 memcpy(ptr, val, len);\r
1e57a462 254 return 0;\r
255}\r
256\r
257int fdt_finish(void *fdt)\r
258{\r
259 char *p = (char *)fdt;\r
3e8576dd 260 fdt32_t *end;\r
1e57a462 261 int oldstroffset, newstroffset;\r
262 uint32_t tag;\r
263 int offset, nextoffset;\r
264\r
265 FDT_SW_CHECK_HEADER(fdt);\r
266\r
267 /* Add terminator */\r
268 end = _fdt_grab_space(fdt, sizeof(*end));\r
269 if (! end)\r
270 return -FDT_ERR_NOSPACE;\r
271 *end = cpu_to_fdt32(FDT_END);\r
272\r
273 /* Relocate the string table */\r
274 oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);\r
275 newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);\r
276 memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));\r
277 fdt_set_off_dt_strings(fdt, newstroffset);\r
278\r
279 /* Walk the structure, correcting string offsets */\r
280 offset = 0;\r
281 while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {\r
282 if (tag == FDT_PROP) {\r
283 struct fdt_property *prop =\r
284 _fdt_offset_ptr_w(fdt, offset);\r
285 int nameoff;\r
286\r
287 nameoff = fdt32_to_cpu(prop->nameoff);\r
288 nameoff += fdt_size_dt_strings(fdt);\r
289 prop->nameoff = cpu_to_fdt32(nameoff);\r
290 }\r
291 offset = nextoffset;\r
292 }\r
293 if (nextoffset < 0)\r
294 return nextoffset;\r
295\r
296 /* Finally, adjust the header */\r
297 fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));\r
298 fdt_set_magic(fdt, FDT_MAGIC);\r
299 return 0;\r
300}\r