source: rtems/cpukit/dtc/libfdt/fdt.c @ 85d1769

5
Last change on this file since 85d1769 was 85d1769, checked in by David Gibson <david@…>, on 10/22/17 at 05:32:15

libfdt: Clean up header checking functions

Many of the libfdt entry points call some sort of sanity check function
before doing anything else. These need to do slightly different things for
the various classes of functions.

The read-only version is shared with the exported fdt_check_header(), which
limits us a bit in how we can improve it. For that reason split the two
functions apart (though the exported one just calls the ro one for now).

We also rename the functions for more consistency - they're all named
fdt_XX_probe_() where the XX indicates which class of functions they're
for. "probe" is a better "term" than the previous check, since they really
only do minimal validation.

Signed-off-by: David Gibson <david@…>
Tested-by: Alexey Kardashevskiy <aik@…>
Reviewed-by: Alexey Kardashevskiy <aik@…>

  • Property mode set to 100644
File size: 6.9 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
58/*
59 * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
60 * that the given buffer contains what appears to be a flattened
61 * device tree with sane information in its header.
62 */
63int fdt_ro_probe_(const void *fdt)
64{
65        if (fdt_magic(fdt) == FDT_MAGIC) {
66                /* Complete tree */
67                if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
68                        return -FDT_ERR_BADVERSION;
69                if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
70                        return -FDT_ERR_BADVERSION;
71        } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
72                /* Unfinished sequential-write blob */
73                if (fdt_size_dt_struct(fdt) == 0)
74                        return -FDT_ERR_BADSTATE;
75        } else {
76                return -FDT_ERR_BADMAGIC;
77        }
78
79        return 0;
80}
81
82int fdt_check_header(const void *fdt)
83{
84        return fdt_ro_probe_(fdt);
85}
86
87const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
88{
89        unsigned absoffset = offset + fdt_off_dt_struct(fdt);
90
91        if ((absoffset < offset)
92            || ((absoffset + len) < absoffset)
93            || (absoffset + len) > fdt_totalsize(fdt))
94                return NULL;
95
96        if (fdt_version(fdt) >= 0x11)
97                if (((offset + len) < offset)
98                    || ((offset + len) > fdt_size_dt_struct(fdt)))
99                        return NULL;
100
101        return fdt_offset_ptr_(fdt, offset);
102}
103
104uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
105{
106        const fdt32_t *tagp, *lenp;
107        uint32_t tag;
108        int offset = startoffset;
109        const char *p;
110
111        *nextoffset = -FDT_ERR_TRUNCATED;
112        tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
113        if (!tagp)
114                return FDT_END; /* premature end */
115        tag = fdt32_to_cpu(*tagp);
116        offset += FDT_TAGSIZE;
117
118        *nextoffset = -FDT_ERR_BADSTRUCTURE;
119        switch (tag) {
120        case FDT_BEGIN_NODE:
121                /* skip name */
122                do {
123                        p = fdt_offset_ptr(fdt, offset++, 1);
124                } while (p && (*p != '\0'));
125                if (!p)
126                        return FDT_END; /* premature end */
127                break;
128
129        case FDT_PROP:
130                lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
131                if (!lenp)
132                        return FDT_END; /* premature end */
133                /* skip-name offset, length and value */
134                offset += sizeof(struct fdt_property) - FDT_TAGSIZE
135                        + fdt32_to_cpu(*lenp);
136                if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
137                    ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
138                        offset += 4;
139                break;
140
141        case FDT_END:
142        case FDT_END_NODE:
143        case FDT_NOP:
144                break;
145
146        default:
147                return FDT_END;
148        }
149
150        if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
151                return FDT_END; /* premature end */
152
153        *nextoffset = FDT_TAGALIGN(offset);
154        return tag;
155}
156
157int fdt_check_node_offset_(const void *fdt, int offset)
158{
159        if ((offset < 0) || (offset % FDT_TAGSIZE)
160            || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
161                return -FDT_ERR_BADOFFSET;
162
163        return offset;
164}
165
166int fdt_check_prop_offset_(const void *fdt, int offset)
167{
168        if ((offset < 0) || (offset % FDT_TAGSIZE)
169            || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
170                return -FDT_ERR_BADOFFSET;
171
172        return offset;
173}
174
175int fdt_next_node(const void *fdt, int offset, int *depth)
176{
177        int nextoffset = 0;
178        uint32_t tag;
179
180        if (offset >= 0)
181                if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
182                        return nextoffset;
183
184        do {
185                offset = nextoffset;
186                tag = fdt_next_tag(fdt, offset, &nextoffset);
187
188                switch (tag) {
189                case FDT_PROP:
190                case FDT_NOP:
191                        break;
192
193                case FDT_BEGIN_NODE:
194                        if (depth)
195                                (*depth)++;
196                        break;
197
198                case FDT_END_NODE:
199                        if (depth && ((--(*depth)) < 0))
200                                return nextoffset;
201                        break;
202
203                case FDT_END:
204                        if ((nextoffset >= 0)
205                            || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
206                                return -FDT_ERR_NOTFOUND;
207                        else
208                                return nextoffset;
209                }
210        } while (tag != FDT_BEGIN_NODE);
211
212        return offset;
213}
214
215int fdt_first_subnode(const void *fdt, int offset)
216{
217        int depth = 0;
218
219        offset = fdt_next_node(fdt, offset, &depth);
220        if (offset < 0 || depth != 1)
221                return -FDT_ERR_NOTFOUND;
222
223        return offset;
224}
225
226int fdt_next_subnode(const void *fdt, int offset)
227{
228        int depth = 1;
229
230        /*
231         * With respect to the parent, the depth of the next subnode will be
232         * the same as the last.
233         */
234        do {
235                offset = fdt_next_node(fdt, offset, &depth);
236                if (offset < 0 || depth < 1)
237                        return -FDT_ERR_NOTFOUND;
238        } while (depth > 1);
239
240        return offset;
241}
242
243const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
244{
245        int len = strlen(s) + 1;
246        const char *last = strtab + tabsize - len;
247        const char *p;
248
249        for (p = strtab; p <= last; p++)
250                if (memcmp(p, s, len) == 0)
251                        return p;
252        return NULL;
253}
254
255int fdt_move(const void *fdt, void *buf, int bufsize)
256{
257        FDT_RO_PROBE(fdt);
258
259        if (fdt_totalsize(fdt) > bufsize)
260                return -FDT_ERR_NOSPACE;
261
262        memmove(buf, fdt, fdt_totalsize(fdt));
263        return 0;
264}
Note: See TracBrowser for help on using the repository browser.