xref: /openbmc/u-boot/lib/libfdt/fdt_wip.c (revision ed09a554)
1 /*
2  * libfdt - Flat Device Tree manipulation
3  * Copyright (C) 2006 David Gibson, IBM Corporation.
4  * SPDX-License-Identifier:	GPL-2.0+ BSD-2-Clause
5  */
6 #include "libfdt_env.h"
7 
8 #ifndef USE_HOSTCC
9 #include <fdt.h>
10 #include <libfdt.h>
11 #else
12 #include "fdt_host.h"
13 #endif
14 
15 #include "libfdt_internal.h"
16 
17 int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
18 			const void *val, int len)
19 {
20 	void *propval;
21 	int proplen;
22 
23 	propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
24 	if (! propval)
25 		return proplen;
26 
27 	if (proplen != len)
28 		return -FDT_ERR_NOSPACE;
29 
30 	memcpy(propval, val, len);
31 	return 0;
32 }
33 
34 static void _fdt_nop_region(void *start, int len)
35 {
36 	fdt32_t *p;
37 
38 	for (p = start; (char *)p < ((char *)start + len); p++)
39 		*p = cpu_to_fdt32(FDT_NOP);
40 }
41 
42 int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
43 {
44 	struct fdt_property *prop;
45 	int len;
46 
47 	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
48 	if (! prop)
49 		return len;
50 
51 	_fdt_nop_region(prop, len + sizeof(*prop));
52 
53 	return 0;
54 }
55 
56 int _fdt_node_end_offset(void *fdt, int offset)
57 {
58 	int depth = 0;
59 
60 	while ((offset >= 0) && (depth >= 0))
61 		offset = fdt_next_node(fdt, offset, &depth);
62 
63 	return offset;
64 }
65 
66 int fdt_nop_node(void *fdt, int nodeoffset)
67 {
68 	int endoffset;
69 
70 	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
71 	if (endoffset < 0)
72 		return endoffset;
73 
74 	_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
75 			endoffset - nodeoffset);
76 	return 0;
77 }
78 
79 #define FDT_MAX_DEPTH	32
80 
81 static int str_in_list(const char *str, char * const list[], int count)
82 {
83 	int i;
84 
85 	for (i = 0; i < count; i++)
86 		if (!strcmp(list[i], str))
87 			return 1;
88 
89 	return 0;
90 }
91 
92 int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
93 		     char * const exc_prop[], int exc_prop_count,
94 		     struct fdt_region region[], int max_regions,
95 		     char *path, int path_len, int add_string_tab)
96 {
97 	int stack[FDT_MAX_DEPTH];
98 	char *end;
99 	int nextoffset = 0;
100 	uint32_t tag;
101 	int count = 0;
102 	int start = -1;
103 	int depth = -1;
104 	int want = 0;
105 	int base = fdt_off_dt_struct(fdt);
106 
107 	end = path;
108 	*end = '\0';
109 	do {
110 		const struct fdt_property *prop;
111 		const char *name;
112 		const char *str;
113 		int include = 0;
114 		int stop_at = 0;
115 		int offset;
116 		int len;
117 
118 		offset = nextoffset;
119 		tag = fdt_next_tag(fdt, offset, &nextoffset);
120 		stop_at = nextoffset;
121 
122 		switch (tag) {
123 		case FDT_PROP:
124 			include = want >= 2;
125 			stop_at = offset;
126 			prop = fdt_get_property_by_offset(fdt, offset, NULL);
127 			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
128 			if (str_in_list(str, exc_prop, exc_prop_count))
129 				include = 0;
130 			break;
131 
132 		case FDT_NOP:
133 			include = want >= 2;
134 			stop_at = offset;
135 			break;
136 
137 		case FDT_BEGIN_NODE:
138 			depth++;
139 			if (depth == FDT_MAX_DEPTH)
140 				return -FDT_ERR_BADSTRUCTURE;
141 			name = fdt_get_name(fdt, offset, &len);
142 			if (end - path + 2 + len >= path_len)
143 				return -FDT_ERR_NOSPACE;
144 			if (end != path + 1)
145 				*end++ = '/';
146 			strcpy(end, name);
147 			end += len;
148 			stack[depth] = want;
149 			if (want == 1)
150 				stop_at = offset;
151 			if (str_in_list(path, inc, inc_count))
152 				want = 2;
153 			else if (want)
154 				want--;
155 			else
156 				stop_at = offset;
157 			include = want;
158 			break;
159 
160 		case FDT_END_NODE:
161 			include = want;
162 			want = stack[depth--];
163 			while (end > path && *--end != '/')
164 				;
165 			*end = '\0';
166 			break;
167 
168 		case FDT_END:
169 			include = 1;
170 			break;
171 		}
172 
173 		if (include && start == -1) {
174 			/* Should we merge with previous? */
175 			if (count && count <= max_regions &&
176 			    offset == region[count - 1].offset +
177 					region[count - 1].size - base)
178 				start = region[--count].offset - base;
179 			else
180 				start = offset;
181 		}
182 
183 		if (!include && start != -1) {
184 			if (count < max_regions) {
185 				region[count].offset = base + start;
186 				region[count].size = stop_at - start;
187 			}
188 			count++;
189 			start = -1;
190 		}
191 	} while (tag != FDT_END);
192 
193 	if (nextoffset != fdt_size_dt_struct(fdt))
194 		return -FDT_ERR_BADLAYOUT;
195 
196 	/* Add a region for the END tag and the string table */
197 	if (count < max_regions) {
198 		region[count].offset = base + start;
199 		region[count].size = nextoffset - start;
200 		if (add_string_tab)
201 			region[count].size += fdt_size_dt_strings(fdt);
202 	}
203 	count++;
204 
205 	return count;
206 }
207