1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <stdint.h>
22#include <string.h>
23
24#include "flat_dt.h"
25
26#define DALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
27#define PALIGN(p, a) ((void *)(DALIGN((unsigned long)(p), (a))))
28#define GET_CELL(p) (p += 4, *((uint32_t *)(p-4)))
29
30static char *skip_name(char *p)
31{
32 while (*p != '\0')
33 p++;
34
35 return PALIGN(p, sizeof(uint32_t));
36}
37
38static char *skip_prop(void *blob, char *p)
39{
40 struct boot_param_header *bph = blob;
41 uint32_t len, nameoff;
42
43 len = GET_CELL(p);
44 nameoff = GET_CELL(p);
45 if ((bph->version < 0x10) && (len >= sizeof(uint64_t)))
46 p = PALIGN(p, sizeof(uint64_t));
47 return PALIGN(p + len, sizeof(uint32_t));
48}
49
50static char *get_unit(char *dtpath)
51{
52 char *p;
53
54 if (dtpath[0] != '/')
55 return dtpath;
56
57 p = dtpath + strlen(dtpath);
58 while (*p != '/')
59 p--;
60
61 return p+1;
62}
63
64static int first_seg_len(char *dtpath)
65{
66 int len = 0;
67
68 while ((dtpath[len] != '/') && (dtpath[len] != '\0'))
69 len++;
70
71 return len;
72}
73
74char *flat_dt_get_string(void *blob, uint32_t offset)
75{
76 struct boot_param_header *bph = blob;
77
78 return (char *)blob + bph->off_dt_strings + offset;
79}
80
81void *flat_dt_get_subnode(void *blob, void *node, char *uname, int unamelen)
82{
83 struct boot_param_header *bph = blob;
84 char *p = node;
85 uint32_t tag;
86 int depth = 0;
87 char *nuname;
88
89 if (! unamelen)
90 unamelen = strlen(uname);
91
92 do {
93 tag = GET_CELL(p);
94
95 switch (tag) {
96 case OF_DT_PROP:
97 p = skip_prop(blob, p);
98 break;
99
100 case OF_DT_BEGIN_NODE:
101 if (depth == 0) {
102 nuname = p;
103
104 if (bph->version < 0x10)
105 nuname = get_unit(nuname);
106
107 p = skip_name(p);
108
109 if (strncmp(nuname, uname, unamelen) == 0)
110 return p;
111 }
112 depth++;
113 break;
114
115 case OF_DT_END_NODE:
116 depth--;
117 break;
118
119 case OF_DT_END:
120
121 return NULL;
122 break;
123
124 default:
125
126 return NULL;
127 }
128 } while (depth >= 0);
129
130 return NULL;
131}
132
133void *flat_dt_get_node(void *blob, char *path)
134{
135 struct boot_param_header *bph = blob;
136 char *node;
137 int seglen;
138
139 node = blob + bph->off_dt_struct;
140 node += sizeof(uint32_t);
141 node = skip_name(node);
142
143 while (node && (*path)) {
144 if (path[0] == '/')
145 path++;
146
147 seglen = first_seg_len(path);
148
149 node = flat_dt_get_subnode(blob, node, path, seglen);
150
151 path += seglen;
152 }
153
154 return node;
155}
156
157void flat_dt_traverse(void *blob,
158 int (*fn)(void *blob, void *node, void *priv),
159 void *private)
160{
161 struct boot_param_header *bph = blob;
162 char *p;
163 uint32_t tag;
164 int depth = 0;
165 char *uname;
166
167 p = (char *)blob + bph->off_dt_struct;
168
169 tag = GET_CELL(p);
170 while (tag != OF_DT_END) {
171 switch (tag) {
172 case OF_DT_BEGIN_NODE:
173 uname = p;
174
175 if (bph->version < 0x10)
176 uname = get_unit(uname);
177
178 p = skip_name(p);
179
180 (*fn)(blob, p, private);
181 depth++;
182 break;
183
184 case OF_DT_END_NODE:
185 depth--;
186 break;
187
188 case OF_DT_PROP:
189 p = skip_prop(blob, p);
190 break;
191
192 default:
193
194 return;
195 }
196 }
197}
198
199void *flat_dt_get_prop(void *blob, void *node, char *name, uint32_t *len)
200{
201 struct boot_param_header *bph = blob;
202 char *p = node;
203
204 do {
205 uint32_t tag = GET_CELL(p);
206 uint32_t sz, noff;
207 const char *nstr;
208
209 if (tag != OF_DT_PROP)
210 return NULL;
211
212 sz = GET_CELL(p);
213 noff = GET_CELL(p);
214
215
216
217 if ((bph->version < 0x10) && (sz >= 8))
218 p = PALIGN(p, 8);
219
220 nstr = flat_dt_get_string(blob, noff);
221
222 if (strcmp(name, nstr) == 0) {
223 if (len)
224 *len = sz;
225 return (void *)p;
226 }
227
228 p = PALIGN(p + sz, sizeof(uint32_t));
229 } while(1);
230}
231