source: rtems/cpukit/dtc/libfdt/fdt_sw.c @ 4fd05d3

Last change on this file since 4fd05d3 was 4fd05d3, checked in by Simon Glass <sjg@…>, on Jul 7, 2018 at 7:57:19 PM

libfdt: Copy the struct region in fdt_resize()

At present this function appears to copy only the data before the struct
region and the data in the string region. It does not seem to copy the
struct region itself.

From the arguments of this function it seems that it should support fdt
and buf being different. This patch attempts to fix this problem.

Signed-off-by: Simon Glass <sjg@…>
Signed-off-by: David Gibson <david@…>

  • Property mode set to 100644
File size: 9.0 KB
Line 
1/*
2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2006 David Gibson, IBM Corporation.
4 *
5 * libfdt is dual licensed: you can use it either under the terms of
6 * the GPL, or the BSD license, at your option.
7 *
8 *  a) This library is free software; you can redistribute it and/or
9 *     modify it under the terms of the GNU General Public License as
10 *     published by the Free Software Foundation; either version 2 of the
11 *     License, or (at your option) any later version.
12 *
13 *     This library is distributed in the hope that it will be useful,
14 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *     GNU General Public License for more details.
17 *
18 *     You should have received a copy of the GNU General Public
19 *     License along with this library; if not, write to the Free
20 *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 *     MA 02110-1301 USA
22 *
23 * Alternatively,
24 *
25 *  b) Redistribution and use in source and binary forms, with or
26 *     without modification, are permitted provided that the following
27 *     conditions are met:
28 *
29 *     1. Redistributions of source code must retain the above
30 *        copyright notice, this list of conditions and the following
31 *        disclaimer.
32 *     2. Redistributions in binary form must reproduce the above
33 *        copyright notice, this list of conditions and the following
34 *        disclaimer in the documentation and/or other materials
35 *        provided with the distribution.
36 *
37 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38 *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39 *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40 *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42 *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48 *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49 *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 */
51#include "libfdt_env.h"
52
53#include <fdt.h>
54#include <libfdt.h>
55
56#include "libfdt_internal.h"
57
58static int fdt_sw_probe_(void *fdt)
59{
60        if (fdt_magic(fdt) == FDT_MAGIC)
61                return -FDT_ERR_BADSTATE;
62        else if (fdt_magic(fdt) != FDT_SW_MAGIC)
63                return -FDT_ERR_BADMAGIC;
64        return 0;
65}
66
67#define FDT_SW_PROBE(fdt) \
68        { \
69                int err; \
70                if ((err = fdt_sw_probe_(fdt)) != 0) \
71                        return err; \
72        }
73
74/* 'memrsv' state:      Initial state after fdt_create()
75 *
76 * Allowed functions:
77 *      fdt_add_reservmap_entry()
78 *      fdt_finish_reservemap()         [moves to 'struct' state]
79 */
80static int fdt_sw_probe_memrsv_(void *fdt)
81{
82        int err = fdt_sw_probe_(fdt);
83        if (err)
84                return err;
85
86        if (fdt_off_dt_strings(fdt) != 0)
87                return -FDT_ERR_BADSTATE;
88        return 0;
89}
90
91#define FDT_SW_PROBE_MEMRSV(fdt) \
92        { \
93                int err; \
94                if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
95                        return err; \
96        }
97
98/* 'struct' state:      Enter this state after fdt_finish_reservemap()
99 *
100 * Allowed functions:
101 *      fdt_begin_node()
102 *      fdt_end_node()
103 *      fdt_property*()
104 *      fdt_finish()                    [moves to 'complete' state]
105 */
106static int fdt_sw_probe_struct_(void *fdt)
107{
108        int err = fdt_sw_probe_(fdt);
109        if (err)
110                return err;
111
112        if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
113                return -FDT_ERR_BADSTATE;
114        return 0;
115}
116
117#define FDT_SW_PROBE_STRUCT(fdt) \
118        { \
119                int err; \
120                if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
121                        return err; \
122        }
123
124/* 'complete' state:    Enter this state after fdt_finish()
125 *
126 * Allowed functions: none
127 */
128
129static void *fdt_grab_space_(void *fdt, size_t len)
130{
131        int offset = fdt_size_dt_struct(fdt);
132        int spaceleft;
133
134        spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
135                - fdt_size_dt_strings(fdt);
136
137        if ((offset + len < offset) || (offset + len > spaceleft))
138                return NULL;
139
140        fdt_set_size_dt_struct(fdt, offset + len);
141        return fdt_offset_ptr_w_(fdt, offset);
142}
143
144int fdt_create(void *buf, int bufsize)
145{
146        void *fdt = buf;
147
148        if (bufsize < sizeof(struct fdt_header))
149                return -FDT_ERR_NOSPACE;
150
151        memset(buf, 0, bufsize);
152
153        fdt_set_magic(fdt, FDT_SW_MAGIC);
154        fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
155        fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
156        fdt_set_totalsize(fdt,  bufsize);
157
158        fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
159                                              sizeof(struct fdt_reserve_entry)));
160        fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
161        fdt_set_off_dt_strings(fdt, 0);
162
163        return 0;
164}
165
166int fdt_resize(void *fdt, void *buf, int bufsize)
167{
168        size_t headsize, tailsize;
169        char *oldtail, *newtail;
170
171        FDT_SW_PROBE(fdt);
172
173        headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
174        tailsize = fdt_size_dt_strings(fdt);
175
176        if ((headsize + tailsize) > bufsize)
177                return -FDT_ERR_NOSPACE;
178
179        oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
180        newtail = (char *)buf + bufsize - tailsize;
181
182        /* Two cases to avoid clobbering data if the old and new
183         * buffers partially overlap */
184        if (buf <= fdt) {
185                memmove(buf, fdt, headsize);
186                memmove(newtail, oldtail, tailsize);
187        } else {
188                memmove(newtail, oldtail, tailsize);
189                memmove(buf, fdt, headsize);
190        }
191
192        fdt_set_totalsize(buf, bufsize);
193        if (fdt_off_dt_strings(buf))
194                fdt_set_off_dt_strings(buf, bufsize);
195
196        return 0;
197}
198
199int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
200{
201        struct fdt_reserve_entry *re;
202        int offset;
203
204        FDT_SW_PROBE_MEMRSV(fdt);
205
206        offset = fdt_off_dt_struct(fdt);
207        if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
208                return -FDT_ERR_NOSPACE;
209
210        re = (struct fdt_reserve_entry *)((char *)fdt + offset);
211        re->address = cpu_to_fdt64(addr);
212        re->size = cpu_to_fdt64(size);
213
214        fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
215
216        return 0;
217}
218
219int fdt_finish_reservemap(void *fdt)
220{
221        int err = fdt_add_reservemap_entry(fdt, 0, 0);
222
223        if (err)
224                return err;
225
226        fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
227        return 0;
228}
229
230int fdt_begin_node(void *fdt, const char *name)
231{
232        struct fdt_node_header *nh;
233        int namelen;
234
235        FDT_SW_PROBE_STRUCT(fdt);
236
237        namelen = strlen(name) + 1;
238        nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
239        if (! nh)
240                return -FDT_ERR_NOSPACE;
241
242        nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
243        memcpy(nh->name, name, namelen);
244        return 0;
245}
246
247int fdt_end_node(void *fdt)
248{
249        fdt32_t *en;
250
251        FDT_SW_PROBE_STRUCT(fdt);
252
253        en = fdt_grab_space_(fdt, FDT_TAGSIZE);
254        if (! en)
255                return -FDT_ERR_NOSPACE;
256
257        *en = cpu_to_fdt32(FDT_END_NODE);
258        return 0;
259}
260
261static int fdt_find_add_string_(void *fdt, const char *s)
262{
263        char *strtab = (char *)fdt + fdt_totalsize(fdt);
264        const char *p;
265        int strtabsize = fdt_size_dt_strings(fdt);
266        int len = strlen(s) + 1;
267        int struct_top, offset;
268
269        p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
270        if (p)
271                return p - strtab;
272
273        /* Add it */
274        offset = -strtabsize - len;
275        struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
276        if (fdt_totalsize(fdt) + offset < struct_top)
277                return 0; /* no more room :( */
278
279        memcpy(strtab + offset, s, len);
280        fdt_set_size_dt_strings(fdt, strtabsize + len);
281        return offset;
282}
283
284int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
285{
286        struct fdt_property *prop;
287        int nameoff;
288
289        FDT_SW_PROBE_STRUCT(fdt);
290
291        nameoff = fdt_find_add_string_(fdt, name);
292        if (nameoff == 0)
293                return -FDT_ERR_NOSPACE;
294
295        prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
296        if (! prop)
297                return -FDT_ERR_NOSPACE;
298
299        prop->tag = cpu_to_fdt32(FDT_PROP);
300        prop->nameoff = cpu_to_fdt32(nameoff);
301        prop->len = cpu_to_fdt32(len);
302        *valp = prop->data;
303        return 0;
304}
305
306int fdt_property(void *fdt, const char *name, const void *val, int len)
307{
308        void *ptr;
309        int ret;
310
311        ret = fdt_property_placeholder(fdt, name, len, &ptr);
312        if (ret)
313                return ret;
314        memcpy(ptr, val, len);
315        return 0;
316}
317
318int fdt_finish(void *fdt)
319{
320        char *p = (char *)fdt;
321        fdt32_t *end;
322        int oldstroffset, newstroffset;
323        uint32_t tag;
324        int offset, nextoffset;
325
326        FDT_SW_PROBE_STRUCT(fdt);
327
328        /* Add terminator */
329        end = fdt_grab_space_(fdt, sizeof(*end));
330        if (! end)
331                return -FDT_ERR_NOSPACE;
332        *end = cpu_to_fdt32(FDT_END);
333
334        /* Relocate the string table */
335        oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
336        newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
337        memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
338        fdt_set_off_dt_strings(fdt, newstroffset);
339
340        /* Walk the structure, correcting string offsets */
341        offset = 0;
342        while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
343                if (tag == FDT_PROP) {
344                        struct fdt_property *prop =
345                                fdt_offset_ptr_w_(fdt, offset);
346                        int nameoff;
347
348                        nameoff = fdt32_to_cpu(prop->nameoff);
349                        nameoff += fdt_size_dt_strings(fdt);
350                        prop->nameoff = cpu_to_fdt32(nameoff);
351                }
352                offset = nextoffset;
353        }
354        if (nextoffset < 0)
355                return nextoffset;
356
357        /* Finally, adjust the header */
358        fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
359        fdt_set_magic(fdt, FDT_MAGIC);
360        return 0;
361}
Note: See TracBrowser for help on using the repository browser.