xref: /utopia/UTPA2-700.0.x/projects/build/scripts/dtc/libfdt/fdt.c (revision 53ee8cc121a030b8d368113ac3e966b4705770ef)
1*53ee8cc1Swenshuai.xi /*
2*53ee8cc1Swenshuai.xi  * libfdt - Flat Device Tree manipulation
3*53ee8cc1Swenshuai.xi  * Copyright (C) 2006 David Gibson, IBM Corporation.
4*53ee8cc1Swenshuai.xi  *
5*53ee8cc1Swenshuai.xi  * libfdt is dual licensed: you can use it either under the terms of
6*53ee8cc1Swenshuai.xi  * the GPL, or the BSD license, at your option.
7*53ee8cc1Swenshuai.xi  *
8*53ee8cc1Swenshuai.xi  *  a) This library is free software; you can redistribute it and/or
9*53ee8cc1Swenshuai.xi  *     modify it under the terms of the GNU General Public License as
10*53ee8cc1Swenshuai.xi  *     published by the Free Software Foundation; either version 2 of the
11*53ee8cc1Swenshuai.xi  *     License, or (at your option) any later version.
12*53ee8cc1Swenshuai.xi  *
13*53ee8cc1Swenshuai.xi  *     This library is distributed in the hope that it will be useful,
14*53ee8cc1Swenshuai.xi  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
15*53ee8cc1Swenshuai.xi  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*53ee8cc1Swenshuai.xi  *     GNU General Public License for more details.
17*53ee8cc1Swenshuai.xi  *
18*53ee8cc1Swenshuai.xi  *     You should have received a copy of the GNU General Public
19*53ee8cc1Swenshuai.xi  *     License along with this library; if not, write to the Free
20*53ee8cc1Swenshuai.xi  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21*53ee8cc1Swenshuai.xi  *     MA 02110-1301 USA
22*53ee8cc1Swenshuai.xi  *
23*53ee8cc1Swenshuai.xi  * Alternatively,
24*53ee8cc1Swenshuai.xi  *
25*53ee8cc1Swenshuai.xi  *  b) Redistribution and use in source and binary forms, with or
26*53ee8cc1Swenshuai.xi  *     without modification, are permitted provided that the following
27*53ee8cc1Swenshuai.xi  *     conditions are met:
28*53ee8cc1Swenshuai.xi  *
29*53ee8cc1Swenshuai.xi  *     1. Redistributions of source code must retain the above
30*53ee8cc1Swenshuai.xi  *        copyright notice, this list of conditions and the following
31*53ee8cc1Swenshuai.xi  *        disclaimer.
32*53ee8cc1Swenshuai.xi  *     2. Redistributions in binary form must reproduce the above
33*53ee8cc1Swenshuai.xi  *        copyright notice, this list of conditions and the following
34*53ee8cc1Swenshuai.xi  *        disclaimer in the documentation and/or other materials
35*53ee8cc1Swenshuai.xi  *        provided with the distribution.
36*53ee8cc1Swenshuai.xi  *
37*53ee8cc1Swenshuai.xi  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38*53ee8cc1Swenshuai.xi  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39*53ee8cc1Swenshuai.xi  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40*53ee8cc1Swenshuai.xi  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41*53ee8cc1Swenshuai.xi  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42*53ee8cc1Swenshuai.xi  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43*53ee8cc1Swenshuai.xi  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44*53ee8cc1Swenshuai.xi  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45*53ee8cc1Swenshuai.xi  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46*53ee8cc1Swenshuai.xi  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47*53ee8cc1Swenshuai.xi  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48*53ee8cc1Swenshuai.xi  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49*53ee8cc1Swenshuai.xi  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50*53ee8cc1Swenshuai.xi  */
51*53ee8cc1Swenshuai.xi #include "libfdt_env.h"
52*53ee8cc1Swenshuai.xi 
53*53ee8cc1Swenshuai.xi #include <fdt.h>
54*53ee8cc1Swenshuai.xi #include <libfdt.h>
55*53ee8cc1Swenshuai.xi 
56*53ee8cc1Swenshuai.xi #include "libfdt_internal.h"
57*53ee8cc1Swenshuai.xi 
fdt_check_header(const void * fdt)58*53ee8cc1Swenshuai.xi int fdt_check_header(const void *fdt)
59*53ee8cc1Swenshuai.xi {
60*53ee8cc1Swenshuai.xi 	if (fdt_magic(fdt) == FDT_MAGIC) {
61*53ee8cc1Swenshuai.xi 		/* Complete tree */
62*53ee8cc1Swenshuai.xi 		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
63*53ee8cc1Swenshuai.xi 			return -FDT_ERR_BADVERSION;
64*53ee8cc1Swenshuai.xi 		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
65*53ee8cc1Swenshuai.xi 			return -FDT_ERR_BADVERSION;
66*53ee8cc1Swenshuai.xi 	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
67*53ee8cc1Swenshuai.xi 		/* Unfinished sequential-write blob */
68*53ee8cc1Swenshuai.xi 		if (fdt_size_dt_struct(fdt) == 0)
69*53ee8cc1Swenshuai.xi 			return -FDT_ERR_BADSTATE;
70*53ee8cc1Swenshuai.xi 	} else {
71*53ee8cc1Swenshuai.xi 		return -FDT_ERR_BADMAGIC;
72*53ee8cc1Swenshuai.xi 	}
73*53ee8cc1Swenshuai.xi 
74*53ee8cc1Swenshuai.xi 	return 0;
75*53ee8cc1Swenshuai.xi }
76*53ee8cc1Swenshuai.xi 
fdt_offset_ptr(const void * fdt,int offset,int len)77*53ee8cc1Swenshuai.xi const void *fdt_offset_ptr(const void *fdt, int offset, int len)
78*53ee8cc1Swenshuai.xi {
79*53ee8cc1Swenshuai.xi 	const char *p;
80*53ee8cc1Swenshuai.xi 
81*53ee8cc1Swenshuai.xi 	if (fdt_version(fdt) >= 0x11)
82*53ee8cc1Swenshuai.xi 		if (((offset + len) < offset)
83*53ee8cc1Swenshuai.xi 		    || ((offset + len) > fdt_size_dt_struct(fdt)))
84*53ee8cc1Swenshuai.xi 			return NULL;
85*53ee8cc1Swenshuai.xi 
86*53ee8cc1Swenshuai.xi 	p = _fdt_offset_ptr(fdt, offset);
87*53ee8cc1Swenshuai.xi 
88*53ee8cc1Swenshuai.xi 	if (p + len < p)
89*53ee8cc1Swenshuai.xi 		return NULL;
90*53ee8cc1Swenshuai.xi 	return p;
91*53ee8cc1Swenshuai.xi }
92*53ee8cc1Swenshuai.xi 
fdt_next_tag(const void * fdt,int offset,int * nextoffset)93*53ee8cc1Swenshuai.xi uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
94*53ee8cc1Swenshuai.xi {
95*53ee8cc1Swenshuai.xi 	const uint32_t *tagp, *lenp;
96*53ee8cc1Swenshuai.xi 	uint32_t tag;
97*53ee8cc1Swenshuai.xi 	const char *p;
98*53ee8cc1Swenshuai.xi 
99*53ee8cc1Swenshuai.xi 	if (offset % FDT_TAGSIZE)
100*53ee8cc1Swenshuai.xi 		return -1;
101*53ee8cc1Swenshuai.xi 
102*53ee8cc1Swenshuai.xi 	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
103*53ee8cc1Swenshuai.xi 	if (! tagp)
104*53ee8cc1Swenshuai.xi 		return FDT_END; /* premature end */
105*53ee8cc1Swenshuai.xi 	tag = fdt32_to_cpu(*tagp);
106*53ee8cc1Swenshuai.xi 	offset += FDT_TAGSIZE;
107*53ee8cc1Swenshuai.xi 
108*53ee8cc1Swenshuai.xi 	switch (tag) {
109*53ee8cc1Swenshuai.xi 	case FDT_BEGIN_NODE:
110*53ee8cc1Swenshuai.xi 		/* skip name */
111*53ee8cc1Swenshuai.xi 		do {
112*53ee8cc1Swenshuai.xi 			p = fdt_offset_ptr(fdt, offset++, 1);
113*53ee8cc1Swenshuai.xi 		} while (p && (*p != '\0'));
114*53ee8cc1Swenshuai.xi 		if (! p)
115*53ee8cc1Swenshuai.xi 			return FDT_END;
116*53ee8cc1Swenshuai.xi 		break;
117*53ee8cc1Swenshuai.xi 	case FDT_PROP:
118*53ee8cc1Swenshuai.xi 		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
119*53ee8cc1Swenshuai.xi 		if (! lenp)
120*53ee8cc1Swenshuai.xi 			return FDT_END;
121*53ee8cc1Swenshuai.xi 		/* skip name offset, length and value */
122*53ee8cc1Swenshuai.xi 		offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
123*53ee8cc1Swenshuai.xi 		break;
124*53ee8cc1Swenshuai.xi 	}
125*53ee8cc1Swenshuai.xi 
126*53ee8cc1Swenshuai.xi 	if (nextoffset)
127*53ee8cc1Swenshuai.xi 		*nextoffset = FDT_TAGALIGN(offset);
128*53ee8cc1Swenshuai.xi 
129*53ee8cc1Swenshuai.xi 	return tag;
130*53ee8cc1Swenshuai.xi }
131*53ee8cc1Swenshuai.xi 
_fdt_check_node_offset(const void * fdt,int offset)132*53ee8cc1Swenshuai.xi int _fdt_check_node_offset(const void *fdt, int offset)
133*53ee8cc1Swenshuai.xi {
134*53ee8cc1Swenshuai.xi 	if ((offset < 0) || (offset % FDT_TAGSIZE)
135*53ee8cc1Swenshuai.xi 	    || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
136*53ee8cc1Swenshuai.xi 		return -FDT_ERR_BADOFFSET;
137*53ee8cc1Swenshuai.xi 
138*53ee8cc1Swenshuai.xi 	return offset;
139*53ee8cc1Swenshuai.xi }
140*53ee8cc1Swenshuai.xi 
fdt_next_node(const void * fdt,int offset,int * depth)141*53ee8cc1Swenshuai.xi int fdt_next_node(const void *fdt, int offset, int *depth)
142*53ee8cc1Swenshuai.xi {
143*53ee8cc1Swenshuai.xi 	int nextoffset = 0;
144*53ee8cc1Swenshuai.xi 	uint32_t tag;
145*53ee8cc1Swenshuai.xi 
146*53ee8cc1Swenshuai.xi 	if (offset >= 0)
147*53ee8cc1Swenshuai.xi 		if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
148*53ee8cc1Swenshuai.xi 			return nextoffset;
149*53ee8cc1Swenshuai.xi 
150*53ee8cc1Swenshuai.xi 	do {
151*53ee8cc1Swenshuai.xi 		offset = nextoffset;
152*53ee8cc1Swenshuai.xi 		tag = fdt_next_tag(fdt, offset, &nextoffset);
153*53ee8cc1Swenshuai.xi 
154*53ee8cc1Swenshuai.xi 		switch (tag) {
155*53ee8cc1Swenshuai.xi 		case FDT_PROP:
156*53ee8cc1Swenshuai.xi 		case FDT_NOP:
157*53ee8cc1Swenshuai.xi 			break;
158*53ee8cc1Swenshuai.xi 
159*53ee8cc1Swenshuai.xi 		case FDT_BEGIN_NODE:
160*53ee8cc1Swenshuai.xi 			if (depth)
161*53ee8cc1Swenshuai.xi 				(*depth)++;
162*53ee8cc1Swenshuai.xi 			break;
163*53ee8cc1Swenshuai.xi 
164*53ee8cc1Swenshuai.xi 		case FDT_END_NODE:
165*53ee8cc1Swenshuai.xi 			if (depth)
166*53ee8cc1Swenshuai.xi 				(*depth)--;
167*53ee8cc1Swenshuai.xi 			break;
168*53ee8cc1Swenshuai.xi 
169*53ee8cc1Swenshuai.xi 		case FDT_END:
170*53ee8cc1Swenshuai.xi 			return -FDT_ERR_NOTFOUND;
171*53ee8cc1Swenshuai.xi 
172*53ee8cc1Swenshuai.xi 		default:
173*53ee8cc1Swenshuai.xi 			return -FDT_ERR_BADSTRUCTURE;
174*53ee8cc1Swenshuai.xi 		}
175*53ee8cc1Swenshuai.xi 	} while (tag != FDT_BEGIN_NODE);
176*53ee8cc1Swenshuai.xi 
177*53ee8cc1Swenshuai.xi 	return offset;
178*53ee8cc1Swenshuai.xi }
179*53ee8cc1Swenshuai.xi 
_fdt_find_string(const char * strtab,int tabsize,const char * s)180*53ee8cc1Swenshuai.xi const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
181*53ee8cc1Swenshuai.xi {
182*53ee8cc1Swenshuai.xi 	int len = strlen(s) + 1;
183*53ee8cc1Swenshuai.xi 	const char *last = strtab + tabsize - len;
184*53ee8cc1Swenshuai.xi 	const char *p;
185*53ee8cc1Swenshuai.xi 
186*53ee8cc1Swenshuai.xi 	for (p = strtab; p <= last; p++)
187*53ee8cc1Swenshuai.xi 		if (memcmp(p, s, len) == 0)
188*53ee8cc1Swenshuai.xi 			return p;
189*53ee8cc1Swenshuai.xi 	return NULL;
190*53ee8cc1Swenshuai.xi }
191*53ee8cc1Swenshuai.xi 
fdt_move(const void * fdt,void * buf,int bufsize)192*53ee8cc1Swenshuai.xi int fdt_move(const void *fdt, void *buf, int bufsize)
193*53ee8cc1Swenshuai.xi {
194*53ee8cc1Swenshuai.xi 	FDT_CHECK_HEADER(fdt);
195*53ee8cc1Swenshuai.xi 
196*53ee8cc1Swenshuai.xi 	if (fdt_totalsize(fdt) > bufsize)
197*53ee8cc1Swenshuai.xi 		return -FDT_ERR_NOSPACE;
198*53ee8cc1Swenshuai.xi 
199*53ee8cc1Swenshuai.xi 	memmove(buf, fdt, fdt_totalsize(fdt));
200*53ee8cc1Swenshuai.xi 	return 0;
201*53ee8cc1Swenshuai.xi }
202