1*13e8728fSAndroid Build Coastguard Worker /*
2*13e8728fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*13e8728fSAndroid Build Coastguard Worker *
4*13e8728fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*13e8728fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*13e8728fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*13e8728fSAndroid Build Coastguard Worker *
8*13e8728fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*13e8728fSAndroid Build Coastguard Worker *
10*13e8728fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*13e8728fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*13e8728fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*13e8728fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*13e8728fSAndroid Build Coastguard Worker * limitations under the License.
15*13e8728fSAndroid Build Coastguard Worker */
16*13e8728fSAndroid Build Coastguard Worker
17*13e8728fSAndroid Build Coastguard Worker #include "libufdt.h"
18*13e8728fSAndroid Build Coastguard Worker
19*13e8728fSAndroid Build Coastguard Worker #include "ufdt_node_pool.h"
20*13e8728fSAndroid Build Coastguard Worker #include "ufdt_prop_dict.h"
21*13e8728fSAndroid Build Coastguard Worker
ufdt_construct(void * fdtp,struct ufdt_node_pool * pool)22*13e8728fSAndroid Build Coastguard Worker struct ufdt *ufdt_construct(void *fdtp, struct ufdt_node_pool *pool) {
23*13e8728fSAndroid Build Coastguard Worker (void)(pool); /* unused parameter */
24*13e8728fSAndroid Build Coastguard Worker
25*13e8728fSAndroid Build Coastguard Worker /* Inital size is 2, will be exponentially increased when it needed later.
26*13e8728fSAndroid Build Coastguard Worker (2 -> 4 -> 8 -> ...) */
27*13e8728fSAndroid Build Coastguard Worker const int DEFAULT_MEM_SIZE_FDTPS = 2;
28*13e8728fSAndroid Build Coastguard Worker
29*13e8728fSAndroid Build Coastguard Worker void **fdtps = NULL;
30*13e8728fSAndroid Build Coastguard Worker struct ufdt *res_ufdt = NULL;
31*13e8728fSAndroid Build Coastguard Worker
32*13e8728fSAndroid Build Coastguard Worker fdtps = (void **)dto_malloc(sizeof(void *) * DEFAULT_MEM_SIZE_FDTPS);
33*13e8728fSAndroid Build Coastguard Worker if (fdtps == NULL) goto error;
34*13e8728fSAndroid Build Coastguard Worker fdtps[0] = fdtp;
35*13e8728fSAndroid Build Coastguard Worker
36*13e8728fSAndroid Build Coastguard Worker res_ufdt = dto_malloc(sizeof(struct ufdt));
37*13e8728fSAndroid Build Coastguard Worker if (res_ufdt == NULL) goto error;
38*13e8728fSAndroid Build Coastguard Worker
39*13e8728fSAndroid Build Coastguard Worker res_ufdt->fdtps = fdtps;
40*13e8728fSAndroid Build Coastguard Worker res_ufdt->mem_size_fdtps = DEFAULT_MEM_SIZE_FDTPS;
41*13e8728fSAndroid Build Coastguard Worker res_ufdt->num_used_fdtps = (fdtp != NULL ? 1 : 0);
42*13e8728fSAndroid Build Coastguard Worker res_ufdt->root = NULL;
43*13e8728fSAndroid Build Coastguard Worker res_ufdt->phandle_table.data = NULL;
44*13e8728fSAndroid Build Coastguard Worker res_ufdt->phandle_table.len = 0;
45*13e8728fSAndroid Build Coastguard Worker
46*13e8728fSAndroid Build Coastguard Worker return res_ufdt;
47*13e8728fSAndroid Build Coastguard Worker
48*13e8728fSAndroid Build Coastguard Worker error:
49*13e8728fSAndroid Build Coastguard Worker if (res_ufdt) dto_free(res_ufdt);
50*13e8728fSAndroid Build Coastguard Worker if (fdtps) dto_free(fdtps);
51*13e8728fSAndroid Build Coastguard Worker
52*13e8728fSAndroid Build Coastguard Worker return NULL;
53*13e8728fSAndroid Build Coastguard Worker }
54*13e8728fSAndroid Build Coastguard Worker
ufdt_destruct(struct ufdt * tree,struct ufdt_node_pool * pool)55*13e8728fSAndroid Build Coastguard Worker void ufdt_destruct(struct ufdt *tree, struct ufdt_node_pool *pool) {
56*13e8728fSAndroid Build Coastguard Worker if (tree == NULL) return;
57*13e8728fSAndroid Build Coastguard Worker
58*13e8728fSAndroid Build Coastguard Worker ufdt_node_destruct(tree->root, pool);
59*13e8728fSAndroid Build Coastguard Worker
60*13e8728fSAndroid Build Coastguard Worker dto_free(tree->fdtps);
61*13e8728fSAndroid Build Coastguard Worker dto_free(tree->phandle_table.data);
62*13e8728fSAndroid Build Coastguard Worker dto_free(tree);
63*13e8728fSAndroid Build Coastguard Worker }
64*13e8728fSAndroid Build Coastguard Worker
ufdt_add_fdt(struct ufdt * tree,void * fdtp)65*13e8728fSAndroid Build Coastguard Worker int ufdt_add_fdt(struct ufdt *tree, void *fdtp) {
66*13e8728fSAndroid Build Coastguard Worker if (fdtp == NULL) {
67*13e8728fSAndroid Build Coastguard Worker return -1;
68*13e8728fSAndroid Build Coastguard Worker }
69*13e8728fSAndroid Build Coastguard Worker
70*13e8728fSAndroid Build Coastguard Worker int i = tree->num_used_fdtps;
71*13e8728fSAndroid Build Coastguard Worker if (i >= tree->mem_size_fdtps) {
72*13e8728fSAndroid Build Coastguard Worker int new_size = tree->mem_size_fdtps * 2;
73*13e8728fSAndroid Build Coastguard Worker void **new_fdtps = dto_malloc(sizeof(void *) * new_size);
74*13e8728fSAndroid Build Coastguard Worker if (new_fdtps == NULL) return -1;
75*13e8728fSAndroid Build Coastguard Worker
76*13e8728fSAndroid Build Coastguard Worker dto_memcpy(new_fdtps, tree->fdtps, sizeof(void *) * tree->mem_size_fdtps);
77*13e8728fSAndroid Build Coastguard Worker dto_free(tree->fdtps);
78*13e8728fSAndroid Build Coastguard Worker
79*13e8728fSAndroid Build Coastguard Worker tree->fdtps = new_fdtps;
80*13e8728fSAndroid Build Coastguard Worker tree->mem_size_fdtps = new_size;
81*13e8728fSAndroid Build Coastguard Worker }
82*13e8728fSAndroid Build Coastguard Worker
83*13e8728fSAndroid Build Coastguard Worker tree->fdtps[i] = fdtp;
84*13e8728fSAndroid Build Coastguard Worker tree->num_used_fdtps = i + 1;
85*13e8728fSAndroid Build Coastguard Worker
86*13e8728fSAndroid Build Coastguard Worker return 0;
87*13e8728fSAndroid Build Coastguard Worker }
88*13e8728fSAndroid Build Coastguard Worker
ufdt_get_string_off(const struct ufdt * tree,const char * s)89*13e8728fSAndroid Build Coastguard Worker int ufdt_get_string_off(const struct ufdt *tree, const char *s) {
90*13e8728fSAndroid Build Coastguard Worker /* fdt_create() sets the dt_string_off to the end of fdt buffer,
91*13e8728fSAndroid Build Coastguard Worker and _ufdt_output_strtab_to_fdt() copy all string tables in reversed order.
92*13e8728fSAndroid Build Coastguard Worker So, here the return offset value is base on the end of all string buffers,
93*13e8728fSAndroid Build Coastguard Worker and it should be a minus value. */
94*13e8728fSAndroid Build Coastguard Worker int res_off = 0;
95*13e8728fSAndroid Build Coastguard Worker for (int i = 0; i < tree->num_used_fdtps; i++) {
96*13e8728fSAndroid Build Coastguard Worker void *fdt = tree->fdtps[i];
97*13e8728fSAndroid Build Coastguard Worker const char *strtab_start = (const char *)fdt + fdt_off_dt_strings(fdt);
98*13e8728fSAndroid Build Coastguard Worker int strtab_size = fdt_size_dt_strings(fdt);
99*13e8728fSAndroid Build Coastguard Worker const char *strtab_end = strtab_start + strtab_size;
100*13e8728fSAndroid Build Coastguard Worker
101*13e8728fSAndroid Build Coastguard Worker /* Check if the string is in the string table */
102*13e8728fSAndroid Build Coastguard Worker if (s >= strtab_start && s < strtab_end) {
103*13e8728fSAndroid Build Coastguard Worker res_off += (s - strtab_end);
104*13e8728fSAndroid Build Coastguard Worker return res_off;
105*13e8728fSAndroid Build Coastguard Worker }
106*13e8728fSAndroid Build Coastguard Worker
107*13e8728fSAndroid Build Coastguard Worker res_off -= strtab_size;
108*13e8728fSAndroid Build Coastguard Worker }
109*13e8728fSAndroid Build Coastguard Worker /* Can not find the string, return 0 */
110*13e8728fSAndroid Build Coastguard Worker return 0;
111*13e8728fSAndroid Build Coastguard Worker }
112*13e8728fSAndroid Build Coastguard Worker
ufdt_new_node(void * fdtp,int node_offset,struct ufdt_node_pool * pool)113*13e8728fSAndroid Build Coastguard Worker static struct ufdt_node *ufdt_new_node(void *fdtp, int node_offset,
114*13e8728fSAndroid Build Coastguard Worker struct ufdt_node_pool *pool) {
115*13e8728fSAndroid Build Coastguard Worker if (fdtp == NULL) {
116*13e8728fSAndroid Build Coastguard Worker dto_error("Failed to get new_node because tree is NULL\n");
117*13e8728fSAndroid Build Coastguard Worker return NULL;
118*13e8728fSAndroid Build Coastguard Worker }
119*13e8728fSAndroid Build Coastguard Worker
120*13e8728fSAndroid Build Coastguard Worker fdt32_t *fdt_tag_ptr =
121*13e8728fSAndroid Build Coastguard Worker (fdt32_t *)fdt_offset_ptr(fdtp, node_offset, sizeof(fdt32_t));
122*13e8728fSAndroid Build Coastguard Worker struct ufdt_node *res = ufdt_node_construct(fdtp, fdt_tag_ptr, pool);
123*13e8728fSAndroid Build Coastguard Worker return res;
124*13e8728fSAndroid Build Coastguard Worker }
125*13e8728fSAndroid Build Coastguard Worker
fdt_to_ufdt_tree(void * fdtp,int cur_fdt_tag_offset,int * next_fdt_tag_offset,int cur_tag,struct ufdt_node_pool * pool)126*13e8728fSAndroid Build Coastguard Worker static struct ufdt_node *fdt_to_ufdt_tree(void *fdtp, int cur_fdt_tag_offset,
127*13e8728fSAndroid Build Coastguard Worker int *next_fdt_tag_offset, int cur_tag,
128*13e8728fSAndroid Build Coastguard Worker struct ufdt_node_pool *pool) {
129*13e8728fSAndroid Build Coastguard Worker if (fdtp == NULL) {
130*13e8728fSAndroid Build Coastguard Worker return NULL;
131*13e8728fSAndroid Build Coastguard Worker }
132*13e8728fSAndroid Build Coastguard Worker uint32_t tag;
133*13e8728fSAndroid Build Coastguard Worker struct ufdt_node *res, *child_node;
134*13e8728fSAndroid Build Coastguard Worker
135*13e8728fSAndroid Build Coastguard Worker res = NULL;
136*13e8728fSAndroid Build Coastguard Worker child_node = NULL;
137*13e8728fSAndroid Build Coastguard Worker tag = cur_tag;
138*13e8728fSAndroid Build Coastguard Worker
139*13e8728fSAndroid Build Coastguard Worker switch (tag) {
140*13e8728fSAndroid Build Coastguard Worker case FDT_END_NODE:
141*13e8728fSAndroid Build Coastguard Worker case FDT_NOP:
142*13e8728fSAndroid Build Coastguard Worker case FDT_END:
143*13e8728fSAndroid Build Coastguard Worker break;
144*13e8728fSAndroid Build Coastguard Worker
145*13e8728fSAndroid Build Coastguard Worker case FDT_PROP:
146*13e8728fSAndroid Build Coastguard Worker res = ufdt_new_node(fdtp, cur_fdt_tag_offset, pool);
147*13e8728fSAndroid Build Coastguard Worker break;
148*13e8728fSAndroid Build Coastguard Worker
149*13e8728fSAndroid Build Coastguard Worker case FDT_BEGIN_NODE:
150*13e8728fSAndroid Build Coastguard Worker res = ufdt_new_node(fdtp, cur_fdt_tag_offset, pool);
151*13e8728fSAndroid Build Coastguard Worker
152*13e8728fSAndroid Build Coastguard Worker do {
153*13e8728fSAndroid Build Coastguard Worker cur_fdt_tag_offset = *next_fdt_tag_offset;
154*13e8728fSAndroid Build Coastguard Worker
155*13e8728fSAndroid Build Coastguard Worker tag = fdt_next_tag(fdtp, cur_fdt_tag_offset, next_fdt_tag_offset);
156*13e8728fSAndroid Build Coastguard Worker if (tag == FDT_END) {
157*13e8728fSAndroid Build Coastguard Worker dto_error("failed to get next tag\n");
158*13e8728fSAndroid Build Coastguard Worker break;
159*13e8728fSAndroid Build Coastguard Worker }
160*13e8728fSAndroid Build Coastguard Worker
161*13e8728fSAndroid Build Coastguard Worker child_node = fdt_to_ufdt_tree(fdtp, cur_fdt_tag_offset,
162*13e8728fSAndroid Build Coastguard Worker next_fdt_tag_offset, tag, pool);
163*13e8728fSAndroid Build Coastguard Worker ufdt_node_add_child(res, child_node);
164*13e8728fSAndroid Build Coastguard Worker } while (tag != FDT_END_NODE);
165*13e8728fSAndroid Build Coastguard Worker break;
166*13e8728fSAndroid Build Coastguard Worker
167*13e8728fSAndroid Build Coastguard Worker default:
168*13e8728fSAndroid Build Coastguard Worker break;
169*13e8728fSAndroid Build Coastguard Worker }
170*13e8728fSAndroid Build Coastguard Worker
171*13e8728fSAndroid Build Coastguard Worker return res;
172*13e8728fSAndroid Build Coastguard Worker }
173*13e8728fSAndroid Build Coastguard Worker
ufdt_print(struct ufdt * tree)174*13e8728fSAndroid Build Coastguard Worker void ufdt_print(struct ufdt *tree) {
175*13e8728fSAndroid Build Coastguard Worker ufdt_node_print(tree->root, 0);
176*13e8728fSAndroid Build Coastguard Worker }
177*13e8728fSAndroid Build Coastguard Worker
ufdt_get_node_by_path_len(struct ufdt * tree,const char * path,int len)178*13e8728fSAndroid Build Coastguard Worker struct ufdt_node *ufdt_get_node_by_path_len(struct ufdt *tree, const char *path,
179*13e8728fSAndroid Build Coastguard Worker int len) {
180*13e8728fSAndroid Build Coastguard Worker /*
181*13e8728fSAndroid Build Coastguard Worker * RARE: aliases
182*13e8728fSAndroid Build Coastguard Worker * In device tree, we can assign some alias to specific nodes by defining
183*13e8728fSAndroid Build Coastguard Worker * these relation in "/aliases" node.
184*13e8728fSAndroid Build Coastguard Worker * The node has the form:
185*13e8728fSAndroid Build Coastguard Worker * {
186*13e8728fSAndroid Build Coastguard Worker * a = "/a_for_apple";
187*13e8728fSAndroid Build Coastguard Worker * b = "/b_for_banana";
188*13e8728fSAndroid Build Coastguard Worker * };
189*13e8728fSAndroid Build Coastguard Worker * So the path "a/subnode_1" should be expanded to "/a_for_apple/subnode_1".
190*13e8728fSAndroid Build Coastguard Worker */
191*13e8728fSAndroid Build Coastguard Worker if (*path != '/') {
192*13e8728fSAndroid Build Coastguard Worker const char *end = path + len;
193*13e8728fSAndroid Build Coastguard Worker
194*13e8728fSAndroid Build Coastguard Worker const char *next_slash;
195*13e8728fSAndroid Build Coastguard Worker next_slash = dto_memchr(path, '/', end - path);
196*13e8728fSAndroid Build Coastguard Worker if (!next_slash) next_slash = end;
197*13e8728fSAndroid Build Coastguard Worker
198*13e8728fSAndroid Build Coastguard Worker struct ufdt_node *aliases_node =
199*13e8728fSAndroid Build Coastguard Worker ufdt_node_get_node_by_path(tree->root, "/aliases");
200*13e8728fSAndroid Build Coastguard Worker aliases_node = ufdt_node_get_property_by_name_len(aliases_node, path,
201*13e8728fSAndroid Build Coastguard Worker next_slash - path);
202*13e8728fSAndroid Build Coastguard Worker
203*13e8728fSAndroid Build Coastguard Worker int path_len = 0;
204*13e8728fSAndroid Build Coastguard Worker const char *alias_path =
205*13e8728fSAndroid Build Coastguard Worker ufdt_node_get_fdt_prop_data(aliases_node, &path_len);
206*13e8728fSAndroid Build Coastguard Worker
207*13e8728fSAndroid Build Coastguard Worker if (alias_path == NULL || path_len == 0) {
208*13e8728fSAndroid Build Coastguard Worker dto_error("Failed to find valid alias %s\n", path);
209*13e8728fSAndroid Build Coastguard Worker return NULL;
210*13e8728fSAndroid Build Coastguard Worker }
211*13e8728fSAndroid Build Coastguard Worker
212*13e8728fSAndroid Build Coastguard Worker /* property data must be a nul terminated string */
213*13e8728fSAndroid Build Coastguard Worker int alias_len = strnlen(alias_path, path_len);
214*13e8728fSAndroid Build Coastguard Worker
215*13e8728fSAndroid Build Coastguard Worker if (alias_len != path_len - 1 || alias_len == 0) {
216*13e8728fSAndroid Build Coastguard Worker dto_error("Invalid alias for %s\n", path);
217*13e8728fSAndroid Build Coastguard Worker return NULL;
218*13e8728fSAndroid Build Coastguard Worker }
219*13e8728fSAndroid Build Coastguard Worker
220*13e8728fSAndroid Build Coastguard Worker struct ufdt_node *target_node =
221*13e8728fSAndroid Build Coastguard Worker ufdt_node_get_node_by_path_len(tree->root, alias_path, alias_len);
222*13e8728fSAndroid Build Coastguard Worker
223*13e8728fSAndroid Build Coastguard Worker return ufdt_node_get_node_by_path_len(target_node, next_slash,
224*13e8728fSAndroid Build Coastguard Worker end - next_slash);
225*13e8728fSAndroid Build Coastguard Worker }
226*13e8728fSAndroid Build Coastguard Worker return ufdt_node_get_node_by_path_len(tree->root, path, len);
227*13e8728fSAndroid Build Coastguard Worker }
228*13e8728fSAndroid Build Coastguard Worker
ufdt_get_node_by_path(struct ufdt * tree,const char * path)229*13e8728fSAndroid Build Coastguard Worker struct ufdt_node *ufdt_get_node_by_path(struct ufdt *tree, const char *path) {
230*13e8728fSAndroid Build Coastguard Worker return ufdt_get_node_by_path_len(tree, path, dto_strlen(path));
231*13e8728fSAndroid Build Coastguard Worker }
232*13e8728fSAndroid Build Coastguard Worker
ufdt_get_node_by_phandle(struct ufdt * tree,uint32_t phandle)233*13e8728fSAndroid Build Coastguard Worker struct ufdt_node *ufdt_get_node_by_phandle(struct ufdt *tree,
234*13e8728fSAndroid Build Coastguard Worker uint32_t phandle) {
235*13e8728fSAndroid Build Coastguard Worker struct ufdt_node *res = NULL;
236*13e8728fSAndroid Build Coastguard Worker /*
237*13e8728fSAndroid Build Coastguard Worker * Do binary search in phandle_table.data.
238*13e8728fSAndroid Build Coastguard Worker * [s, e) means the possible range which contains target node.
239*13e8728fSAndroid Build Coastguard Worker */
240*13e8728fSAndroid Build Coastguard Worker int s = 0, e = tree->phandle_table.len;
241*13e8728fSAndroid Build Coastguard Worker while (e - s > 1) {
242*13e8728fSAndroid Build Coastguard Worker int mid = s + ((e - s) >> 1);
243*13e8728fSAndroid Build Coastguard Worker uint32_t mid_phandle = tree->phandle_table.data[mid].phandle;
244*13e8728fSAndroid Build Coastguard Worker if (phandle < mid_phandle)
245*13e8728fSAndroid Build Coastguard Worker e = mid;
246*13e8728fSAndroid Build Coastguard Worker else
247*13e8728fSAndroid Build Coastguard Worker s = mid;
248*13e8728fSAndroid Build Coastguard Worker }
249*13e8728fSAndroid Build Coastguard Worker if (e - s > 0 && tree->phandle_table.data[s].phandle == phandle) {
250*13e8728fSAndroid Build Coastguard Worker res = tree->phandle_table.data[s].node;
251*13e8728fSAndroid Build Coastguard Worker }
252*13e8728fSAndroid Build Coastguard Worker return res;
253*13e8728fSAndroid Build Coastguard Worker }
254*13e8728fSAndroid Build Coastguard Worker
count_phandle_node(struct ufdt_node * node)255*13e8728fSAndroid Build Coastguard Worker static int count_phandle_node(struct ufdt_node *node) {
256*13e8728fSAndroid Build Coastguard Worker if (node == NULL) return 0;
257*13e8728fSAndroid Build Coastguard Worker if (ufdt_node_tag(node) != FDT_BEGIN_NODE) return 0;
258*13e8728fSAndroid Build Coastguard Worker int res = 0;
259*13e8728fSAndroid Build Coastguard Worker if (ufdt_node_get_phandle(node) > 0) res++;
260*13e8728fSAndroid Build Coastguard Worker struct ufdt_node **it;
261*13e8728fSAndroid Build Coastguard Worker for_each_child(it, node) { res += count_phandle_node(*it); }
262*13e8728fSAndroid Build Coastguard Worker return res;
263*13e8728fSAndroid Build Coastguard Worker }
264*13e8728fSAndroid Build Coastguard Worker
set_phandle_table_entry(struct ufdt_node * node,struct ufdt_phandle_table_entry * data,int * cur)265*13e8728fSAndroid Build Coastguard Worker static void set_phandle_table_entry(struct ufdt_node *node,
266*13e8728fSAndroid Build Coastguard Worker struct ufdt_phandle_table_entry *data,
267*13e8728fSAndroid Build Coastguard Worker int *cur) {
268*13e8728fSAndroid Build Coastguard Worker if (node == NULL || ufdt_node_tag(node) != FDT_BEGIN_NODE) return;
269*13e8728fSAndroid Build Coastguard Worker uint32_t ph = ufdt_node_get_phandle(node);
270*13e8728fSAndroid Build Coastguard Worker if (ph > 0) {
271*13e8728fSAndroid Build Coastguard Worker data[*cur].phandle = ph;
272*13e8728fSAndroid Build Coastguard Worker data[*cur].node = node;
273*13e8728fSAndroid Build Coastguard Worker (*cur)++;
274*13e8728fSAndroid Build Coastguard Worker }
275*13e8728fSAndroid Build Coastguard Worker struct ufdt_node **it;
276*13e8728fSAndroid Build Coastguard Worker for_each_child(it, node) set_phandle_table_entry(*it, data, cur);
277*13e8728fSAndroid Build Coastguard Worker return;
278*13e8728fSAndroid Build Coastguard Worker }
279*13e8728fSAndroid Build Coastguard Worker
phandle_table_entry_cmp(const void * pa,const void * pb)280*13e8728fSAndroid Build Coastguard Worker int phandle_table_entry_cmp(const void *pa, const void *pb) {
281*13e8728fSAndroid Build Coastguard Worker uint32_t ph_a = ((const struct ufdt_phandle_table_entry *)pa)->phandle;
282*13e8728fSAndroid Build Coastguard Worker uint32_t ph_b = ((const struct ufdt_phandle_table_entry *)pb)->phandle;
283*13e8728fSAndroid Build Coastguard Worker if (ph_a < ph_b)
284*13e8728fSAndroid Build Coastguard Worker return -1;
285*13e8728fSAndroid Build Coastguard Worker else if (ph_a == ph_b)
286*13e8728fSAndroid Build Coastguard Worker return 0;
287*13e8728fSAndroid Build Coastguard Worker else
288*13e8728fSAndroid Build Coastguard Worker return 1;
289*13e8728fSAndroid Build Coastguard Worker }
290*13e8728fSAndroid Build Coastguard Worker
build_phandle_table(struct ufdt * tree)291*13e8728fSAndroid Build Coastguard Worker struct ufdt_static_phandle_table build_phandle_table(struct ufdt *tree) {
292*13e8728fSAndroid Build Coastguard Worker struct ufdt_static_phandle_table res;
293*13e8728fSAndroid Build Coastguard Worker res.len = count_phandle_node(tree->root);
294*13e8728fSAndroid Build Coastguard Worker res.data = dto_malloc(sizeof(struct ufdt_phandle_table_entry) * res.len);
295*13e8728fSAndroid Build Coastguard Worker int cur = 0;
296*13e8728fSAndroid Build Coastguard Worker set_phandle_table_entry(tree->root, res.data, &cur);
297*13e8728fSAndroid Build Coastguard Worker dto_qsort(res.data, res.len, sizeof(struct ufdt_phandle_table_entry),
298*13e8728fSAndroid Build Coastguard Worker phandle_table_entry_cmp);
299*13e8728fSAndroid Build Coastguard Worker return res;
300*13e8728fSAndroid Build Coastguard Worker }
301*13e8728fSAndroid Build Coastguard Worker
ufdt_from_fdt(void * fdtp,size_t fdt_size,struct ufdt_node_pool * pool)302*13e8728fSAndroid Build Coastguard Worker struct ufdt *ufdt_from_fdt(void *fdtp, size_t fdt_size,
303*13e8728fSAndroid Build Coastguard Worker struct ufdt_node_pool *pool) {
304*13e8728fSAndroid Build Coastguard Worker (void)(fdt_size); /* unused parameter */
305*13e8728fSAndroid Build Coastguard Worker
306*13e8728fSAndroid Build Coastguard Worker int start_offset = fdt_path_offset(fdtp, "/");
307*13e8728fSAndroid Build Coastguard Worker if (start_offset < 0) {
308*13e8728fSAndroid Build Coastguard Worker return ufdt_construct(NULL, pool);
309*13e8728fSAndroid Build Coastguard Worker }
310*13e8728fSAndroid Build Coastguard Worker
311*13e8728fSAndroid Build Coastguard Worker int end_offset;
312*13e8728fSAndroid Build Coastguard Worker int start_tag = fdt_next_tag(fdtp, start_offset, &end_offset);
313*13e8728fSAndroid Build Coastguard Worker
314*13e8728fSAndroid Build Coastguard Worker if (start_tag != FDT_BEGIN_NODE) {
315*13e8728fSAndroid Build Coastguard Worker return ufdt_construct(NULL, pool);
316*13e8728fSAndroid Build Coastguard Worker }
317*13e8728fSAndroid Build Coastguard Worker
318*13e8728fSAndroid Build Coastguard Worker struct ufdt *res_tree = ufdt_construct(fdtp, pool);
319*13e8728fSAndroid Build Coastguard Worker if (res_tree == NULL) return NULL;
320*13e8728fSAndroid Build Coastguard Worker
321*13e8728fSAndroid Build Coastguard Worker res_tree->root =
322*13e8728fSAndroid Build Coastguard Worker fdt_to_ufdt_tree(fdtp, start_offset, &end_offset, start_tag, pool);
323*13e8728fSAndroid Build Coastguard Worker
324*13e8728fSAndroid Build Coastguard Worker res_tree->phandle_table = build_phandle_table(res_tree);
325*13e8728fSAndroid Build Coastguard Worker
326*13e8728fSAndroid Build Coastguard Worker return res_tree;
327*13e8728fSAndroid Build Coastguard Worker }
328*13e8728fSAndroid Build Coastguard Worker
_ufdt_get_property_nameoff(const struct ufdt * tree,const char * name,const struct ufdt_prop_dict * dict)329*13e8728fSAndroid Build Coastguard Worker static int _ufdt_get_property_nameoff(const struct ufdt *tree, const char *name,
330*13e8728fSAndroid Build Coastguard Worker const struct ufdt_prop_dict *dict) {
331*13e8728fSAndroid Build Coastguard Worker int res;
332*13e8728fSAndroid Build Coastguard Worker const struct fdt_property *same_name_prop = ufdt_prop_dict_find(dict, name);
333*13e8728fSAndroid Build Coastguard Worker if (same_name_prop != NULL) {
334*13e8728fSAndroid Build Coastguard Worker /* There is a property with same name, just use its string offset */
335*13e8728fSAndroid Build Coastguard Worker res = fdt32_to_cpu(same_name_prop->nameoff);
336*13e8728fSAndroid Build Coastguard Worker } else {
337*13e8728fSAndroid Build Coastguard Worker /* Get the string offset from the string table of the current tree */
338*13e8728fSAndroid Build Coastguard Worker res = ufdt_get_string_off(tree, name);
339*13e8728fSAndroid Build Coastguard Worker if (res == 0) {
340*13e8728fSAndroid Build Coastguard Worker dto_error("Cannot find property name in string table: %s\n", name);
341*13e8728fSAndroid Build Coastguard Worker return 0;
342*13e8728fSAndroid Build Coastguard Worker }
343*13e8728fSAndroid Build Coastguard Worker }
344*13e8728fSAndroid Build Coastguard Worker return res;
345*13e8728fSAndroid Build Coastguard Worker }
346*13e8728fSAndroid Build Coastguard Worker
_ufdt_output_property_to_fdt(const struct ufdt * tree,void * fdtp,const struct ufdt_node_fdt_prop * prop_node,struct ufdt_prop_dict * dict)347*13e8728fSAndroid Build Coastguard Worker static int _ufdt_output_property_to_fdt(
348*13e8728fSAndroid Build Coastguard Worker const struct ufdt *tree, void *fdtp,
349*13e8728fSAndroid Build Coastguard Worker const struct ufdt_node_fdt_prop *prop_node, struct ufdt_prop_dict *dict) {
350*13e8728fSAndroid Build Coastguard Worker int nameoff = _ufdt_get_property_nameoff(tree, prop_node->name, dict);
351*13e8728fSAndroid Build Coastguard Worker if (nameoff == 0) return -1;
352*13e8728fSAndroid Build Coastguard Worker
353*13e8728fSAndroid Build Coastguard Worker int data_len = 0;
354*13e8728fSAndroid Build Coastguard Worker void *data = ufdt_node_get_fdt_prop_data(&prop_node->parent, &data_len);
355*13e8728fSAndroid Build Coastguard Worker if (!data) {
356*13e8728fSAndroid Build Coastguard Worker dto_error("Failed to get property data.\n");
357*13e8728fSAndroid Build Coastguard Worker return -1;
358*13e8728fSAndroid Build Coastguard Worker }
359*13e8728fSAndroid Build Coastguard Worker
360*13e8728fSAndroid Build Coastguard Worker unsigned int aligned_data_len =
361*13e8728fSAndroid Build Coastguard Worker ((unsigned int)data_len + (FDT_TAGSIZE - 1u)) & ~(FDT_TAGSIZE - 1u);
362*13e8728fSAndroid Build Coastguard Worker
363*13e8728fSAndroid Build Coastguard Worker unsigned int new_propoff = fdt_size_dt_struct(fdtp);
364*13e8728fSAndroid Build Coastguard Worker unsigned int new_prop_size = sizeof(struct fdt_property) + aligned_data_len;
365*13e8728fSAndroid Build Coastguard Worker struct fdt_property *new_prop =
366*13e8728fSAndroid Build Coastguard Worker (struct fdt_property *)((char *)fdtp + fdt_off_dt_struct(fdtp) +
367*13e8728fSAndroid Build Coastguard Worker new_propoff);
368*13e8728fSAndroid Build Coastguard Worker char *fdt_end = (char *)fdtp + fdt_totalsize(fdtp);
369*13e8728fSAndroid Build Coastguard Worker if ((char *)new_prop + new_prop_size > fdt_end) {
370*13e8728fSAndroid Build Coastguard Worker dto_error("Not enough space for adding property.\n");
371*13e8728fSAndroid Build Coastguard Worker return -1;
372*13e8728fSAndroid Build Coastguard Worker }
373*13e8728fSAndroid Build Coastguard Worker fdt_set_size_dt_struct(fdtp, new_propoff + new_prop_size);
374*13e8728fSAndroid Build Coastguard Worker
375*13e8728fSAndroid Build Coastguard Worker new_prop->tag = cpu_to_fdt32(FDT_PROP);
376*13e8728fSAndroid Build Coastguard Worker new_prop->nameoff = cpu_to_fdt32(nameoff);
377*13e8728fSAndroid Build Coastguard Worker new_prop->len = cpu_to_fdt32(data_len);
378*13e8728fSAndroid Build Coastguard Worker dto_memcpy(new_prop->data, data, data_len);
379*13e8728fSAndroid Build Coastguard Worker
380*13e8728fSAndroid Build Coastguard Worker ufdt_prop_dict_add(dict, new_prop);
381*13e8728fSAndroid Build Coastguard Worker
382*13e8728fSAndroid Build Coastguard Worker return 0;
383*13e8728fSAndroid Build Coastguard Worker }
384*13e8728fSAndroid Build Coastguard Worker
_ufdt_output_node_to_fdt(const struct ufdt * tree,void * fdtp,const struct ufdt_node * node,struct ufdt_prop_dict * dict)385*13e8728fSAndroid Build Coastguard Worker static int _ufdt_output_node_to_fdt(const struct ufdt *tree, void *fdtp,
386*13e8728fSAndroid Build Coastguard Worker const struct ufdt_node *node,
387*13e8728fSAndroid Build Coastguard Worker struct ufdt_prop_dict *dict) {
388*13e8728fSAndroid Build Coastguard Worker uint32_t tag = ufdt_node_tag(node);
389*13e8728fSAndroid Build Coastguard Worker
390*13e8728fSAndroid Build Coastguard Worker if (tag == FDT_PROP) {
391*13e8728fSAndroid Build Coastguard Worker return _ufdt_output_property_to_fdt(
392*13e8728fSAndroid Build Coastguard Worker tree, fdtp, (const struct ufdt_node_fdt_prop *)node, dict);
393*13e8728fSAndroid Build Coastguard Worker }
394*13e8728fSAndroid Build Coastguard Worker
395*13e8728fSAndroid Build Coastguard Worker int err = fdt_begin_node(fdtp, ufdt_node_name(node));
396*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
397*13e8728fSAndroid Build Coastguard Worker
398*13e8728fSAndroid Build Coastguard Worker struct ufdt_node **it;
399*13e8728fSAndroid Build Coastguard Worker for_each_prop(it, node) {
400*13e8728fSAndroid Build Coastguard Worker err = _ufdt_output_node_to_fdt(tree, fdtp, *it, dict);
401*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
402*13e8728fSAndroid Build Coastguard Worker }
403*13e8728fSAndroid Build Coastguard Worker
404*13e8728fSAndroid Build Coastguard Worker for_each_node(it, node) {
405*13e8728fSAndroid Build Coastguard Worker err = _ufdt_output_node_to_fdt(tree, fdtp, *it, dict);
406*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
407*13e8728fSAndroid Build Coastguard Worker }
408*13e8728fSAndroid Build Coastguard Worker
409*13e8728fSAndroid Build Coastguard Worker err = fdt_end_node(fdtp);
410*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
411*13e8728fSAndroid Build Coastguard Worker
412*13e8728fSAndroid Build Coastguard Worker return 0;
413*13e8728fSAndroid Build Coastguard Worker }
414*13e8728fSAndroid Build Coastguard Worker
_ufdt_output_strtab_to_fdt(const struct ufdt * tree,void * fdt)415*13e8728fSAndroid Build Coastguard Worker static int _ufdt_output_strtab_to_fdt(const struct ufdt *tree, void *fdt) {
416*13e8728fSAndroid Build Coastguard Worker /* Currently, we don't know the final dt_struct size, so we copy all
417*13e8728fSAndroid Build Coastguard Worker string tables to the end of the target fdt buffer in reversed order.
418*13e8728fSAndroid Build Coastguard Worker At last, fdt_finish() will adjust dt_string offset */
419*13e8728fSAndroid Build Coastguard Worker const char *struct_top =
420*13e8728fSAndroid Build Coastguard Worker (char *)fdt + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
421*13e8728fSAndroid Build Coastguard Worker char *dest = (char *)fdt + fdt_totalsize(fdt);
422*13e8728fSAndroid Build Coastguard Worker
423*13e8728fSAndroid Build Coastguard Worker int dest_size = 0;
424*13e8728fSAndroid Build Coastguard Worker for (int i = 0; i < tree->num_used_fdtps; i++) {
425*13e8728fSAndroid Build Coastguard Worker void *src_fdt = tree->fdtps[i];
426*13e8728fSAndroid Build Coastguard Worker const char *src_strtab = (const char *)src_fdt + fdt_off_dt_strings(src_fdt);
427*13e8728fSAndroid Build Coastguard Worker int strtab_size = fdt_size_dt_strings(src_fdt);
428*13e8728fSAndroid Build Coastguard Worker
429*13e8728fSAndroid Build Coastguard Worker dest -= strtab_size;
430*13e8728fSAndroid Build Coastguard Worker if (dest < struct_top) {
431*13e8728fSAndroid Build Coastguard Worker dto_error("Not enough space for string table.\n");
432*13e8728fSAndroid Build Coastguard Worker return -1;
433*13e8728fSAndroid Build Coastguard Worker }
434*13e8728fSAndroid Build Coastguard Worker
435*13e8728fSAndroid Build Coastguard Worker dto_memcpy(dest, src_strtab, strtab_size);
436*13e8728fSAndroid Build Coastguard Worker
437*13e8728fSAndroid Build Coastguard Worker dest_size += strtab_size;
438*13e8728fSAndroid Build Coastguard Worker }
439*13e8728fSAndroid Build Coastguard Worker
440*13e8728fSAndroid Build Coastguard Worker fdt_set_size_dt_strings(fdt, dest_size);
441*13e8728fSAndroid Build Coastguard Worker
442*13e8728fSAndroid Build Coastguard Worker return 0;
443*13e8728fSAndroid Build Coastguard Worker }
444*13e8728fSAndroid Build Coastguard Worker
ufdt_to_fdt(const struct ufdt * tree,void * buf,int buf_size)445*13e8728fSAndroid Build Coastguard Worker int ufdt_to_fdt(const struct ufdt *tree, void *buf, int buf_size) {
446*13e8728fSAndroid Build Coastguard Worker if (tree->num_used_fdtps == 0) return -1;
447*13e8728fSAndroid Build Coastguard Worker if (tree->root == NULL) return -1;
448*13e8728fSAndroid Build Coastguard Worker
449*13e8728fSAndroid Build Coastguard Worker int err;
450*13e8728fSAndroid Build Coastguard Worker err = fdt_create(buf, buf_size);
451*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
452*13e8728fSAndroid Build Coastguard Worker
453*13e8728fSAndroid Build Coastguard Worker /* Here we output the memory reserve map of the ONLY FIRST fdt,
454*13e8728fSAndroid Build Coastguard Worker to be in compliance with the DTO behavior of libfdt. */
455*13e8728fSAndroid Build Coastguard Worker int n_mem_rsv = fdt_num_mem_rsv(tree->fdtps[0]);
456*13e8728fSAndroid Build Coastguard Worker for (int i = 0; i < n_mem_rsv; i++) {
457*13e8728fSAndroid Build Coastguard Worker uint64_t addr, size;
458*13e8728fSAndroid Build Coastguard Worker fdt_get_mem_rsv(tree->fdtps[0], i, &addr, &size);
459*13e8728fSAndroid Build Coastguard Worker fdt_add_reservemap_entry(buf, addr, size);
460*13e8728fSAndroid Build Coastguard Worker }
461*13e8728fSAndroid Build Coastguard Worker
462*13e8728fSAndroid Build Coastguard Worker err = fdt_finish_reservemap(buf);
463*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
464*13e8728fSAndroid Build Coastguard Worker
465*13e8728fSAndroid Build Coastguard Worker err = _ufdt_output_strtab_to_fdt(tree, buf);
466*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
467*13e8728fSAndroid Build Coastguard Worker
468*13e8728fSAndroid Build Coastguard Worker struct ufdt_prop_dict dict;
469*13e8728fSAndroid Build Coastguard Worker err = ufdt_prop_dict_construct(&dict, buf);
470*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
471*13e8728fSAndroid Build Coastguard Worker
472*13e8728fSAndroid Build Coastguard Worker err = _ufdt_output_node_to_fdt(tree, buf, tree->root, &dict);
473*13e8728fSAndroid Build Coastguard Worker
474*13e8728fSAndroid Build Coastguard Worker // Ensure property_dict is freed, even on error path.
475*13e8728fSAndroid Build Coastguard Worker ufdt_prop_dict_destruct(&dict);
476*13e8728fSAndroid Build Coastguard Worker
477*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
478*13e8728fSAndroid Build Coastguard Worker
479*13e8728fSAndroid Build Coastguard Worker err = fdt_finish(buf);
480*13e8728fSAndroid Build Coastguard Worker if (err < 0) return -1;
481*13e8728fSAndroid Build Coastguard Worker
482*13e8728fSAndroid Build Coastguard Worker /*
483*13e8728fSAndroid Build Coastguard Worker * IMPORTANT: fdt_totalsize(buf) might be less than buf_size
484*13e8728fSAndroid Build Coastguard Worker * so this is needed to make use of remain spaces.
485*13e8728fSAndroid Build Coastguard Worker */
486*13e8728fSAndroid Build Coastguard Worker return fdt_open_into(buf, buf, buf_size);
487*13e8728fSAndroid Build Coastguard Worker }
488