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