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/kern_types.h>
39#include <kern/kalloc.h>
40
41#include <sys/types.h>
42
43#ifndef NULL
44#define       NULL    ((void *) 0)
45#endif
46
47#define round_long(x)	(((x) + 3UL) & ~(3UL))
48#define next_prop(x)	((DeviceTreeNodeProperty *) (((uintptr_t)x) + sizeof(DeviceTreeNodeProperty) + round_long(x->length)))
49
50/* Entry*/
51typedef DeviceTreeNode *RealDTEntry;
52
53typedef struct DTSavedScope {
54	struct DTSavedScope * nextScope;
55	RealDTEntry scope;
56	RealDTEntry entry;
57	unsigned long index;
58} *DTSavedScopePtr;
59
60/* Entry Iterator*/
61typedef struct OpaqueDTEntryIterator {
62	RealDTEntry outerScope;
63	RealDTEntry currentScope;
64	RealDTEntry currentEntry;
65	DTSavedScopePtr savedScope;
66	unsigned long currentIndex;
67} *RealDTEntryIterator;
68
69/* Property Iterator*/
70typedef struct OpaqueDTPropertyIterator {
71	RealDTEntry entry;
72	DeviceTreeNodeProperty *currentProperty;
73	unsigned long currentIndex;
74} *RealDTPropertyIterator;
75
76static int DTInitialized;
77static RealDTEntry DTRootNode;
78
79/*
80 * Support Routines
81 */
82static RealDTEntry
83skipProperties(RealDTEntry entry)
84{
85	DeviceTreeNodeProperty *prop;
86	unsigned int k;
87
88	if (entry == NULL || entry->nProperties == 0) {
89		return NULL;
90	} else {
91		prop = (DeviceTreeNodeProperty *) (entry + 1);
92		for (k = 0; k < entry->nProperties; k++) {
93			prop = next_prop(prop);
94		}
95	}
96	return ((RealDTEntry) prop);
97}
98
99static RealDTEntry
100skipTree(RealDTEntry root)
101{
102	RealDTEntry entry;
103	unsigned int k;
104
105	entry = skipProperties(root);
106	if (entry == NULL) {
107		return NULL;
108	}
109	for (k = 0; k < root->nChildren; k++) {
110		entry = skipTree(entry);
111	}
112	return entry;
113}
114
115static RealDTEntry
116GetFirstChild(RealDTEntry parent)
117{
118	return skipProperties(parent);
119}
120
121static RealDTEntry
122GetNextChild(RealDTEntry sibling)
123{
124	return skipTree(sibling);
125}
126
127static const char *
128GetNextComponent(const char *cp, char *bp)
129{
130	size_t length = 0;
131	char *origbp = bp;
132
133	while (*cp != 0) {
134		if (*cp == kDTPathNameSeparator) {
135			cp++;
136			break;
137		}
138		if (++length > kDTMaxEntryNameLength) {
139			*origbp = '\0';
140			return cp;
141		}
142		*bp++ = *cp++;
143	}
144	*bp = 0;
145	return cp;
146}
147
148static RealDTEntry
149FindChild(RealDTEntry cur, char *buf)
150{
151	RealDTEntry	child;
152	unsigned long	index;
153	char *			str;
154	unsigned int	dummy;
155
156	if (cur->nChildren == 0) {
157		return NULL;
158	}
159	index = 1;
160	child = GetFirstChild(cur);
161	while (1) {
162		if (DTGetProperty(child, "name", (void **)&str, &dummy) != kSuccess) {
163			break;
164		}
165		if (strcmp(str, buf) == 0) {
166			return child;
167		}
168		if (index >= cur->nChildren) {
169			break;
170		}
171		child = GetNextChild(child);
172		index++;
173	}
174	return NULL;
175}
176
177
178/*
179 * External Routines
180 */
181void
182DTInit(void *base)
183{
184	DTRootNode = (RealDTEntry) base;
185	DTInitialized = (DTRootNode != 0);
186}
187
188int
189DTEntryIsEqual(const DTEntry ref1, const DTEntry ref2)
190{
191	/* equality of pointers */
192	return (ref1 == ref2);
193}
194
195static char *startingP;		// needed for find_entry
196int find_entry(const char *propName, const char *propValue, DTEntry *entryH);
197
198int DTFindEntry(const char *propName, const char *propValue, DTEntry *entryH)
199{
200	if (!DTInitialized) {
201		return kError;
202	}
203
204	startingP = (char *)DTRootNode;
205	return(find_entry(propName, propValue, entryH));
206}
207
208int find_entry(const char *propName, const char *propValue, DTEntry *entryH)
209{
210	DeviceTreeNode *nodeP = (DeviceTreeNode *) (void *) startingP;
211	unsigned int k;
212
213	if (nodeP->nProperties == 0) return(kError);	// End of the list of nodes
214	startingP = (char *) (nodeP + 1);
215
216	// Search current entry
217	for (k = 0; k < nodeP->nProperties; ++k) {
218		DeviceTreeNodeProperty *propP = (DeviceTreeNodeProperty *) (void *) startingP;
219
220		startingP += sizeof (*propP) + ((propP->length + 3) & -4);
221
222		if (strcmp (propP->name, propName) == 0) {
223			if (propValue == NULL || strcmp( (char *)(propP + 1), propValue) == 0)
224			{
225				*entryH = (DTEntry)nodeP;
226				return(kSuccess);
227			}
228		}
229	}
230
231	// Search child nodes
232	for (k = 0; k < nodeP->nChildren; ++k)
233	{
234		if (find_entry(propName, propValue, entryH) == kSuccess)
235			return(kSuccess);
236	}
237	return(kError);
238}
239
240int
241DTLookupEntry(const DTEntry searchPoint, const char *pathName, DTEntry *foundEntry)
242{
243	DTEntryNameBuf	buf;
244	RealDTEntry	cur;
245	const char *	cp;
246
247	if (!DTInitialized) {
248		return kError;
249	}
250	if (searchPoint == NULL) {
251		cur = DTRootNode;
252	} else {
253		cur = searchPoint;
254	}
255	cp = pathName;
256	if (*cp == kDTPathNameSeparator) {
257		cp++;
258		if (*cp == 0) {
259			*foundEntry = cur;
260			return kSuccess;
261		}
262	}
263	do {
264		cp = GetNextComponent(cp, buf);
265
266		/* Check for done */
267		if (*buf == 0) {
268			if (*cp == 0) {
269				*foundEntry = cur;
270				return kSuccess;
271			}
272			break;
273		}
274
275		cur = FindChild(cur, buf);
276
277	} while (cur != NULL);
278
279	return kError;
280}
281
282int
283DTCreateEntryIterator(const DTEntry startEntry, DTEntryIterator *iterator)
284{
285	RealDTEntryIterator iter;
286
287	if (!DTInitialized) {
288		return kError;
289	}
290
291	iter = (RealDTEntryIterator) kalloc(sizeof(struct OpaqueDTEntryIterator));
292	if (startEntry != NULL) {
293		iter->outerScope = (RealDTEntry) startEntry;
294		iter->currentScope = (RealDTEntry) startEntry;
295	} else {
296		iter->outerScope = DTRootNode;
297		iter->currentScope = DTRootNode;
298	}
299	iter->currentEntry = NULL;
300	iter->savedScope = NULL;
301	iter->currentIndex = 0;
302
303	*iterator = iter;
304	return kSuccess;
305}
306
307int
308DTDisposeEntryIterator(DTEntryIterator iterator)
309{
310	RealDTEntryIterator iter = iterator;
311	DTSavedScopePtr scope;
312
313	while ((scope = iter->savedScope) != NULL) {
314		iter->savedScope = scope->nextScope;
315		kfree(scope, sizeof(struct DTSavedScope));
316	}
317	kfree(iterator, sizeof(struct OpaqueDTEntryIterator));
318	return kSuccess;
319}
320
321int
322DTEnterEntry(DTEntryIterator iterator, DTEntry childEntry)
323{
324	RealDTEntryIterator iter = iterator;
325	DTSavedScopePtr newScope;
326
327	if (childEntry == NULL) {
328		return kError;
329	}
330	newScope = (DTSavedScopePtr) kalloc(sizeof(struct DTSavedScope));
331	newScope->nextScope = iter->savedScope;
332	newScope->scope = iter->currentScope;
333	newScope->entry = iter->currentEntry;
334	newScope->index = iter->currentIndex;
335
336	iter->currentScope = childEntry;
337	iter->currentEntry = NULL;
338	iter->savedScope = newScope;
339	iter->currentIndex = 0;
340
341	return kSuccess;
342}
343
344int
345DTExitEntry(DTEntryIterator iterator, DTEntry *currentPosition)
346{
347	RealDTEntryIterator iter = iterator;
348	DTSavedScopePtr newScope;
349
350	newScope = iter->savedScope;
351	if (newScope == NULL) {
352		return kError;
353	}
354	iter->savedScope = newScope->nextScope;
355	iter->currentScope = newScope->scope;
356	iter->currentEntry = newScope->entry;
357	iter->currentIndex = newScope->index;
358	*currentPosition = iter->currentEntry;
359
360	kfree(newScope, sizeof(struct DTSavedScope));
361
362	return kSuccess;
363}
364
365int
366DTIterateEntries(DTEntryIterator iterator, DTEntry *nextEntry)
367{
368	RealDTEntryIterator iter = iterator;
369
370	if (iter->currentIndex >= iter->currentScope->nChildren) {
371		*nextEntry = NULL;
372		return kIterationDone;
373	} else {
374		iter->currentIndex++;
375		if (iter->currentIndex == 1) {
376			iter->currentEntry = GetFirstChild(iter->currentScope);
377		} else {
378			iter->currentEntry = GetNextChild(iter->currentEntry);
379		}
380		*nextEntry = iter->currentEntry;
381		return kSuccess;
382	}
383}
384
385int
386DTRestartEntryIteration(DTEntryIterator iterator)
387{
388	RealDTEntryIterator iter = iterator;
389#if 0
390	// This commented out code allows a second argument (outer)
391	// which (if true) causes restarting at the outer scope
392	// rather than the current scope.
393	DTSavedScopePtr scope;
394
395	if (outer) {
396		while ((scope = iter->savedScope) != NULL) {
397			iter->savedScope = scope->nextScope;
398			kfree((vm_offset_t) scope, sizeof(struct DTSavedScope));
399		}
400		iter->currentScope = iter->outerScope;
401	}
402#endif
403	iter->currentEntry = NULL;
404	iter->currentIndex = 0;
405	return kSuccess;
406}
407
408int
409DTGetProperty(const DTEntry entry, const char *propertyName, void **propertyValue, unsigned int *propertySize)
410{
411	DeviceTreeNodeProperty *prop;
412	unsigned int k;
413
414	if (entry == NULL || entry->nProperties == 0) {
415		return kError;
416	} else {
417		prop = (DeviceTreeNodeProperty *) (entry + 1);
418		for (k = 0; k < entry->nProperties; k++) {
419			if (strcmp(prop->name, propertyName) == 0) {
420				*propertyValue = (void *) (((uintptr_t)prop)
421						+ sizeof(DeviceTreeNodeProperty));
422				*propertySize = prop->length;
423				return kSuccess;
424			}
425			prop = next_prop(prop);
426		}
427	}
428	return kError;
429}
430
431int
432DTCreatePropertyIterator(const DTEntry entry, DTPropertyIterator *iterator)
433{
434	RealDTPropertyIterator iter;
435
436	iter = (RealDTPropertyIterator) kalloc(sizeof(struct OpaqueDTPropertyIterator));
437	iter->entry = entry;
438	iter->currentProperty = NULL;
439	iter->currentIndex = 0;
440
441	*iterator = iter;
442	return kSuccess;
443}
444
445int
446DTDisposePropertyIterator(DTPropertyIterator iterator)
447{
448	kfree(iterator, sizeof(struct OpaqueDTPropertyIterator));
449	return kSuccess;
450}
451
452int
453DTIterateProperties(DTPropertyIterator iterator, char **foundProperty)
454{
455	RealDTPropertyIterator iter = iterator;
456
457	if (iter->currentIndex >= iter->entry->nProperties) {
458		*foundProperty = NULL;
459		return kIterationDone;
460	} else {
461		iter->currentIndex++;
462		if (iter->currentIndex == 1) {
463			iter->currentProperty = (DeviceTreeNodeProperty *) (iter->entry + 1);
464		} else {
465			iter->currentProperty = next_prop(iter->currentProperty);
466		}
467		*foundProperty = iter->currentProperty->name;
468		return kSuccess;
469	}
470}
471
472int
473DTRestartPropertyIteration(DTPropertyIterator iterator)
474{
475	RealDTPropertyIterator iter = iterator;
476
477	iter->currentProperty = NULL;
478	iter->currentIndex = 0;
479	return kSuccess;
480}
481
482