]>
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@ |
0a7de745 | 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. | |
0a7de745 | 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. | |
0a7de745 | 17 | * |
2d21ac55 A |
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. | |
0a7de745 | 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; | |
0a7de745 | 55 | if (os_add3_overflow((uintptr_t)prop, prop->length, sizeof(DeviceTreeNodeProperty) + 3, &next_addr)) { |
5ba3f43e | 56 | panic("Device tree property overflow: prop %p, length 0x%x\n", prop, prop->length); |
0a7de745 | 57 | } |
5ba3f43e A |
58 | next_addr &= ~(3ULL); |
59 | return (DeviceTreeNodeProperty*)next_addr; | |
60 | } | |
61 | ||
1c79356b A |
62 | static RealDTEntry |
63 | skipProperties(RealDTEntry entry) | |
64 | { | |
65 | DeviceTreeNodeProperty *prop; | |
2d21ac55 | 66 | unsigned int k; |
1c79356b A |
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 | } | |
0a7de745 | 76 | return (RealDTEntry) prop; |
1c79356b A |
77 | } |
78 | ||
79 | static RealDTEntry | |
80 | skipTree(RealDTEntry root) | |
81 | { | |
82 | RealDTEntry entry; | |
2d21ac55 | 83 | unsigned int k; |
1c79356b A |
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 | { | |
316670eb A |
110 | size_t length = 0; |
111 | char *origbp = bp; | |
112 | ||
1c79356b A |
113 | while (*cp != 0) { |
114 | if (*cp == kDTPathNameSeparator) { | |
115 | cp++; | |
116 | break; | |
117 | } | |
316670eb A |
118 | if (++length > kDTMaxEntryNameLength) { |
119 | *origbp = '\0'; | |
120 | return cp; | |
121 | } | |
1c79356b A |
122 | *bp++ = *cp++; |
123 | } | |
124 | *bp = 0; | |
125 | return cp; | |
126 | } | |
127 | ||
128 | static RealDTEntry | |
129 | FindChild(RealDTEntry cur, char *buf) | |
130 | { | |
0a7de745 A |
131 | RealDTEntry child; |
132 | unsigned long index; | |
133 | char * str; | |
134 | unsigned int dummy; | |
1c79356b A |
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 */ | |
0a7de745 | 172 | return ref1 == ref2; |
1c79356b A |
173 | } |
174 | ||
0a7de745 | 175 | static char *startingP; // needed for find_entry |
1c79356b A |
176 | int find_entry(const char *propName, const char *propValue, DTEntry *entryH); |
177 | ||
0a7de745 A |
178 | int |
179 | DTFindEntry(const char *propName, const char *propValue, DTEntry *entryH) | |
1c79356b A |
180 | { |
181 | if (!DTInitialized) { | |
182 | return kError; | |
183 | } | |
184 | ||
185 | startingP = (char *)DTRootNode; | |
0a7de745 | 186 | return find_entry(propName, propValue, entryH); |
1c79356b A |
187 | } |
188 | ||
0a7de745 A |
189 | int |
190 | find_entry(const char *propName, const char *propValue, DTEntry *entryH) | |
1c79356b | 191 | { |
b0d623f7 | 192 | DeviceTreeNode *nodeP = (DeviceTreeNode *) (void *) startingP; |
2d21ac55 | 193 | unsigned int k; |
1c79356b | 194 | |
0a7de745 A |
195 | if (nodeP->nProperties == 0) { |
196 | return kError; // End of the list of nodes | |
197 | } | |
1c79356b A |
198 | startingP = (char *) (nodeP + 1); |
199 | ||
200 | // Search current entry | |
201 | for (k = 0; k < nodeP->nProperties; ++k) { | |
b0d623f7 | 202 | DeviceTreeNodeProperty *propP = (DeviceTreeNodeProperty *) (void *) startingP; |
1c79356b | 203 | |
0a7de745 | 204 | startingP += sizeof(*propP) + ((propP->length + 3) & -4); |
1c79356b | 205 | |
0a7de745 A |
206 | if (strcmp(propP->name, propName) == 0) { |
207 | if (propValue == NULL || strcmp((char *)(propP + 1), propValue) == 0) { | |
1c79356b | 208 | *entryH = (DTEntry)nodeP; |
0a7de745 | 209 | return kSuccess; |
1c79356b A |
210 | } |
211 | } | |
212 | } | |
213 | ||
214 | // Search child nodes | |
0a7de745 A |
215 | for (k = 0; k < nodeP->nChildren; ++k) { |
216 | if (find_entry(propName, propValue, entryH) == kSuccess) { | |
217 | return kSuccess; | |
218 | } | |
1c79356b | 219 | } |
0a7de745 | 220 | return kError; |
1c79356b A |
221 | } |
222 | ||
223 | int | |
224 | DTLookupEntry(const DTEntry searchPoint, const char *pathName, DTEntry *foundEntry) | |
225 | { | |
0a7de745 A |
226 | DTEntryNameBuf buf; |
227 | RealDTEntry cur; | |
228 | const char * cp; | |
1c79356b A |
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); | |
1c79356b A |
259 | } while (cur != NULL); |
260 | ||
261 | return kError; | |
262 | } | |
263 | ||
264 | int | |
5ba3f43e | 265 | DTInitEntryIterator(const DTEntry startEntry, DTEntryIterator iter) |
1c79356b | 266 | { |
1c79356b A |
267 | if (!DTInitialized) { |
268 | return kError; | |
269 | } | |
270 | ||
1c79356b A |
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 | ||
1c79356b A |
282 | return kSuccess; |
283 | } | |
284 | ||
285 | int | |
5ba3f43e | 286 | DTEnterEntry(DTEntryIterator iter, DTEntry childEntry) |
1c79356b | 287 | { |
1c79356b A |
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; | |
0a7de745 | 297 | newScope->index = iter->currentIndex; |
1c79356b A |
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 | |
5ba3f43e | 308 | DTExitEntry(DTEntryIterator iter, DTEntry *currentPosition) |
1c79356b | 309 | { |
1c79356b A |
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 | ||
91447636 | 322 | kfree(newScope, sizeof(struct DTSavedScope)); |
1c79356b A |
323 | |
324 | return kSuccess; | |
325 | } | |
326 | ||
327 | int | |
5ba3f43e | 328 | DTIterateEntries(DTEntryIterator iter, DTEntry *nextEntry) |
1c79356b | 329 | { |
1c79356b A |
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 | |
5ba3f43e | 346 | DTRestartEntryIteration(DTEntryIterator iter) |
1c79356b | 347 | { |
1c79356b A |
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 | |
2d21ac55 | 368 | DTGetProperty(const DTEntry entry, const char *propertyName, void **propertyValue, unsigned int *propertySize) |
1c79356b A |
369 | { |
370 | DeviceTreeNodeProperty *prop; | |
2d21ac55 | 371 | unsigned int k; |
1c79356b A |
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) { | |
b0d623f7 | 379 | *propertyValue = (void *) (((uintptr_t)prop) |
0a7de745 | 380 | + sizeof(DeviceTreeNodeProperty)); |
1c79356b A |
381 | *propertySize = prop->length; |
382 | return kSuccess; | |
383 | } | |
384 | prop = next_prop(prop); | |
385 | } | |
386 | } | |
387 | return kError; | |
388 | } | |
389 | ||
390 | int | |
5ba3f43e | 391 | DTInitPropertyIterator(const DTEntry entry, DTPropertyIterator iter) |
1c79356b | 392 | { |
1c79356b A |
393 | iter->entry = entry; |
394 | iter->currentProperty = NULL; | |
395 | iter->currentIndex = 0; | |
1c79356b A |
396 | return kSuccess; |
397 | } | |
398 | ||
399 | int | |
5ba3f43e | 400 | DTIterateProperties(DTPropertyIterator iter, char **foundProperty) |
1c79356b | 401 | { |
1c79356b A |
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 | |
5ba3f43e | 418 | DTRestartPropertyIteration(DTPropertyIterator iter) |
1c79356b | 419 | { |
1c79356b A |
420 | iter->currentProperty = NULL; |
421 | iter->currentIndex = 0; | |
422 | return kSuccess; | |
423 | } |