]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/FdtLib/fdt_sw.c
EmbeddedPkg: Apply uncrustify changes
[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
e7108d0e
MK
58static int\r
59_fdt_sw_check_header (\r
60 void *fdt\r
61 )\r
1e57a462 62{\r
e7108d0e
MK
63 if (fdt_magic (fdt) != FDT_SW_MAGIC) {\r
64 return -FDT_ERR_BADMAGIC;\r
65 }\r
66\r
67 /* FIXME: should check more details about the header state */\r
68 return 0;\r
1e57a462 69}\r
70\r
71#define FDT_SW_CHECK_HEADER(fdt) \\r
e7108d0e
MK
72 { \\r
73 int err; \\r
74 if ((err = _fdt_sw_check_header(fdt)) != 0) \\r
75 return err; \\r
76 }\r
77\r
78static void *\r
79_fdt_grab_space (\r
80 void *fdt,\r
81 size_t len\r
82 )\r
1e57a462 83{\r
e7108d0e
MK
84 int offset = fdt_size_dt_struct (fdt);\r
85 int spaceleft;\r
1e57a462 86\r
e7108d0e
MK
87 spaceleft = fdt_totalsize (fdt) - fdt_off_dt_struct (fdt)\r
88 - fdt_size_dt_strings (fdt);\r
1e57a462 89\r
e7108d0e
MK
90 if ((offset + len < offset) || (offset + len > spaceleft)) {\r
91 return NULL;\r
92 }\r
1e57a462 93\r
e7108d0e
MK
94 fdt_set_size_dt_struct (fdt, offset + len);\r
95 return _fdt_offset_ptr_w (fdt, offset);\r
1e57a462 96}\r
97\r
e7108d0e
MK
98int\r
99fdt_create (\r
100 void *buf,\r
101 int bufsize\r
102 )\r
1e57a462 103{\r
e7108d0e
MK
104 void *fdt = buf;\r
105\r
106 if (bufsize < sizeof (struct fdt_header)) {\r
107 return -FDT_ERR_NOSPACE;\r
108 }\r
109\r
110 memset (buf, 0, bufsize);\r
111\r
112 fdt_set_magic (fdt, FDT_SW_MAGIC);\r
113 fdt_set_version (fdt, FDT_LAST_SUPPORTED_VERSION);\r
114 fdt_set_last_comp_version (fdt, FDT_FIRST_SUPPORTED_VERSION);\r
115 fdt_set_totalsize (fdt, bufsize);\r
116\r
117 fdt_set_off_mem_rsvmap (\r
118 fdt,\r
119 FDT_ALIGN (\r
120 sizeof (struct fdt_header),\r
121 sizeof (struct fdt_reserve_entry)\r
122 )\r
123 );\r
124 fdt_set_off_dt_struct (fdt, fdt_off_mem_rsvmap (fdt));\r
125 fdt_set_off_dt_strings (fdt, bufsize);\r
126\r
127 return 0;\r
1e57a462 128}\r
129\r
e7108d0e
MK
130int\r
131fdt_resize (\r
132 void *fdt,\r
133 void *buf,\r
134 int bufsize\r
135 )\r
a0992390 136{\r
e7108d0e
MK
137 size_t headsize, tailsize;\r
138 char *oldtail, *newtail;\r
a0992390 139\r
e7108d0e 140 FDT_SW_CHECK_HEADER (fdt);\r
a0992390 141\r
e7108d0e
MK
142 headsize = fdt_off_dt_struct (fdt);\r
143 tailsize = fdt_size_dt_strings (fdt);\r
a0992390 144\r
e7108d0e
MK
145 if ((headsize + tailsize) > bufsize) {\r
146 return -FDT_ERR_NOSPACE;\r
147 }\r
a0992390 148\r
e7108d0e
MK
149 oldtail = (char *)fdt + fdt_totalsize (fdt) - tailsize;\r
150 newtail = (char *)buf + bufsize - tailsize;\r
a0992390 151\r
e7108d0e
MK
152 /* Two cases to avoid clobbering data if the old and new\r
153 * buffers partially overlap */\r
154 if (buf <= fdt) {\r
155 memmove (buf, fdt, headsize);\r
156 memmove (newtail, oldtail, tailsize);\r
157 } else {\r
158 memmove (newtail, oldtail, tailsize);\r
159 memmove (buf, fdt, headsize);\r
160 }\r
a0992390 161\r
e7108d0e
MK
162 fdt_set_off_dt_strings (buf, bufsize);\r
163 fdt_set_totalsize (buf, bufsize);\r
a0992390 164\r
e7108d0e 165 return 0;\r
a0992390
PB
166}\r
167\r
e7108d0e
MK
168int\r
169fdt_add_reservemap_entry (\r
170 void *fdt,\r
171 uint64_t addr,\r
172 uint64_t size\r
173 )\r
1e57a462 174{\r
e7108d0e
MK
175 struct fdt_reserve_entry *re;\r
176 int offset;\r
1e57a462 177\r
e7108d0e 178 FDT_SW_CHECK_HEADER (fdt);\r
1e57a462 179\r
e7108d0e
MK
180 if (fdt_size_dt_struct (fdt)) {\r
181 return -FDT_ERR_BADSTATE;\r
182 }\r
1e57a462 183\r
e7108d0e
MK
184 offset = fdt_off_dt_struct (fdt);\r
185 if ((offset + sizeof (*re)) > fdt_totalsize (fdt)) {\r
186 return -FDT_ERR_NOSPACE;\r
187 }\r
1e57a462 188\r
e7108d0e
MK
189 re = (struct fdt_reserve_entry *)((char *)fdt + offset);\r
190 re->address = cpu_to_fdt64 (addr);\r
191 re->size = cpu_to_fdt64 (size);\r
1e57a462 192\r
e7108d0e 193 fdt_set_off_dt_struct (fdt, offset + sizeof (*re));\r
1e57a462 194\r
e7108d0e 195 return 0;\r
1e57a462 196}\r
197\r
e7108d0e
MK
198int\r
199fdt_finish_reservemap (\r
200 void *fdt\r
201 )\r
1e57a462 202{\r
e7108d0e 203 return fdt_add_reservemap_entry (fdt, 0, 0);\r
1e57a462 204}\r
205\r
e7108d0e
MK
206int\r
207fdt_begin_node (\r
208 void *fdt,\r
209 const char *name\r
210 )\r
1e57a462 211{\r
e7108d0e
MK
212 struct fdt_node_header *nh;\r
213 int namelen = strlen (name) + 1;\r
1e57a462 214\r
e7108d0e 215 FDT_SW_CHECK_HEADER (fdt);\r
1e57a462 216\r
e7108d0e
MK
217 nh = _fdt_grab_space (fdt, sizeof (*nh) + FDT_TAGALIGN (namelen));\r
218 if (!nh) {\r
219 return -FDT_ERR_NOSPACE;\r
220 }\r
1e57a462 221\r
e7108d0e
MK
222 nh->tag = cpu_to_fdt32 (FDT_BEGIN_NODE);\r
223 memcpy (nh->name, name, namelen);\r
224 return 0;\r
1e57a462 225}\r
226\r
e7108d0e
MK
227int\r
228fdt_end_node (\r
229 void *fdt\r
230 )\r
1e57a462 231{\r
e7108d0e 232 fdt32_t *en;\r
1e57a462 233\r
e7108d0e 234 FDT_SW_CHECK_HEADER (fdt);\r
1e57a462 235\r
e7108d0e
MK
236 en = _fdt_grab_space (fdt, FDT_TAGSIZE);\r
237 if (!en) {\r
238 return -FDT_ERR_NOSPACE;\r
239 }\r
1e57a462 240\r
e7108d0e
MK
241 *en = cpu_to_fdt32 (FDT_END_NODE);\r
242 return 0;\r
1e57a462 243}\r
244\r
e7108d0e
MK
245static int\r
246_fdt_find_add_string (\r
247 void *fdt,\r
248 const char *s\r
249 )\r
1e57a462 250{\r
e7108d0e
MK
251 char *strtab = (char *)fdt + fdt_totalsize (fdt);\r
252 const char *p;\r
253 int strtabsize = fdt_size_dt_strings (fdt);\r
254 int len = strlen (s) + 1;\r
255 int struct_top, offset;\r
256\r
257 p = _fdt_find_string (strtab - strtabsize, strtabsize, s);\r
258 if (p) {\r
259 return p - strtab;\r
260 }\r
261\r
262 /* Add it */\r
263 offset = -strtabsize - len;\r
264 struct_top = fdt_off_dt_struct (fdt) + fdt_size_dt_struct (fdt);\r
265 if (fdt_totalsize (fdt) + offset < struct_top) {\r
266 return 0; /* no more room :( */\r
267 }\r
268\r
269 memcpy (strtab + offset, s, len);\r
270 fdt_set_size_dt_strings (fdt, strtabsize + len);\r
271 return offset;\r
1e57a462 272}\r
273\r
e7108d0e
MK
274int\r
275fdt_property_placeholder (\r
276 void *fdt,\r
277 const char *name,\r
278 int len,\r
279 void **valp\r
280 )\r
1e57a462 281{\r
e7108d0e
MK
282 struct fdt_property *prop;\r
283 int nameoff;\r
284\r
285 FDT_SW_CHECK_HEADER (fdt);\r
286\r
287 nameoff = _fdt_find_add_string (fdt, name);\r
288 if (nameoff == 0) {\r
289 return -FDT_ERR_NOSPACE;\r
290 }\r
291\r
292 prop = _fdt_grab_space (fdt, sizeof (*prop) + FDT_TAGALIGN (len));\r
293 if (!prop) {\r
294 return -FDT_ERR_NOSPACE;\r
295 }\r
296\r
297 prop->tag = cpu_to_fdt32 (FDT_PROP);\r
298 prop->nameoff = cpu_to_fdt32 (nameoff);\r
299 prop->len = cpu_to_fdt32 (len);\r
300 *valp = prop->data;\r
301 return 0;\r
a0992390
PB
302}\r
303\r
e7108d0e
MK
304int\r
305fdt_property (\r
306 void *fdt,\r
307 const char *name,\r
308 const void *val,\r
309 int len\r
310 )\r
a0992390 311{\r
e7108d0e
MK
312 void *ptr;\r
313 int ret;\r
314\r
315 ret = fdt_property_placeholder (fdt, name, len, &ptr);\r
316 if (ret) {\r
317 return ret;\r
318 }\r
319\r
320 memcpy (ptr, val, len);\r
321 return 0;\r
1e57a462 322}\r
323\r
e7108d0e
MK
324int\r
325fdt_finish (\r
326 void *fdt\r
327 )\r
1e57a462 328{\r
e7108d0e
MK
329 char *p = (char *)fdt;\r
330 fdt32_t *end;\r
331 int oldstroffset, newstroffset;\r
332 uint32_t tag;\r
333 int offset, nextoffset;\r
334\r
335 FDT_SW_CHECK_HEADER (fdt);\r
336\r
337 /* Add terminator */\r
338 end = _fdt_grab_space (fdt, sizeof (*end));\r
339 if (!end) {\r
340 return -FDT_ERR_NOSPACE;\r
341 }\r
342\r
343 *end = cpu_to_fdt32 (FDT_END);\r
344\r
345 /* Relocate the string table */\r
346 oldstroffset = fdt_totalsize (fdt) - fdt_size_dt_strings (fdt);\r
347 newstroffset = fdt_off_dt_struct (fdt) + fdt_size_dt_struct (fdt);\r
348 memmove (p + newstroffset, p + oldstroffset, fdt_size_dt_strings (fdt));\r
349 fdt_set_off_dt_strings (fdt, newstroffset);\r
350\r
351 /* Walk the structure, correcting string offsets */\r
352 offset = 0;\r
353 while ((tag = fdt_next_tag (fdt, offset, &nextoffset)) != FDT_END) {\r
354 if (tag == FDT_PROP) {\r
355 struct fdt_property *prop =\r
356 _fdt_offset_ptr_w (fdt, offset);\r
357 int nameoff;\r
358\r
359 nameoff = fdt32_to_cpu (prop->nameoff);\r
360 nameoff += fdt_size_dt_strings (fdt);\r
361 prop->nameoff = cpu_to_fdt32 (nameoff);\r
362 }\r
363\r
364 offset = nextoffset;\r
365 }\r
366\r
367 if (nextoffset < 0) {\r
368 return nextoffset;\r
369 }\r
370\r
371 /* Finally, adjust the header */\r
372 fdt_set_totalsize (fdt, newstroffset + fdt_size_dt_strings (fdt));\r
373 fdt_set_magic (fdt, FDT_MAGIC);\r
374 return 0;\r
1e57a462 375}\r