]> git.saurik.com Git - apple/xnu.git/blob - pexpert/gen/device_tree.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / pexpert / gen / device_tree.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_FREE_COPYRIGHT@
30 */
31
32 #include <pexpert/protos.h>
33 #include <pexpert/boot.h>
34 #include <pexpert/device_tree.h>
35
36 #include <mach/mach_types.h>
37 #include <mach/machine/vm_types.h>
38 #include <kern/debug.h>
39 #include <kern/kern_types.h>
40 #include <kern/kalloc.h>
41 #include <os/overflow.h>
42
43 #include <sys/types.h>
44
45 static int DTInitialized;
46 static RealDTEntry DTRootNode;
47
48 /*
49 * Support Routines
50 */
51 static inline DeviceTreeNodeProperty*
52 next_prop(DeviceTreeNodeProperty* prop)
53 {
54 uintptr_t next_addr;
55 if (os_add3_overflow((uintptr_t)prop, prop->length, sizeof(DeviceTreeNodeProperty) + 3, &next_addr)) {
56 panic("Device tree property overflow: prop %p, length 0x%x\n", prop, prop->length);
57 }
58 next_addr &= ~(3ULL);
59 return (DeviceTreeNodeProperty*)next_addr;
60 }
61
62 static RealDTEntry
63 skipProperties(RealDTEntry entry)
64 {
65 DeviceTreeNodeProperty *prop;
66 unsigned int k;
67
68 if (entry == NULL || entry->nProperties == 0) {
69 return NULL;
70 } else {
71 prop = (DeviceTreeNodeProperty *) (entry + 1);
72 for (k = 0; k < entry->nProperties; k++) {
73 prop = next_prop(prop);
74 }
75 }
76 return (RealDTEntry) prop;
77 }
78
79 static RealDTEntry
80 skipTree(RealDTEntry root)
81 {
82 RealDTEntry entry;
83 unsigned int k;
84
85 entry = skipProperties(root);
86 if (entry == NULL) {
87 return NULL;
88 }
89 for (k = 0; k < root->nChildren; k++) {
90 entry = skipTree(entry);
91 }
92 return entry;
93 }
94
95 static RealDTEntry
96 GetFirstChild(RealDTEntry parent)
97 {
98 return skipProperties(parent);
99 }
100
101 static RealDTEntry
102 GetNextChild(RealDTEntry sibling)
103 {
104 return skipTree(sibling);
105 }
106
107 static const char *
108 GetNextComponent(const char *cp, char *bp)
109 {
110 size_t length = 0;
111 char *origbp = bp;
112
113 while (*cp != 0) {
114 if (*cp == kDTPathNameSeparator) {
115 cp++;
116 break;
117 }
118 if (++length > kDTMaxEntryNameLength) {
119 *origbp = '\0';
120 return cp;
121 }
122 *bp++ = *cp++;
123 }
124 *bp = 0;
125 return cp;
126 }
127
128 static RealDTEntry
129 FindChild(RealDTEntry cur, char *buf)
130 {
131 RealDTEntry child;
132 unsigned long index;
133 char * str;
134 unsigned int dummy;
135
136 if (cur->nChildren == 0) {
137 return NULL;
138 }
139 index = 1;
140 child = GetFirstChild(cur);
141 while (1) {
142 if (DTGetProperty(child, "name", (void **)&str, &dummy) != kSuccess) {
143 break;
144 }
145 if (strcmp(str, buf) == 0) {
146 return child;
147 }
148 if (index >= cur->nChildren) {
149 break;
150 }
151 child = GetNextChild(child);
152 index++;
153 }
154 return NULL;
155 }
156
157
158 /*
159 * External Routines
160 */
161 void
162 DTInit(void *base)
163 {
164 DTRootNode = (RealDTEntry) base;
165 DTInitialized = (DTRootNode != 0);
166 }
167
168 int
169 DTEntryIsEqual(const DTEntry ref1, const DTEntry ref2)
170 {
171 /* equality of pointers */
172 return ref1 == ref2;
173 }
174
175 static char *startingP; // needed for find_entry
176 int find_entry(const char *propName, const char *propValue, DTEntry *entryH);
177
178 int
179 DTFindEntry(const char *propName, const char *propValue, DTEntry *entryH)
180 {
181 if (!DTInitialized) {
182 return kError;
183 }
184
185 startingP = (char *)DTRootNode;
186 return find_entry(propName, propValue, entryH);
187 }
188
189 int
190 find_entry(const char *propName, const char *propValue, DTEntry *entryH)
191 {
192 DeviceTreeNode *nodeP = (DeviceTreeNode *) (void *) startingP;
193 unsigned int k;
194
195 if (nodeP->nProperties == 0) {
196 return kError; // End of the list of nodes
197 }
198 startingP = (char *) (nodeP + 1);
199
200 // Search current entry
201 for (k = 0; k < nodeP->nProperties; ++k) {
202 DeviceTreeNodeProperty *propP = (DeviceTreeNodeProperty *) (void *) startingP;
203
204 startingP += sizeof(*propP) + ((propP->length + 3) & -4);
205
206 if (strcmp(propP->name, propName) == 0) {
207 if (propValue == NULL || strcmp((char *)(propP + 1), propValue) == 0) {
208 *entryH = (DTEntry)nodeP;
209 return kSuccess;
210 }
211 }
212 }
213
214 // Search child nodes
215 for (k = 0; k < nodeP->nChildren; ++k) {
216 if (find_entry(propName, propValue, entryH) == kSuccess) {
217 return kSuccess;
218 }
219 }
220 return kError;
221 }
222
223 int
224 DTLookupEntry(const DTEntry searchPoint, const char *pathName, DTEntry *foundEntry)
225 {
226 DTEntryNameBuf buf;
227 RealDTEntry cur;
228 const char * cp;
229
230 if (!DTInitialized) {
231 return kError;
232 }
233 if (searchPoint == NULL) {
234 cur = DTRootNode;
235 } else {
236 cur = searchPoint;
237 }
238 cp = pathName;
239 if (*cp == kDTPathNameSeparator) {
240 cp++;
241 if (*cp == 0) {
242 *foundEntry = cur;
243 return kSuccess;
244 }
245 }
246 do {
247 cp = GetNextComponent(cp, buf);
248
249 /* Check for done */
250 if (*buf == 0) {
251 if (*cp == 0) {
252 *foundEntry = cur;
253 return kSuccess;
254 }
255 break;
256 }
257
258 cur = FindChild(cur, buf);
259 } while (cur != NULL);
260
261 return kError;
262 }
263
264 int
265 DTInitEntryIterator(const DTEntry startEntry, DTEntryIterator iter)
266 {
267 if (!DTInitialized) {
268 return kError;
269 }
270
271 if (startEntry != NULL) {
272 iter->outerScope = (RealDTEntry) startEntry;
273 iter->currentScope = (RealDTEntry) startEntry;
274 } else {
275 iter->outerScope = DTRootNode;
276 iter->currentScope = DTRootNode;
277 }
278 iter->currentEntry = NULL;
279 iter->savedScope = NULL;
280 iter->currentIndex = 0;
281
282 return kSuccess;
283 }
284
285 int
286 DTEnterEntry(DTEntryIterator iter, DTEntry childEntry)
287 {
288 DTSavedScopePtr newScope;
289
290 if (childEntry == NULL) {
291 return kError;
292 }
293 newScope = (DTSavedScopePtr) kalloc(sizeof(struct DTSavedScope));
294 newScope->nextScope = iter->savedScope;
295 newScope->scope = iter->currentScope;
296 newScope->entry = iter->currentEntry;
297 newScope->index = iter->currentIndex;
298
299 iter->currentScope = childEntry;
300 iter->currentEntry = NULL;
301 iter->savedScope = newScope;
302 iter->currentIndex = 0;
303
304 return kSuccess;
305 }
306
307 int
308 DTExitEntry(DTEntryIterator iter, DTEntry *currentPosition)
309 {
310 DTSavedScopePtr newScope;
311
312 newScope = iter->savedScope;
313 if (newScope == NULL) {
314 return kError;
315 }
316 iter->savedScope = newScope->nextScope;
317 iter->currentScope = newScope->scope;
318 iter->currentEntry = newScope->entry;
319 iter->currentIndex = newScope->index;
320 *currentPosition = iter->currentEntry;
321
322 kfree(newScope, sizeof(struct DTSavedScope));
323
324 return kSuccess;
325 }
326
327 int
328 DTIterateEntries(DTEntryIterator iter, DTEntry *nextEntry)
329 {
330 if (iter->currentIndex >= iter->currentScope->nChildren) {
331 *nextEntry = NULL;
332 return kIterationDone;
333 } else {
334 iter->currentIndex++;
335 if (iter->currentIndex == 1) {
336 iter->currentEntry = GetFirstChild(iter->currentScope);
337 } else {
338 iter->currentEntry = GetNextChild(iter->currentEntry);
339 }
340 *nextEntry = iter->currentEntry;
341 return kSuccess;
342 }
343 }
344
345 int
346 DTRestartEntryIteration(DTEntryIterator iter)
347 {
348 #if 0
349 // This commented out code allows a second argument (outer)
350 // which (if true) causes restarting at the outer scope
351 // rather than the current scope.
352 DTSavedScopePtr scope;
353
354 if (outer) {
355 while ((scope = iter->savedScope) != NULL) {
356 iter->savedScope = scope->nextScope;
357 kfree((vm_offset_t) scope, sizeof(struct DTSavedScope));
358 }
359 iter->currentScope = iter->outerScope;
360 }
361 #endif
362 iter->currentEntry = NULL;
363 iter->currentIndex = 0;
364 return kSuccess;
365 }
366
367 int
368 DTGetProperty(const DTEntry entry, const char *propertyName, void **propertyValue, unsigned int *propertySize)
369 {
370 DeviceTreeNodeProperty *prop;
371 unsigned int k;
372
373 if (entry == NULL || entry->nProperties == 0) {
374 return kError;
375 } else {
376 prop = (DeviceTreeNodeProperty *) (entry + 1);
377 for (k = 0; k < entry->nProperties; k++) {
378 if (strcmp(prop->name, propertyName) == 0) {
379 *propertyValue = (void *) (((uintptr_t)prop)
380 + sizeof(DeviceTreeNodeProperty));
381 *propertySize = prop->length;
382 return kSuccess;
383 }
384 prop = next_prop(prop);
385 }
386 }
387 return kError;
388 }
389
390 int
391 DTInitPropertyIterator(const DTEntry entry, DTPropertyIterator iter)
392 {
393 iter->entry = entry;
394 iter->currentProperty = NULL;
395 iter->currentIndex = 0;
396 return kSuccess;
397 }
398
399 int
400 DTIterateProperties(DTPropertyIterator iter, char **foundProperty)
401 {
402 if (iter->currentIndex >= iter->entry->nProperties) {
403 *foundProperty = NULL;
404 return kIterationDone;
405 } else {
406 iter->currentIndex++;
407 if (iter->currentIndex == 1) {
408 iter->currentProperty = (DeviceTreeNodeProperty *) (iter->entry + 1);
409 } else {
410 iter->currentProperty = next_prop(iter->currentProperty);
411 }
412 *foundProperty = iter->currentProperty->name;
413 return kSuccess;
414 }
415 }
416
417 int
418 DTRestartPropertyIteration(DTPropertyIterator iter)
419 {
420 iter->currentProperty = NULL;
421 iter->currentIndex = 0;
422 return kSuccess;
423 }