1 /*
2  * Copyright (c) 1998-2006 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 #include <IOKit/IODeviceTreeSupport.h>
30 #include <libkern/c++/OSContainers.h>
31 #include <libkern/c++/OSSharedPtr.h>
32 #include <IOKit/IODeviceMemory.h>
33 #include <IOKit/IOService.h>
34 #include <IOKit/IOCatalogue.h>
35 
36 #include <IOKit/IOLib.h>
37 #include <IOKit/IOKitKeys.h>
38 
39 #include <pexpert/device_tree.h>
40 
41 #if __arm64__
42 typedef UInt64  dtptr_t;
43 #else
44 typedef UInt32  dtptr_t;
45 #endif
46 
47 #include <machine/machine_routines.h>
48 
49 extern "C" {
50 int IODTGetLoaderInfo( const char *key, void **infoAddr, int *infosize );
51 void IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize );
52 int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize );
53 }
54 
55 #include <IOKit/assert.h>
56 
57 #define IODTSUPPORTDEBUG 0
58 
59 const IORegistryPlane * gIODTPlane;
60 
61 static OSArray *    gIODTPHandles;
62 static OSArray *    gIODTPHandleMap;
63 static OSData  *    gIODTResolvers;
64 
65 const OSSymbol *        gIODTNameKey;
66 const OSSymbol *        gIODTUnitKey;
67 const OSSymbol *        gIODTCompatibleKey;
68 const OSSymbol *        gIODTTypeKey;
69 const OSSymbol *        gIODTModelKey;
70 const OSSymbol *        gIODTBridgeModelKey;
71 const OSSymbol *        gIODTTargetTypeKey;
72 
73 const OSSymbol *        gIODTSizeCellKey;
74 const OSSymbol *        gIODTAddressCellKey;
75 const OSSymbol *        gIODTRangeKey;
76 
77 const OSSymbol *        gIODTPersistKey;
78 
79 const OSSymbol *        gIODTDefaultInterruptController;
80 const OSSymbol *        gIODTAAPLInterruptsKey;
81 const OSSymbol *        gIODTPHandleKey;
82 const OSSymbol *        gIODTInterruptCellKey;
83 const OSSymbol *        gIODTInterruptParentKey;
84 const OSSymbol *        gIODTNWInterruptMappingKey;
85 
86 OSDictionary   *        gIODTSharedInterrupts;
87 
88 static IOLock  *    gIODTResolversLock;
89 
90 static IORegistryEntry * MakeReferenceTable( DTEntry dtEntry, bool copy );
91 static void AddPHandle( IORegistryEntry * regEntry );
92 static void FreePhysicalMemory( vm_offset_t * range );
93 static bool IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts );
94 
95 // FIXME: Implementation of this function is hidden from the static analyzer.
96 // The analyzer doesn't know that the registry holds retains, and gets confused
97 // about releases after calls to 'attachToParent'.
98 // Feel free to remove the #ifndef and address the warning!
99 #ifndef __clang_analyzer__
100 IORegistryEntry *
101 IODeviceTreeAlloc( void * dtTop )
102 {
103 	IORegistryEntry *           parent;
104 	IORegistryEntry *           child;
105 	IORegistryIterator *        regIter;
106 	OpaqueDTEntryIterator       iter;
107 	DTEntry                     dtChild;
108 	DTEntry                     mapEntry;
109 	OSArray *                   stack;
110 	OSData *                    prop;
111 	OSDictionary *              allInts;
112 	vm_offset_t *               dtMap;
113 	unsigned int                propSize;
114 	bool                        intMap;
115 	bool                        foundDTNode;
116 	bool                        freeDT;
117 
118 	gIODTPlane = IORegistryEntry::makePlane( kIODeviceTreePlane );
119 
120 	gIODTNameKey                = OSSymbol::withCStringNoCopy( "name" );
121 	gIODTUnitKey                = OSSymbol::withCStringNoCopy( "AAPL,unit-string" );
122 	gIODTCompatibleKey  = OSSymbol::withCStringNoCopy( "compatible" );
123 	gIODTTypeKey                = OSSymbol::withCStringNoCopy( "device_type" );
124 	gIODTModelKey               = OSSymbol::withCStringNoCopy( "model" );
125 	gIODTBridgeModelKey         = OSSymbol::withCStringNoCopy( "bridge-model" );
126 	gIODTTargetTypeKey          = OSSymbol::withCStringNoCopy( "target-type" );
127 	gIODTSizeCellKey    = OSSymbol::withCStringNoCopy( "#size-cells" );
128 	gIODTAddressCellKey = OSSymbol::withCStringNoCopy( "#address-cells" );
129 	gIODTRangeKey               = OSSymbol::withCStringNoCopy( "ranges" );
130 	gIODTPersistKey             = OSSymbol::withCStringNoCopy( "IODTPersist" );
131 
132 	assert(    gIODTPlane && gIODTCompatibleKey
133 	    && gIODTTypeKey && gIODTModelKey
134 	    && gIODTSizeCellKey && gIODTAddressCellKey && gIODTRangeKey
135 	    && gIODTPersistKey );
136 
137 	gIODTDefaultInterruptController
138 	        = OSSymbol::withCStringNoCopy("IOPrimaryInterruptController");
139 	gIODTNWInterruptMappingKey
140 	        = OSSymbol::withCStringNoCopy("IONWInterrupts");
141 
142 	gIODTAAPLInterruptsKey
143 	        = OSSymbol::withCStringNoCopy("AAPL,interrupts");
144 	gIODTPHandleKey
145 	        = OSSymbol::withCStringNoCopy("AAPL,phandle");
146 
147 	gIODTInterruptParentKey
148 	        = OSSymbol::withCStringNoCopy("interrupt-parent");
149 
150 	gIODTPHandles       = OSArray::withCapacity( 1 );
151 	gIODTPHandleMap     = OSArray::withCapacity( 1 );
152 	gIODTResolvers  = OSData::withCapacity(16);
153 
154 	gIODTResolversLock = IOLockAlloc();
155 
156 	gIODTInterruptCellKey
157 	        = OSSymbol::withCStringNoCopy("#interrupt-cells");
158 
159 	assert(    gIODTDefaultInterruptController && gIODTNWInterruptMappingKey
160 	    && gIODTAAPLInterruptsKey
161 	    && gIODTPHandleKey && gIODTInterruptParentKey
162 	    && gIODTPHandles && gIODTPHandleMap && gIODTResolvers && gIODTResolversLock
163 	    && gIODTInterruptCellKey
164 	    );
165 
166 	foundDTNode = (kSuccess == SecureDTLookupEntry( NULL, "/chosen/memory-map", &mapEntry ))
167 	    && (kSuccess == SecureDTGetProperty( mapEntry,
168 	    "DeviceTree", (void const **) &dtMap, &propSize ))
169 	    && ((2 * sizeof(uint32_t)) == propSize);
170 
171 	freeDT = foundDTNode && !SecureDTIsLockedDown();
172 
173 	parent = MakeReferenceTable((DTEntry)dtTop, freeDT );
174 
175 	stack = OSArray::withObjects((const OSObject **) &parent, 1, 10 );
176 	SecureDTInitEntryIterator((DTEntry)dtTop, &iter );
177 
178 	do {
179 		parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1);
180 		//parent->release();
181 		stack->removeObject( stack->getCount() - 1);
182 
183 		while (kSuccess == SecureDTIterateEntries( &iter, &dtChild)) {
184 			child = MakeReferenceTable( dtChild, freeDT );
185 			child->attachToParent( parent, gIODTPlane);
186 
187 			AddPHandle( child );
188 
189 			if (kSuccess == SecureDTEnterEntry( &iter, dtChild)) {
190 				stack->setObject( parent);
191 				parent = child;
192 			}
193 			// only registry holds retain
194 			child->release();
195 		}
196 	} while (stack->getCount()
197 	    && (kSuccess == SecureDTExitEntry( &iter, &dtChild)));
198 
199 	stack->release();
200 	assert(kSuccess != SecureDTExitEntry(&iter, &dtChild));
201 
202 	// parent is now root of the created tree
203 
204 	// make root name first compatible entry (purely cosmetic)
205 	if ((prop = (OSData *) parent->getProperty( gIODTCompatibleKey))) {
206 		parent->setName( parent->getName(), gIODTPlane );
207 		parent->setName((const char *) prop->getBytesNoCopy());
208 	}
209 
210 	// attach tree to meta root
211 	parent->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane);
212 	parent->release();
213 
214 	if (freeDT) {
215 		// free original device tree
216 		SecureDTInit(NULL, 0);
217 		IODTFreeLoaderInfo( "DeviceTree",
218 		    (void *)dtMap[0], (int) round_page(dtMap[1]));
219 	}
220 
221 	// adjust tree
222 
223 	gIODTSharedInterrupts = OSDictionary::withCapacity(4);
224 	allInts = OSDictionary::withCapacity(4);
225 	intMap = false;
226 	regIter = IORegistryIterator::iterateOver( gIODTPlane,
227 	    kIORegistryIterateRecursively );
228 	assert( regIter && allInts && gIODTSharedInterrupts );
229 	if (regIter && allInts && gIODTSharedInterrupts) {
230 		while ((child = regIter->getNextObject())) {
231 			IODTMapInterruptsSharing( child, allInts );
232 			if (!intMap && child->getProperty( gIODTInterruptParentKey)) {
233 				intMap = true;
234 			}
235 			if (!strcmp("sep", child->getName())
236 			    || !strcmp("aop", child->getName())
237 			    || !strcmp("disp0", child->getName())) {
238 				uint32_t aotFlags = 1;
239 				child->setProperty("aot-power", &aotFlags, sizeof(aotFlags));
240 			}
241 		}
242 		regIter->release();
243 	}
244 
245 #if IODTSUPPORTDEBUG
246 	parent->setProperty("allInts", allInts);
247 	parent->setProperty("sharedInts", gIODTSharedInterrupts);
248 
249 	regIter = IORegistryIterator::iterateOver( gIODTPlane,
250 	    kIORegistryIterateRecursively );
251 	if (regIter) {
252 		while ((child = regIter->getNextObject())) {
253 			OSArray *
254 			    array = OSDynamicCast(OSArray, child->getProperty( gIOInterruptSpecifiersKey ));
255 			for (UInt32 i = 0; array && (i < array->getCount()); i++) {
256 				IOOptionBits options;
257 				IOReturn ret = IODTGetInterruptOptions( child, i, &options );
258 				if ((ret != kIOReturnSuccess) || options) {
259 					IOLog("%s[%ld] %ld (%x)\n", child->getName(), i, options, ret);
260 				}
261 			}
262 		}
263 		regIter->release();
264 	}
265 #endif
266 
267 	allInts->release();
268 
269 	if (intMap) {
270 		// set a key in the root to indicate we found NW interrupt mapping
271 		parent->setProperty( gIODTNWInterruptMappingKey,
272 		    (OSObject *) gIODTNWInterruptMappingKey );
273 	}
274 
275 	return parent;
276 }
277 #endif
278 
279 int
280 IODTGetLoaderInfo( const char *key, void **infoAddr, int *infoSize )
281 {
282 	IORegistryEntry             *chosen;
283 	OSData                              *propObj;
284 	dtptr_t                             *propPtr;
285 	unsigned int                propSize;
286 	int ret = -1;
287 
288 	chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane );
289 	if (chosen == NULL) {
290 		return -1;
291 	}
292 
293 	propObj = OSDynamicCast( OSData, chosen->getProperty(key));
294 	if (propObj == NULL) {
295 		goto cleanup;
296 	}
297 
298 	propSize = propObj->getLength();
299 	if (propSize != (2 * sizeof(dtptr_t))) {
300 		goto cleanup;
301 	}
302 
303 	propPtr = (dtptr_t *)propObj->getBytesNoCopy();
304 	if (propPtr == NULL) {
305 		goto cleanup;
306 	}
307 
308 	*infoAddr = (void *)(uintptr_t) (propPtr[0]);
309 	*infoSize = (int)               (propPtr[1]);
310 
311 	ret = 0;
312 
313 cleanup:
314 	chosen->release();
315 
316 	return ret;
317 }
318 
319 void
320 IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize )
321 {
322 	vm_offset_t                 range[2];
323 	IORegistryEntry             *chosen;
324 
325 	range[0] = (vm_offset_t)infoAddr;
326 	range[1] = (vm_offset_t)infoSize;
327 	FreePhysicalMemory( range );
328 
329 	if (key != NULL) {
330 		chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane );
331 		if (chosen != NULL) {
332 			chosen->removeProperty(key);
333 			chosen->release();
334 		}
335 	}
336 }
337 
338 int
339 IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize )
340 {
341 	IORegistryEntry             *defaults;
342 	OSData                      *defaultObj;
343 	unsigned int                defaultSize;
344 
345 	defaults = IORegistryEntry::fromPath( "/defaults", gIODTPlane );
346 	if (defaults == NULL) {
347 		return -1;
348 	}
349 
350 	defaultObj = OSDynamicCast( OSData, defaults->getProperty(key));
351 	if (defaultObj == NULL) {
352 		return -1;
353 	}
354 
355 	defaultSize = defaultObj->getLength();
356 	if (defaultSize > infoSize) {
357 		return -1;
358 	}
359 
360 	memcpy( infoAddr, defaultObj->getBytesNoCopy(), defaultSize );
361 
362 	return 0;
363 }
364 
365 static void
366 FreePhysicalMemory( vm_offset_t * range )
367 {
368 	vm_offset_t virt;
369 
370 	virt = ml_static_ptovirt( range[0] );
371 	if (virt) {
372 		ml_static_mfree( virt, range[1] );
373 	}
374 }
375 
376 static IORegistryEntry *
377 MakeReferenceTable( DTEntry dtEntry, bool copy )
378 {
379 	IORegistryEntry             *regEntry;
380 	OSDictionary                *propTable;
381 	const OSSymbol              *nameKey;
382 	OSData                              *data;
383 	const OSSymbol              *sym;
384 	OpaqueDTPropertyIterator    dtIter;
385 	void const                  *prop;
386 	unsigned int                propSize;
387 	char const                                      *name;
388 	char                                location[32];
389 	bool                                noLocation = true;
390 	bool                                kernelOnly;
391 
392 	regEntry = new IOService;
393 
394 	if (regEntry && (false == regEntry->init())) {
395 		regEntry->release();
396 		regEntry = NULL;
397 	}
398 
399 	if (regEntry &&
400 	    (kSuccess == SecureDTInitPropertyIterator( dtEntry, &dtIter))) {
401 		kernelOnly = (kSuccess == SecureDTGetProperty(dtEntry, "kernel-only", &prop, &propSize));
402 		propTable = regEntry->getPropertyTable();
403 
404 		while (kSuccess == SecureDTIterateProperties( &dtIter, &name)) {
405 			if (kSuccess != SecureDTGetProperty( dtEntry, name, &prop, &propSize )) {
406 				continue;
407 			}
408 
409 			if (copy) {
410 				nameKey = OSSymbol::withCString(name);
411 				data = OSData::withBytes(prop, propSize);
412 			} else {
413 				nameKey = OSSymbol::withCStringNoCopy(name);
414 				/* There is no OSDataConst or other way to indicate
415 				 * that the OSData is actually immutable. But CTRR
416 				 * will catch any write attempts. */
417 				data = OSData::withBytesNoCopy((void**)(uintptr_t)prop, propSize);
418 			}
419 			assert( nameKey && data );
420 
421 			if (kernelOnly) {
422 				data->setSerializable(false);
423 			}
424 
425 			propTable->setObject( nameKey, data);
426 			data->release();
427 			nameKey->release();
428 
429 			if (nameKey == gIODTNameKey) {
430 				if (copy) {
431 					sym = OSSymbol::withCString((const char *) prop);
432 				} else {
433 					sym = OSSymbol::withCStringNoCopy((const char *) prop);
434 				}
435 				regEntry->setName( sym );
436 				sym->release();
437 			} else if (nameKey == gIODTUnitKey) {
438 				// all OF strings are null terminated... except this one
439 				if (propSize >= (int) sizeof(location)) {
440 					propSize = sizeof(location) - 1;
441 				}
442 				strncpy( location, (const char *) prop, propSize );
443 				location[propSize] = 0;
444 				regEntry->setLocation( location );
445 				propTable->removeObject( gIODTUnitKey );
446 				noLocation = false;
447 			} else if (noLocation && (!strncmp(name, "reg", sizeof("reg")))) {
448 				// default location - override later
449 				snprintf(location, sizeof(location), "%X", *((uint32_t *) prop));
450 				regEntry->setLocation( location );
451 			}
452 		}
453 	}
454 
455 	return regEntry;
456 }
457 
458 static void
459 AddPHandle( IORegistryEntry * regEntry )
460 {
461 	OSData *    data;
462 
463 	if (regEntry->getProperty( gIODTInterruptCellKey)
464 	    && (data = OSDynamicCast( OSData, regEntry->getProperty( gIODTPHandleKey )))) {
465 		// a possible interrupt-parent
466 		gIODTPHandles->setObject( data );
467 		gIODTPHandleMap->setObject( regEntry );
468 	}
469 }
470 
471 static IORegistryEntry *
472 FindPHandle( UInt32 phandle )
473 {
474 	OSData                      *data;
475 	IORegistryEntry *regEntry = NULL;
476 	int                         i;
477 
478 	for (i = 0; (data = (OSData *)gIODTPHandles->getObject( i )); i++) {
479 		if (phandle == *((UInt32 *)data->getBytesNoCopy())) {
480 			regEntry = (IORegistryEntry *)
481 			    gIODTPHandleMap->getObject( i );
482 			break;
483 		}
484 	}
485 
486 	return regEntry;
487 }
488 
489 static bool
490 GetUInt32( IORegistryEntry * regEntry, const OSSymbol * name,
491     UInt32 * value )
492 {
493 	OSObject * obj;
494 	OSData   * data;
495 	bool       result;
496 
497 	if (!(obj = regEntry->copyProperty(name))) {
498 		return false;
499 	}
500 
501 	result = ((data = OSDynamicCast(OSData, obj)) && (sizeof(UInt32) == data->getLength()));
502 	if (result) {
503 		*value = *((UInt32 *) data->getBytesNoCopy());
504 	}
505 
506 	obj->release();
507 	return result;
508 }
509 
510 static IORegistryEntry *
511 IODTFindInterruptParent( IORegistryEntry * regEntry, IOItemCount index )
512 {
513 	IORegistryEntry *   parent;
514 	UInt32              phandle;
515 	OSData          *   data;
516 	unsigned int        len;
517 
518 	if ((data = OSDynamicCast( OSData, regEntry->getProperty( gIODTInterruptParentKey )))
519 	    && (sizeof(UInt32) <= (len = data->getLength()))) {
520 		if (((index + 1) * sizeof(UInt32)) > len) {
521 			index = 0;
522 		}
523 		phandle = ((UInt32 *) data->getBytesNoCopy())[index];
524 		parent = FindPHandle( phandle );
525 	} else if (NULL == regEntry->getProperty( "interrupt-controller")) {
526 		parent = regEntry->getParentEntry( gIODTPlane);
527 	} else {
528 		parent = NULL;
529 	}
530 
531 	return parent;
532 }
533 
534 const OSSymbol *
535 IODTInterruptControllerName( IORegistryEntry * regEntry )
536 {
537 	const OSSymbol      *sym;
538 	UInt32              phandle;
539 	bool                ok;
540 	char                buf[48];
541 
542 	ok = GetUInt32( regEntry, gIODTPHandleKey, &phandle);
543 	assert( ok );
544 
545 	if (ok) {
546 		snprintf(buf, sizeof(buf), "IOInterruptController%08X", (uint32_t)phandle);
547 		sym = OSSymbol::withCString( buf );
548 	} else {
549 		sym = NULL;
550 	}
551 
552 	return sym;
553 }
554 
555 #define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; }
556 
557 static void
558 IODTGetICellCounts( IORegistryEntry * regEntry,
559     UInt32 * iCellCount, UInt32 * aCellCount)
560 {
561 	if (!GetUInt32( regEntry, gIODTInterruptCellKey, iCellCount)) {
562 		unexpected( *iCellCount = 1 );
563 	}
564 	if (!GetUInt32( regEntry, gIODTAddressCellKey, aCellCount)) {
565 		*aCellCount = 0;
566 	}
567 }
568 
569 static UInt32
570 IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec, UInt32 index,
571     LIBKERN_RETURNS_RETAINED OSData ** spec,
572     LIBKERN_RETURNS_RETAINED const OSSymbol ** controller )
573 {
574 	IORegistryEntry *parent = NULL;
575 	OSData                      *data;
576 	UInt32                      *addrCmp;
577 	UInt32                      *maskCmp;
578 	UInt32                      *map;
579 	UInt32                      *endMap;
580 	UInt32                      acells, icells, pacells, picells, cell;
581 	UInt32                      i, original_icells;
582 	bool                        cmp, ok = false;
583 
584 	parent = IODTFindInterruptParent( regEntry, index );
585 	IODTGetICellCounts( parent, &icells, &acells );
586 	addrCmp = NULL;
587 	if (acells) {
588 		data = OSDynamicCast( OSData, regEntry->getProperty( "reg" ));
589 		if (data && (data->getLength() >= (acells * sizeof(UInt32)))) {
590 			addrCmp = (UInt32 *) data->getBytesNoCopy();
591 		}
592 	}
593 	original_icells = icells;
594 	regEntry = parent;
595 
596 	do {
597 #if IODTSUPPORTDEBUG
598 		kprintf("IODTMapOneInterrupt: current regEntry name %s\n", regEntry->getName());
599 		kprintf("acells - icells: ");
600 		for (i = 0; i < acells; i++) {
601 			kprintf("0x%08X ", addrCmp[i]);
602 		}
603 		kprintf("- ");
604 		for (i = 0; i < icells; i++) {
605 			kprintf("0x%08X ", intSpec[i]);
606 		}
607 		kprintf("\n");
608 #endif
609 
610 		if (parent && (data = OSDynamicCast( OSData,
611 		    regEntry->getProperty( "interrupt-controller")))) {
612 			// found a controller - don't want to follow cascaded controllers
613 			parent = NULL;
614 			*spec = OSData::withBytesNoCopy((void *) intSpec,
615 			    icells * sizeof(UInt32));
616 			*controller = IODTInterruptControllerName( regEntry );
617 			ok = (*spec && *controller);
618 		} else if (parent && (data = OSDynamicCast( OSData,
619 		    regEntry->getProperty( "interrupt-map")))) {
620 			// interrupt-map
621 			map = (UInt32 *) data->getBytesNoCopy();
622 			endMap = map + (data->getLength() / sizeof(UInt32));
623 			data = OSDynamicCast( OSData, regEntry->getProperty( "interrupt-map-mask" ));
624 			if (data && (data->getLength() >= ((acells + icells) * sizeof(UInt32)))) {
625 				maskCmp = (UInt32 *) data->getBytesNoCopy();
626 			} else {
627 				maskCmp = NULL;
628 			}
629 
630 #if IODTSUPPORTDEBUG
631 			if (maskCmp) {
632 				kprintf("        maskCmp: ");
633 				for (i = 0; i < acells + icells; i++) {
634 					if (i == acells) {
635 						kprintf("- ");
636 					}
637 					kprintf("0x%08X ", maskCmp[i]);
638 				}
639 				kprintf("\n");
640 				kprintf("         masked: ");
641 				for (i = 0; i < acells + icells; i++) {
642 					if (i == acells) {
643 						kprintf("- ");
644 					}
645 					kprintf("0x%08X ", ((i < acells) ? addrCmp[i] : intSpec[i - acells]) & maskCmp[i]);
646 				}
647 				kprintf("\n");
648 			} else {
649 				kprintf("no maskCmp\n");
650 			}
651 #endif
652 			do {
653 #if IODTSUPPORTDEBUG
654 				kprintf("            map: ");
655 				for (i = 0; i < acells + icells; i++) {
656 					if (i == acells) {
657 						kprintf("- ");
658 					}
659 					kprintf("0x%08X ", map[i]);
660 				}
661 				kprintf("\n");
662 #endif
663 				for (i = 0, cmp = true; cmp && (i < (acells + icells)); i++) {
664 					cell = (i < acells) ? addrCmp[i] : intSpec[i - acells];
665 					if (maskCmp) {
666 						cell &= maskCmp[i];
667 					}
668 					cmp = (cell == map[i]);
669 				}
670 
671 				map += acells + icells;
672 				if (NULL == (parent = FindPHandle( *(map++)))) {
673 					unexpected(break);
674 				}
675 
676 				IODTGetICellCounts( parent, &picells, &pacells );
677 				if (cmp) {
678 					addrCmp = map;
679 					intSpec = map + pacells;
680 					regEntry = parent;
681 				} else {
682 					map += pacells + picells;
683 				}
684 			} while (!cmp && (map < endMap));
685 			if (!cmp) {
686 				parent = NULL;
687 			}
688 		}
689 
690 		if (parent) {
691 			IODTGetICellCounts( parent, &icells, &acells );
692 			regEntry = parent;
693 		}
694 	} while (parent);
695 
696 	return ok ? original_icells : 0;
697 }
698 
699 IOReturn
700 IODTGetInterruptOptions( IORegistryEntry * regEntry, int source, IOOptionBits * options )
701 {
702 	OSArray *   controllers;
703 	OSArray *   specifiers;
704 	OSArray *   shared;
705 	OSObject *  spec;
706 	OSObject *  oneSpec;
707 
708 	*options = 0;
709 
710 	controllers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptControllersKey));
711 	specifiers  = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptSpecifiersKey));
712 
713 	if (!controllers || !specifiers) {
714 		return kIOReturnNoInterrupt;
715 	}
716 
717 	shared = (OSArray *) gIODTSharedInterrupts->getObject(
718 		(const OSSymbol *) controllers->getObject(source));
719 	if (!shared) {
720 		return kIOReturnSuccess;
721 	}
722 
723 	spec = specifiers->getObject(source);
724 	if (!spec) {
725 		return kIOReturnNoInterrupt;
726 	}
727 
728 	for (unsigned int i = 0;
729 	    (oneSpec = shared->getObject(i))
730 	    && (!oneSpec->isEqualTo(spec));
731 	    i++) {
732 	}
733 
734 	if (oneSpec) {
735 		*options = kIODTInterruptShared;
736 	}
737 
738 	return kIOReturnSuccess;
739 }
740 
741 static bool
742 IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts )
743 {
744 	IORegistryEntry *   parent;
745 	OSData *            local;
746 	OSData *            local2;
747 	UInt32 *            localBits;
748 	UInt32 *            localEnd;
749 	IOItemCount         index;
750 	OSData *            map;
751 	OSObject *          oneMap;
752 	OSArray *           mapped;
753 	OSArray *           controllerInts;
754 	const OSSymbol *    controller = NULL;
755 	OSArray *           controllers;
756 	UInt32              skip = 1;
757 	bool                ok, nw;
758 
759 	nw = (NULL == (local = OSDynamicCast( OSData,
760 	    regEntry->getProperty( gIODTAAPLInterruptsKey))));
761 	if (nw && (NULL == (local = OSDynamicCast( OSData,
762 	    regEntry->getProperty( "interrupts"))))) {
763 		return true;  // nothing to see here
764 	}
765 	if (nw && (parent = regEntry->getParentEntry( gIODTPlane))) {
766 		// check for bridges on old world
767 		if ((local2 = OSDynamicCast( OSData,
768 		    parent->getProperty( gIODTAAPLInterruptsKey)))) {
769 			local = local2;
770 			nw = false;
771 		}
772 	}
773 
774 	localBits = (UInt32 *) local->getBytesNoCopy();
775 	localEnd = localBits + (local->getLength() / sizeof(UInt32));
776 	index = 0;
777 	mapped = OSArray::withCapacity( 1 );
778 	controllers = OSArray::withCapacity( 1 );
779 
780 	ok = (mapped && controllers);
781 
782 	if (ok) {
783 		do {
784 			if (nw) {
785 				skip = IODTMapOneInterrupt( regEntry, localBits, index, &map, &controller );
786 				if (0 == skip) {
787 					IOLog("%s: error mapping interrupt[%d]\n",
788 					    regEntry->getName(), mapped->getCount());
789 					break;
790 				}
791 			} else {
792 				map = OSData::withData( local, mapped->getCount() * sizeof(UInt32),
793 				    sizeof(UInt32));
794 				controller = gIODTDefaultInterruptController;
795 				controller->retain();
796 			}
797 
798 			index++;
799 			localBits += skip;
800 			mapped->setObject( map );
801 			controllers->setObject( controller );
802 
803 			if (allInts) {
804 				controllerInts = (OSArray *) allInts->getObject( controller );
805 				if (controllerInts) {
806 					for (unsigned int i = 0; (oneMap = controllerInts->getObject(i)); i++) {
807 						if (map->isEqualTo(oneMap)) {
808 							controllerInts = (OSArray *) gIODTSharedInterrupts->getObject( controller );
809 							if (controllerInts) {
810 								controllerInts->setObject(map);
811 							} else {
812 								controllerInts = OSArray::withObjects((const OSObject **) &map, 1, 4 );
813 								if (controllerInts) {
814 									gIODTSharedInterrupts->setObject( controller, controllerInts );
815 									controllerInts->release();
816 								}
817 							}
818 							break;
819 						}
820 					}
821 					if (!oneMap) {
822 						controllerInts->setObject(map);
823 					}
824 				} else {
825 					controllerInts = OSArray::withObjects((const OSObject **) &map, 1, 16 );
826 					if (controllerInts) {
827 						allInts->setObject( controller, controllerInts );
828 						controllerInts->release();
829 					}
830 				}
831 			}
832 
833 			map->release();
834 			controller->release();
835 		} while (localBits < localEnd);
836 	}
837 
838 	ok &= (localBits == localEnd);
839 
840 	if (ok) {
841 		// store results
842 		ok  = regEntry->setProperty( gIOInterruptControllersKey, controllers);
843 		ok &= regEntry->setProperty( gIOInterruptSpecifiersKey, mapped);
844 	}
845 
846 	if (controllers) {
847 		controllers->release();
848 	}
849 	if (mapped) {
850 		mapped->release();
851 	}
852 
853 	return ok;
854 }
855 
856 bool
857 IODTMapInterrupts( IORegistryEntry * regEntry )
858 {
859 	return IODTMapInterruptsSharing( regEntry, NULL );
860 }
861 
862 /*
863  */
864 
865 static bool
866 CompareKey( OSString * key,
867     const IORegistryEntry * table, const OSSymbol * propName,
868     LIBKERN_RETURNS_RETAINED OSString ** matchingName )
869 {
870 	OSObject            *prop;
871 	OSData                      *data;
872 	OSString            *string;
873 	const char          *ckey;
874 	UInt32                      keyLen;
875 	UInt32          nlen;
876 	const char          *names;
877 	const char          *lastName;
878 	bool                        wild;
879 	bool                        matched;
880 	const char          *result = NULL;
881 
882 	if (NULL == (prop = table->copyProperty( propName ))) {
883 		return 0;
884 	}
885 
886 	if ((data = OSDynamicCast( OSData, prop ))) {
887 		names = (const char *) data->getBytesNoCopy();
888 		lastName = names + data->getLength();
889 	} else if ((string = OSDynamicCast( OSString, prop ))) {
890 		names = string->getCStringNoCopy();
891 		lastName = names + string->getLength() + 1;
892 	} else {
893 		names = NULL;
894 	}
895 
896 	if (names) {
897 		ckey = key->getCStringNoCopy();
898 		keyLen = key->getLength();
899 		wild = ('*' == key->getChar( keyLen - 1 ));
900 
901 		do {
902 			// for each name in the property
903 			nlen = (unsigned int) strnlen(names, lastName - names);
904 			if (wild) {
905 				matched = ((nlen >= (keyLen - 1)) && (0 == strncmp(ckey, names, keyLen - 1)));
906 			} else {
907 				matched = (keyLen == nlen) && (0 == strncmp(ckey, names, keyLen));
908 			}
909 
910 			if (matched) {
911 				result = names;
912 			}
913 
914 			names = names + nlen + 1;
915 		} while ((names < lastName) && (false == matched));
916 	}
917 
918 	if (result && matchingName) {
919 		*matchingName = OSString::withCString( result );
920 	}
921 
922 	if (prop) {
923 		prop->release();
924 	}
925 
926 	return result != NULL;
927 }
928 
929 
930 bool
931 IODTCompareNubName( const IORegistryEntry * regEntry,
932     OSString * name, OSString ** matchingName )
933 {
934 	bool matched;
935 
936 	matched = CompareKey( name, regEntry, gIODTNameKey, matchingName)
937 	    || CompareKey( name, regEntry, gIODTCompatibleKey, matchingName)
938 	    || CompareKey( name, regEntry, gIODTTypeKey, matchingName)
939 	    || CompareKey( name, regEntry, gIODTModelKey, matchingName);
940 
941 	return matched;
942 }
943 
944 bool
945 IODTCompareNubName( const IORegistryEntry * regEntry,
946     OSString * name, OSSharedPtr<OSString>& matchingName )
947 {
948 	OSString* matchingNameRaw = NULL;
949 	bool result = IODTCompareNubName(regEntry, name, &matchingNameRaw);
950 	matchingName.reset(matchingNameRaw, OSNoRetain);
951 	return result;
952 }
953 
954 bool
955 IODTMatchNubWithKeys( IORegistryEntry * regEntry,
956     const char * keys )
957 {
958 	OSObject    *obj;
959 	bool                result = false;
960 
961 	obj = OSUnserialize( keys, NULL );
962 
963 	if (obj) {
964 		result = regEntry->compareNames( obj );
965 		obj->release();
966 	}
967 #if DEBUG
968 	else {
969 		IOLog("Couldn't unserialize %s\n", keys );
970 	}
971 #endif
972 
973 	return result;
974 }
975 
976 OSCollectionIterator *
977 IODTFindMatchingEntries( IORegistryEntry * from,
978     IOOptionBits options, const char * keys )
979 {
980 	OSSet                                       *result = NULL;
981 	IORegistryEntry                     *next;
982 	IORegistryIterator          *iter;
983 	OSCollectionIterator        *cIter;
984 	bool                                        cmp;
985 	bool                                        minus = options & kIODTExclusive;
986 
987 
988 	iter = IORegistryIterator::iterateOver( from, gIODTPlane,
989 	    (options & kIODTRecursive) ? kIORegistryIterateRecursively : 0 );
990 	if (iter) {
991 		do {
992 			if (result) {
993 				result->release();
994 			}
995 			result = OSSet::withCapacity( 3 );
996 			if (!result) {
997 				break;
998 			}
999 
1000 			iter->reset();
1001 			while ((next = iter->getNextObject())) {
1002 				// Look for existence of a debug property to skip
1003 				if (next->getProperty("AAPL,ignore")) {
1004 					continue;
1005 				}
1006 
1007 				if (keys) {
1008 					cmp = IODTMatchNubWithKeys( next, keys );
1009 					if ((minus && (false == cmp))
1010 					    || ((false == minus) && (false != cmp))) {
1011 						result->setObject( next);
1012 					}
1013 				} else {
1014 					result->setObject( next);
1015 				}
1016 			}
1017 		} while (!iter->isValid());
1018 
1019 		iter->release();
1020 	}
1021 
1022 	cIter = OSCollectionIterator::withCollection( result);
1023 	if (result) {
1024 		result->release();
1025 	}
1026 
1027 	return cIter;
1028 }
1029 
1030 
1031 struct IODTPersistent {
1032 	IODTCompareAddressCellFunc  compareFunc;
1033 };
1034 
1035 void
1036 IODTSetResolving( IORegistryEntry *        regEntry,
1037     IODTCompareAddressCellFunc      compareFunc,
1038     IODTNVLocationFunc              locationFunc __unused )
1039 {
1040 	IODTPersistent       persist;
1041 	IODTPersistent * entry;
1042 	OSNumber       * num;
1043 	unsigned int     index, count;
1044 
1045 	IOLockLock(gIODTResolversLock);
1046 
1047 	count = (gIODTResolvers->getLength() / sizeof(IODTPersistent));
1048 	entry = (typeof(entry))gIODTResolvers->getBytesNoCopy();
1049 	for (index = 0; index < count; index++) {
1050 		if (compareFunc == entry->compareFunc) {
1051 			break;
1052 		}
1053 		entry++;
1054 	}
1055 	if (index == count) {
1056 		persist.compareFunc = compareFunc;
1057 		if (!gIODTResolvers->appendBytes(&persist, sizeof(IODTPersistent))) {
1058 			panic("IODTSetResolving");
1059 		}
1060 	}
1061 
1062 	IOLockUnlock(gIODTResolversLock);
1063 
1064 	num = OSNumber::withNumber(index, 32);
1065 	regEntry->setProperty(gIODTPersistKey, num);
1066 	OSSafeReleaseNULL(num);
1067 
1068 	return;
1069 }
1070 
1071 #if  defined(__arm64__)
1072 static SInt64
1073 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
1074 {
1075 	SInt64 diff = 0;
1076 
1077 	if (cellCount == 2) {
1078 		diff = IOPhysical32(left[1], left[0]) - IOPhysical32(right[1], right[0]);
1079 	} else if (cellCount == 1) {
1080 		diff = (left[0] - right[0]);
1081 	} else {
1082 		panic("DefaultCompare only knows how to handle 1 or 2 cells.");
1083 	}
1084 
1085 	return diff;
1086 }
1087 #elif defined(__arm__) || defined(__i386__) || defined(__x86_64__)
1088 static SInt32
1089 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
1090 {
1091 	cellCount--;
1092 	return left[cellCount] - right[cellCount];
1093 }
1094 #else
1095 #error Unknown architecture.
1096 #endif
1097 
1098 static void
1099 AddLengthToCells( UInt32 numCells, UInt32 *cells, UInt64 offset)
1100 {
1101 	if (numCells == 1) {
1102 		cells[0] += (UInt32)offset;
1103 	} else {
1104 #if defined(__arm64__) || defined(__arm__)
1105 		UInt64 sum = cells[numCells - 2] + offset;
1106 		cells[numCells - 2] = (UInt32)sum;
1107 		if (sum > UINT32_MAX) {
1108 			cells[numCells - 1] += (UInt32)(sum >> 32);
1109 		}
1110 #else
1111 		UInt64 sum = cells[numCells - 1] + offset;
1112 		cells[numCells - 1] = (UInt32)sum;
1113 		if (sum > UINT32_MAX) {
1114 			cells[numCells - 2] += (UInt32)(sum >> 32);
1115 		}
1116 #endif
1117 	}
1118 }
1119 
1120 static IOPhysicalAddress
1121 CellsValue( UInt32 numCells, UInt32 *cells)
1122 {
1123 	if (numCells == 1) {
1124 		return IOPhysical32( 0, cells[0] );
1125 	} else {
1126 #if defined(__arm64__) || defined(arm)
1127 		return IOPhysical32( cells[numCells - 1], cells[numCells - 2] );
1128 #else
1129 		return IOPhysical32( cells[numCells - 2], cells[numCells - 1] );
1130 #endif
1131 	}
1132 }
1133 
1134 void
1135 IODTGetCellCounts( IORegistryEntry * regEntry,
1136     UInt32 * sizeCount, UInt32 * addressCount)
1137 {
1138 	if (!GetUInt32( regEntry, gIODTSizeCellKey, sizeCount)) {
1139 		*sizeCount = 1;
1140 	}
1141 	if (!GetUInt32( regEntry, gIODTAddressCellKey, addressCount)) {
1142 		*addressCount = 2;
1143 	}
1144 	return;
1145 }
1146 
1147 // Given addr & len cells from our child, find it in our ranges property, then
1148 // look in our parent to resolve the base of the range for us.
1149 
1150 // Range[]: child-addr  our-addr  child-len
1151 // #cells:    child       ours     child
1152 
1153 bool
1154 IODTResolveAddressCell( IORegistryEntry * startEntry,
1155     UInt32 cellsIn[],
1156     IOPhysicalAddress * phys, IOPhysicalLength * lenOut )
1157 {
1158 	IORegistryEntry     * parent;
1159 	IORegistryEntry * regEntry;
1160 	OSData          * prop;
1161 	OSNumber    * num;
1162 	unsigned int  index, count;
1163 	// cells in addresses at regEntry
1164 	UInt32              sizeCells, addressCells;
1165 	// cells in addresses below regEntry
1166 	UInt32              childSizeCells, childAddressCells;
1167 	UInt32              childCells;
1168 	UInt32              cell[8], propLen;
1169 	UInt64              offset = 0;
1170 	UInt32              endCell[8];
1171 	UInt32              *range;
1172 	UInt32              *lookRange;
1173 	UInt32              *startRange;
1174 	UInt32              *endRanges;
1175 	bool                ok = true;
1176 	SInt64              diff, diff2, endDiff;
1177 	UInt64              len, rangeLen;
1178 
1179 	IODTPersistent      *persist;
1180 	IODTCompareAddressCellFunc  compare;
1181 
1182 	regEntry = startEntry;
1183 	IODTGetCellCounts( regEntry, &childSizeCells, &childAddressCells );
1184 	childCells = childAddressCells + childSizeCells;
1185 
1186 	if (childCells > sizeof(cell) / sizeof(cell[0])) {
1187 		panic("IODTResolveAddressCell: Invalid device tree (%u,%u)", (uint32_t)childAddressCells, (uint32_t)childSizeCells);
1188 	}
1189 
1190 	bcopy( cellsIn, cell, sizeof(UInt32) * childCells );
1191 	*lenOut = CellsValue( childSizeCells, cellsIn + childAddressCells );
1192 
1193 	do{
1194 		prop = OSDynamicCast( OSData, regEntry->getProperty( gIODTRangeKey ));
1195 		if (NULL == prop) {
1196 			/* end of the road */
1197 			*phys = CellsValue( childAddressCells, cell );
1198 			*phys += offset;
1199 			if (regEntry != startEntry) {
1200 				regEntry->release();
1201 			}
1202 			break;
1203 		}
1204 
1205 		parent = regEntry->copyParentEntry( gIODTPlane );
1206 		IODTGetCellCounts( parent, &sizeCells, &addressCells );
1207 
1208 		if ((propLen = prop->getLength())) {
1209 			// search
1210 			startRange = (UInt32 *) prop->getBytesNoCopy();
1211 			range = startRange;
1212 			endRanges = range + (propLen / sizeof(UInt32));
1213 
1214 			compare = NULL;
1215 			num = OSDynamicCast(OSNumber, regEntry->getProperty(gIODTPersistKey));
1216 			if (num) {
1217 				IOLockLock(gIODTResolversLock);
1218 				index = num->unsigned32BitValue();
1219 				count = gIODTResolvers->getLength() / sizeof(IODTPersistent);
1220 				if (index < count) {
1221 					persist = ((IODTPersistent *) gIODTResolvers->getBytesNoCopy()) + index;
1222 					compare = persist->compareFunc;
1223 				}
1224 				IOLockUnlock(gIODTResolversLock);
1225 			}
1226 
1227 			if (!compare && (addressCells == childAddressCells)) {
1228 				compare = DefaultCompare;
1229 			}
1230 			if (!compare) {
1231 				panic("There is no mixed comparison function yet...");
1232 			}
1233 
1234 			for (ok = false;
1235 			    range < endRanges;
1236 			    range += (childCells + addressCells)) {
1237 				// is cell start within range?
1238 				diff = (*compare)( childAddressCells, cell, range );
1239 
1240 				if (childAddressCells > sizeof(endCell) / sizeof(endCell[0])) {
1241 					panic("IODTResolveAddressCell: Invalid device tree (%u)", (uint32_t)childAddressCells);
1242 				}
1243 
1244 				bcopy(range, endCell, childAddressCells * sizeof(UInt32));
1245 
1246 				rangeLen = CellsValue(childSizeCells, range + childAddressCells + addressCells);
1247 				AddLengthToCells(childAddressCells, endCell, rangeLen);
1248 
1249 				diff2 = (*compare)( childAddressCells, cell, endCell );
1250 
1251 				// if start of cell < start of range, or end of range >= start of cell, skip
1252 				if ((diff < 0) || (diff2 >= 0)) {
1253 					continue;
1254 				}
1255 
1256 				len = CellsValue(childSizeCells, cell + childAddressCells);
1257 				ok = (0 == len);
1258 
1259 				if (!ok) {
1260 					// search for cell end
1261 					bcopy(cell, endCell, childAddressCells * sizeof(UInt32));
1262 
1263 					AddLengthToCells(childAddressCells, endCell, len - 1);
1264 
1265 					for (lookRange = startRange;
1266 					    lookRange < endRanges;
1267 					    lookRange += (childCells + addressCells)) {
1268 						// make sure end of cell >= range start
1269 						endDiff = (*compare)( childAddressCells, endCell, lookRange );
1270 						if (endDiff < 0) {
1271 							continue;
1272 						}
1273 
1274 						UInt64 rangeStart = CellsValue(addressCells, range + childAddressCells);
1275 						UInt64 lookRangeStart = CellsValue(addressCells, lookRange + childAddressCells);
1276 						if ((endDiff - len + 1 + lookRangeStart) == (diff + rangeStart)) {
1277 							ok = true;
1278 							break;
1279 						}
1280 					}
1281 					if (!ok) {
1282 						continue;
1283 					}
1284 				}
1285 				offset += diff;
1286 				break;
1287 			}
1288 
1289 			if (addressCells + sizeCells > sizeof(cell) / sizeof(cell[0])) {
1290 				panic("IODTResolveAddressCell: Invalid device tree (%u, %u)", (uint32_t)addressCells, (uint32_t)sizeCells);
1291 			}
1292 
1293 			// Get the physical start of the range from our parent
1294 			bcopy( range + childAddressCells, cell, sizeof(UInt32) * addressCells );
1295 			bzero( cell + addressCells, sizeof(UInt32) * sizeCells );
1296 		} /* else zero length range => pass thru to parent */
1297 
1298 		if (regEntry != startEntry) {
1299 			regEntry->release();
1300 		}
1301 		regEntry                = parent;
1302 		childSizeCells          = sizeCells;
1303 		childAddressCells       = addressCells;
1304 		childCells              = childAddressCells + childSizeCells;
1305 	}while (ok && regEntry);
1306 
1307 	return ok;
1308 }
1309 
1310 
1311 OSArray *
1312 IODTResolveAddressing( IORegistryEntry * regEntry,
1313     const char * addressPropertyName,
1314     IODeviceMemory * parent )
1315 {
1316 	IORegistryEntry             *parentEntry;
1317 	OSData                              *addressProperty;
1318 	UInt32                              sizeCells, addressCells, cells;
1319 	int                                 i, num;
1320 	UInt32                              *reg;
1321 	IOPhysicalAddress   phys;
1322 	IOPhysicalLength    len;
1323 	OSArray                             *array;
1324 	IODeviceMemory              *range;
1325 
1326 	array = NULL;
1327 	do{
1328 		parentEntry = regEntry->copyParentEntry( gIODTPlane );
1329 		addressProperty = (OSData *) regEntry->getProperty( addressPropertyName );
1330 		if ((NULL == addressProperty) || (NULL == parentEntry)) {
1331 			break;
1332 		}
1333 
1334 		IODTGetCellCounts( parentEntry, &sizeCells, &addressCells );
1335 		if (0 == sizeCells) {
1336 			break;
1337 		}
1338 
1339 		cells = sizeCells + addressCells;
1340 		reg = (UInt32 *) addressProperty->getBytesNoCopy();
1341 		num = addressProperty->getLength() / (4 * cells);
1342 
1343 		array = OSArray::withCapacity( 1 );
1344 		if (NULL == array) {
1345 			break;
1346 		}
1347 
1348 		for (i = 0; i < num; i++) {
1349 			if (IODTResolveAddressCell( parentEntry, reg, &phys, &len )) {
1350 				range = NULL;
1351 				if (parent) {
1352 					range = IODeviceMemory::withSubRange( parent,
1353 					    phys - parent->getPhysicalSegment(0, NULL, kIOMemoryMapperNone), len );
1354 				}
1355 				if (NULL == range) {
1356 					range = IODeviceMemory::withRange( phys, len );
1357 				}
1358 				if (range) {
1359 					array->setObject( range );
1360 				}
1361 			}
1362 			reg += cells;
1363 		}
1364 
1365 		regEntry->setProperty( gIODeviceMemoryKey, array);
1366 		array->release(); /* ??? */
1367 	}while (false);
1368 
1369 	OSSafeReleaseNULL(parentEntry);
1370 
1371 	return array;
1372 }
1373 
1374 OSData *
1375 IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber )
1376 {
1377 	IORegistryEntry             *parent;
1378 	OSData                              *data;
1379 	OSData                              *ret = NULL;
1380 	UInt32                              *bits;
1381 	UInt32                              i;
1382 	UInt32              nlen;
1383 	char                                *names;
1384 	char                                *lastName;
1385 	UInt32                              mask;
1386 
1387 	data = (OSData *) regEntry->getProperty("AAPL,slot-name");
1388 	if (data) {
1389 		return data;
1390 	}
1391 
1392 	do{
1393 		parent = regEntry->copyParentEntry( gIODTPlane );
1394 		if (!parent) {
1395 			break;
1396 		}
1397 
1398 		data = OSDynamicCast( OSData, parent->getProperty("slot-names"));
1399 		if (!data) {
1400 			break;
1401 		}
1402 		if (data->getLength() <= 4) {
1403 			break;
1404 		}
1405 
1406 		bits = (UInt32 *) data->getBytesNoCopy();
1407 		mask = *bits;
1408 		if ((0 == (mask & (1 << deviceNumber)))) {
1409 			break;
1410 		}
1411 
1412 		names = (char *)(bits + 1);
1413 		lastName = names + (data->getLength() - 4);
1414 
1415 		for (i = 0; (i <= deviceNumber) && (names < lastName); i++) {
1416 			if (mask & (1 << i)) {
1417 				nlen = 1 + ((unsigned int) strnlen(names, lastName - names));
1418 				if (i == deviceNumber) {
1419 					data = OSData::withBytesNoCopy(names, nlen);
1420 					if (data) {
1421 						regEntry->setProperty("AAPL,slot-name", data);
1422 						ret = data;
1423 						data->release();
1424 					}
1425 				} else {
1426 					names += nlen;
1427 				}
1428 			}
1429 		}
1430 	}while (false);
1431 
1432 	OSSafeReleaseNULL(parent);
1433 
1434 	return ret;
1435 }
1436 
1437 extern "C" IOReturn
1438 IONDRVLibrariesInitialize( IOService * provider )
1439 {
1440 	return kIOReturnUnsupported;
1441 }
1442