]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IODeviceTreeSupport.cpp
xnu-7195.81.3.tar.gz
[apple/xnu.git] / iokit / Kernel / IODeviceTreeSupport.cpp
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 1998-2006 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 27 */
1c79356b
A
28
29#include <IOKit/IODeviceTreeSupport.h>
30#include <libkern/c++/OSContainers.h>
f427ee49 31#include <libkern/c++/OSSharedPtr.h>
1c79356b
A
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
55e303ae
A
39#include <pexpert/device_tree.h>
40
5ba3f43e
A
41#if __arm64__
42typedef UInt64 dtptr_t;
43#else
490019cf 44typedef UInt32 dtptr_t;
5ba3f43e 45#endif
490019cf 46
6d2010ae
A
47#include <machine/machine_routines.h>
48
1c79356b 49extern "C" {
6d2010ae
A
50int IODTGetLoaderInfo( const char *key, void **infoAddr, int *infosize );
51void IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize );
52int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize );
1c79356b
A
53}
54
55#include <IOKit/assert.h>
56
0b4e3aa0 57#define IODTSUPPORTDEBUG 0
1c79356b
A
58
59const IORegistryPlane * gIODTPlane;
60
5ba3f43e
A
61static OSArray * gIODTPHandles;
62static OSArray * gIODTPHandleMap;
63static OSData * gIODTResolvers;
1c79356b 64
0a7de745
A
65const OSSymbol * gIODTNameKey;
66const OSSymbol * gIODTUnitKey;
67const OSSymbol * gIODTCompatibleKey;
68const OSSymbol * gIODTTypeKey;
69const OSSymbol * gIODTModelKey;
f427ee49 70const OSSymbol * gIODTBridgeModelKey;
0a7de745 71const OSSymbol * gIODTTargetTypeKey;
1c79356b 72
0a7de745
A
73const OSSymbol * gIODTSizeCellKey;
74const OSSymbol * gIODTAddressCellKey;
75const OSSymbol * gIODTRangeKey;
1c79356b 76
0a7de745 77const OSSymbol * gIODTPersistKey;
1c79356b 78
0a7de745
A
79const OSSymbol * gIODTDefaultInterruptController;
80const OSSymbol * gIODTAAPLInterruptsKey;
81const OSSymbol * gIODTPHandleKey;
82const OSSymbol * gIODTInterruptCellKey;
83const OSSymbol * gIODTInterruptParentKey;
84const OSSymbol * gIODTNWInterruptMappingKey;
1c79356b 85
0a7de745 86OSDictionary * gIODTSharedInterrupts;
1c79356b 87
5ba3f43e
A
88static IOLock * gIODTResolversLock;
89
1c79356b
A
90static IORegistryEntry * MakeReferenceTable( DTEntry dtEntry, bool copy );
91static void AddPHandle( IORegistryEntry * regEntry );
92static void FreePhysicalMemory( vm_offset_t * range );
91447636 93static bool IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts );
1c79356b 94
f427ee49
A
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__
1c79356b
A
100IORegistryEntry *
101IODeviceTreeAlloc( void * dtTop )
102{
0a7de745
A
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;
f427ee49 115 bool foundDTNode;
0a7de745
A
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" );
f427ee49 125 gIODTBridgeModelKey = OSSymbol::withCStringNoCopy( "bridge-model" );
0a7de745
A
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
1c79356b
A
160 && gIODTAAPLInterruptsKey
161 && gIODTPHandleKey && gIODTInterruptParentKey
5ba3f43e 162 && gIODTPHandles && gIODTPHandleMap && gIODTResolvers && gIODTResolversLock
0a7de745
A
163 && gIODTInterruptCellKey
164 );
165
f427ee49
A
166 foundDTNode = (kSuccess == SecureDTLookupEntry( NULL, "/chosen/memory-map", &mapEntry ))
167 && (kSuccess == SecureDTGetProperty( mapEntry,
168 "DeviceTree", (void const **) &dtMap, &propSize ))
0a7de745
A
169 && ((2 * sizeof(uint32_t)) == propSize);
170
f427ee49
A
171 freeDT = foundDTNode && !SecureDTIsLockedDown();
172
0a7de745
A
173 parent = MakeReferenceTable((DTEntry)dtTop, freeDT );
174
175 stack = OSArray::withObjects((const OSObject **) &parent, 1, 10 );
f427ee49 176 SecureDTInitEntryIterator((DTEntry)dtTop, &iter );
0a7de745
A
177
178 do {
179 parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1);
180 //parent->release();
181 stack->removeObject( stack->getCount() - 1);
182
f427ee49 183 while (kSuccess == SecureDTIterateEntries( &iter, &dtChild)) {
0a7de745
A
184 child = MakeReferenceTable( dtChild, freeDT );
185 child->attachToParent( parent, gIODTPlane);
186
187 AddPHandle( child );
188
f427ee49 189 if (kSuccess == SecureDTEnterEntry( &iter, dtChild)) {
0a7de745
A
190 stack->setObject( parent);
191 parent = child;
192 }
193 // only registry holds retain
194 child->release();
195 }
196 } while (stack->getCount()
f427ee49 197 && (kSuccess == SecureDTExitEntry( &iter, &dtChild)));
0a7de745
A
198
199 stack->release();
f427ee49 200 assert(kSuccess != SecureDTExitEntry(&iter, &dtChild));
0a7de745
A
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
f427ee49 216 SecureDTInit(NULL, 0);
0a7de745
A
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 }
cb323159
A
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 }
0a7de745
A
241 }
242 regIter->release();
243 }
1c79356b 244
91447636 245#if IODTSUPPORTDEBUG
0a7de745
A
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();
91447636 264 }
91447636
A
265#endif
266
0a7de745 267 allInts->release();
91447636 268
0a7de745
A
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 }
1c79356b 274
0a7de745 275 return parent;
1c79356b 276}
f427ee49 277#endif
1c79356b 278
0a7de745
A
279int
280IODTGetLoaderInfo( const char *key, void **infoAddr, int *infoSize )
1c79356b 281{
0a7de745
A
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 );
cb323159 289 if (chosen == NULL) {
0a7de745
A
290 return -1;
291 }
1c79356b 292
0a7de745 293 propObj = OSDynamicCast( OSData, chosen->getProperty(key));
cb323159 294 if (propObj == NULL) {
0a7de745
A
295 goto cleanup;
296 }
1c79356b 297
0a7de745
A
298 propSize = propObj->getLength();
299 if (propSize != (2 * sizeof(dtptr_t))) {
300 goto cleanup;
301 }
1c79356b 302
0a7de745 303 propPtr = (dtptr_t *)propObj->getBytesNoCopy();
cb323159 304 if (propPtr == NULL) {
0a7de745
A
305 goto cleanup;
306 }
1c79356b 307
0a7de745
A
308 *infoAddr = (void *)(uintptr_t) (propPtr[0]);
309 *infoSize = (int) (propPtr[1]);
1c79356b 310
0a7de745 311 ret = 0;
d190cdc3
A
312
313cleanup:
0a7de745 314 chosen->release();
d190cdc3 315
0a7de745 316 return ret;
1c79356b
A
317}
318
0a7de745
A
319void
320IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize )
1c79356b 321{
0a7de745
A
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
cb323159 329 if (key != NULL) {
0a7de745 330 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane );
cb323159 331 if (chosen != NULL) {
0a7de745
A
332 chosen->removeProperty(key);
333 chosen->release();
334 }
335 }
1c79356b
A
336}
337
0a7de745
A
338int
339IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize )
6d2010ae 340{
0a7de745
A
341 IORegistryEntry *defaults;
342 OSData *defaultObj;
343 unsigned int defaultSize;
6d2010ae 344
0a7de745 345 defaults = IORegistryEntry::fromPath( "/defaults", gIODTPlane );
cb323159 346 if (defaults == NULL) {
0a7de745
A
347 return -1;
348 }
6d2010ae 349
0a7de745 350 defaultObj = OSDynamicCast( OSData, defaults->getProperty(key));
cb323159 351 if (defaultObj == NULL) {
0a7de745
A
352 return -1;
353 }
6d2010ae 354
0a7de745
A
355 defaultSize = defaultObj->getLength();
356 if (defaultSize > infoSize) {
357 return -1;
358 }
6d2010ae 359
0a7de745 360 memcpy( infoAddr, defaultObj->getBytesNoCopy(), defaultSize );
6d2010ae 361
0a7de745 362 return 0;
6d2010ae
A
363}
364
0a7de745
A
365static void
366FreePhysicalMemory( vm_offset_t * range )
1c79356b 367{
0a7de745 368 vm_offset_t virt;
1c79356b 369
0a7de745
A
370 virt = ml_static_ptovirt( range[0] );
371 if (virt) {
372 ml_static_mfree( virt, range[1] );
373 }
1c79356b
A
374}
375
376static IORegistryEntry *
377MakeReferenceTable( DTEntry dtEntry, bool copy )
378{
0a7de745
A
379 IORegistryEntry *regEntry;
380 OSDictionary *propTable;
381 const OSSymbol *nameKey;
382 OSData *data;
383 const OSSymbol *sym;
384 OpaqueDTPropertyIterator dtIter;
f427ee49 385 void const *prop;
0a7de745 386 unsigned int propSize;
f427ee49 387 char const *name;
0a7de745
A
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();
cb323159 396 regEntry = NULL;
0a7de745
A
397 }
398
399 if (regEntry &&
f427ee49
A
400 (kSuccess == SecureDTInitPropertyIterator( dtEntry, &dtIter))) {
401 kernelOnly = (kSuccess == SecureDTGetProperty(dtEntry, "kernel-only", &prop, &propSize));
0a7de745
A
402 propTable = regEntry->getPropertyTable();
403
f427ee49
A
404 while (kSuccess == SecureDTIterateProperties( &dtIter, &name)) {
405 if (kSuccess != SecureDTGetProperty( dtEntry, name, &prop, &propSize )) {
0a7de745
A
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);
f427ee49
A
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);
0a7de745
A
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;
1c79356b
A
456}
457
0a7de745
A
458static void
459AddPHandle( IORegistryEntry * regEntry )
1c79356b 460{
0a7de745
A
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 }
1c79356b
A
469}
470
0a7de745
A
471static IORegistryEntry *
472FindPHandle( UInt32 phandle )
1c79356b 473{
0a7de745 474 OSData *data;
cb323159 475 IORegistryEntry *regEntry = NULL;
0a7de745
A
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;
1c79356b
A
487}
488
0a7de745
A
489static bool
490GetUInt32( IORegistryEntry * regEntry, const OSSymbol * name,
491 UInt32 * value )
1c79356b 492{
0a7de745
A
493 OSObject * obj;
494 OSData * data;
495 bool result;
1c79356b 496
0a7de745
A
497 if (!(obj = regEntry->copyProperty(name))) {
498 return false;
499 }
39037602 500
0a7de745
A
501 result = ((data = OSDynamicCast(OSData, obj)) && (sizeof(UInt32) == data->getLength()));
502 if (result) {
503 *value = *((UInt32 *) data->getBytesNoCopy());
504 }
39037602 505
0a7de745
A
506 obj->release();
507 return result;
1c79356b
A
508}
509
0a7de745
A
510static IORegistryEntry *
511IODTFindInterruptParent( IORegistryEntry * regEntry, IOItemCount index )
1c79356b 512{
0a7de745
A
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 );
cb323159 525 } else if (NULL == regEntry->getProperty( "interrupt-controller")) {
0a7de745
A
526 parent = regEntry->getParentEntry( gIODTPlane);
527 } else {
cb323159 528 parent = NULL;
0a7de745
A
529 }
530
531 return parent;
1c79356b
A
532}
533
0a7de745
A
534const OSSymbol *
535IODTInterruptControllerName( IORegistryEntry * regEntry )
1c79356b 536{
0a7de745
A
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 {
cb323159 549 sym = NULL;
0a7de745 550 }
1c79356b 551
0a7de745 552 return sym;
1c79356b
A
553}
554
555#define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; }
556
0a7de745
A
557static void
558IODTGetICellCounts( IORegistryEntry * regEntry,
559 UInt32 * iCellCount, UInt32 * aCellCount)
1c79356b 560{
0a7de745
A
561 if (!GetUInt32( regEntry, gIODTInterruptCellKey, iCellCount)) {
562 unexpected( *iCellCount = 1 );
563 }
564 if (!GetUInt32( regEntry, gIODTAddressCellKey, aCellCount)) {
565 *aCellCount = 0;
566 }
1c79356b
A
567}
568
0a7de745
A
569static UInt32
570IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec, UInt32 index,
cb323159
A
571 LIBKERN_RETURNS_RETAINED OSData ** spec,
572 LIBKERN_RETURNS_RETAINED const OSSymbol ** controller )
1c79356b 573{
cb323159 574 IORegistryEntry *parent = NULL;
0a7de745
A
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 );
cb323159 586 addrCmp = NULL;
0a7de745
A
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 {
0b4e3aa0 597#if IODTSUPPORTDEBUG
0a7de745
A
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");
0b4e3aa0 608#endif
1c79356b 609
0a7de745
A
610 if (parent && (data = OSDynamicCast( OSData,
611 regEntry->getProperty( "interrupt-controller")))) {
612 // found a controller - don't want to follow cascaded controllers
cb323159 613 parent = NULL;
0a7de745
A
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 {
cb323159 627 maskCmp = NULL;
0a7de745 628 }
0b4e3aa0
A
629
630#if IODTSUPPORTDEBUG
0a7de745
A
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 }
0b4e3aa0 651#endif
0a7de745 652 do {
0b4e3aa0 653#if IODTSUPPORTDEBUG
0a7de745
A
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");
0b4e3aa0 662#endif
0a7de745
A
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;
cb323159 672 if (NULL == (parent = FindPHandle( *(map++)))) {
0a7de745
A
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) {
cb323159 686 parent = NULL;
0a7de745
A
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;
1c79356b
A
697}
698
0a7de745
A
699IOReturn
700IODTGetInterruptOptions( IORegistryEntry * regEntry, int source, IOOptionBits * options )
1c79356b 701{
0a7de745
A
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;
91447636
A
739}
740
0a7de745
A
741static bool
742IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts )
91447636 743{
0a7de745
A
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;
cb323159 754 const OSSymbol * controller = NULL;
0a7de745
A
755 OSArray * controllers;
756 UInt32 skip = 1;
757 bool ok, nw;
758
cb323159 759 nw = (NULL == (local = OSDynamicCast( OSData,
0a7de745 760 regEntry->getProperty( gIODTAAPLInterruptsKey))));
cb323159 761 if (nw && (NULL == (local = OSDynamicCast( OSData,
0a7de745
A
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;
1c79356b
A
854}
855
0a7de745
A
856bool
857IODTMapInterrupts( IORegistryEntry * regEntry )
91447636 858{
cb323159 859 return IODTMapInterruptsSharing( regEntry, NULL );
91447636
A
860}
861
1c79356b
A
862/*
863 */
864
39037602 865static bool
1c79356b 866CompareKey( OSString * key,
0a7de745 867 const IORegistryEntry * table, const OSSymbol * propName,
cb323159 868 LIBKERN_RETURNS_RETAINED OSString ** matchingName )
1c79356b 869{
0a7de745
A
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;
cb323159 880 const char *result = NULL;
0a7de745 881
cb323159 882 if (NULL == (prop = table->copyProperty( propName ))) {
0a7de745
A
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 {
cb323159 893 names = NULL;
0a7de745 894 }
1c79356b 895
39037602
A
896 if (names) {
897 ckey = key->getCStringNoCopy();
898 keyLen = key->getLength();
899 wild = ('*' == key->getChar( keyLen - 1 ));
1c79356b 900
39037602
A
901 do {
902 // for each name in the property
f427ee49 903 nlen = (unsigned int) strnlen(names, lastName - names);
0a7de745 904 if (wild) {
39037602 905 matched = ((nlen >= (keyLen - 1)) && (0 == strncmp(ckey, names, keyLen - 1)));
0a7de745 906 } else {
39037602 907 matched = (keyLen == nlen) && (0 == strncmp(ckey, names, keyLen));
0a7de745 908 }
1c79356b 909
0a7de745 910 if (matched) {
39037602 911 result = names;
0a7de745 912 }
1c79356b 913
39037602 914 names = names + nlen + 1;
0a7de745 915 } while ((names < lastName) && (false == matched));
39037602
A
916 }
917
0a7de745
A
918 if (result && matchingName) {
919 *matchingName = OSString::withCString( result );
920 }
39037602 921
0a7de745
A
922 if (prop) {
923 prop->release();
924 }
1c79356b 925
cb323159 926 return result != NULL;
1c79356b
A
927}
928
929
0a7de745
A
930bool
931IODTCompareNubName( const IORegistryEntry * regEntry,
932 OSString * name, OSString ** matchingName )
1c79356b 933{
0a7de745 934 bool matched;
1c79356b 935
0a7de745
A
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);
1c79356b 940
0a7de745 941 return matched;
1c79356b
A
942}
943
f427ee49
A
944bool
945IODTCompareNubName( 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
0a7de745
A
954bool
955IODTMatchNubWithKeys( IORegistryEntry * regEntry,
956 const char * keys )
1c79356b 957{
0a7de745
A
958 OSObject *obj;
959 bool result = false;
1c79356b 960
cb323159 961 obj = OSUnserialize( keys, NULL );
1c79356b 962
0a7de745
A
963 if (obj) {
964 result = regEntry->compareNames( obj );
0b4e3aa0 965 obj->release();
0a7de745 966 }
b0d623f7 967#if DEBUG
0a7de745
A
968 else {
969 IOLog("Couldn't unserialize %s\n", keys );
970 }
1c79356b
A
971#endif
972
0a7de745 973 return result;
1c79356b
A
974}
975
0a7de745
A
976OSCollectionIterator *
977IODTFindMatchingEntries( IORegistryEntry * from,
978 IOOptionBits options, const char * keys )
1c79356b 979{
cb323159 980 OSSet *result = NULL;
0a7de745
A
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;
1c79356b
A
1028}
1029
1030
1031struct IODTPersistent {
0a7de745 1032 IODTCompareAddressCellFunc compareFunc;
1c79356b
A
1033};
1034
0a7de745
A
1035void
1036IODTSetResolving( IORegistryEntry * regEntry,
1037 IODTCompareAddressCellFunc compareFunc,
1038 IODTNVLocationFunc locationFunc __unused )
1c79356b 1039{
0a7de745
A
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;
1c79356b
A
1069}
1070
5ba3f43e 1071#if defined(__arm64__)
0a7de745
A
1072static SInt64
1073DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
5ba3f43e 1074{
0a7de745
A
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 }
5ba3f43e 1084
0a7de745 1085 return diff;
5ba3f43e
A
1086}
1087#elif defined(__arm__) || defined(__i386__) || defined(__x86_64__)
0a7de745
A
1088static SInt32
1089DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
1c79356b 1090{
316670eb 1091 cellCount--;
0a7de745 1092 return left[cellCount] - right[cellCount];
1c79356b 1093}
39236c6e
A
1094#else
1095#error Unknown architecture.
1096#endif
1097
0a7de745
A
1098static void
1099AddLengthToCells( UInt32 numCells, UInt32 *cells, UInt64 offset)
39236c6e 1100{
0a7de745
A
1101 if (numCells == 1) {
1102 cells[0] += (UInt32)offset;
1103 } else {
5ba3f43e 1104#if defined(__arm64__) || defined(__arm__)
0a7de745
A
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 }
5ba3f43e 1110#else
0a7de745
A
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 }
5ba3f43e 1116#endif
0a7de745 1117 }
39236c6e
A
1118}
1119
0a7de745
A
1120static IOPhysicalAddress
1121CellsValue( UInt32 numCells, UInt32 *cells)
39236c6e 1122{
0a7de745
A
1123 if (numCells == 1) {
1124 return IOPhysical32( 0, cells[0] );
1125 } else {
5ba3f43e 1126#if defined(__arm64__) || defined(arm)
0a7de745 1127 return IOPhysical32( cells[numCells - 1], cells[numCells - 2] );
5ba3f43e 1128#else
0a7de745 1129 return IOPhysical32( cells[numCells - 2], cells[numCells - 1] );
5ba3f43e 1130#endif
0a7de745 1131 }
39236c6e 1132}
1c79356b 1133
0a7de745
A
1134void
1135IODTGetCellCounts( IORegistryEntry * regEntry,
1136 UInt32 * sizeCount, UInt32 * addressCount)
1c79356b 1137{
0a7de745
A
1138 if (!GetUInt32( regEntry, gIODTSizeCellKey, sizeCount)) {
1139 *sizeCount = 1;
1140 }
1141 if (!GetUInt32( regEntry, gIODTAddressCellKey, addressCount)) {
1142 *addressCount = 2;
1143 }
1144 return;
1c79356b
A
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
0a7de745
A
1153bool
1154IODTResolveAddressCell( IORegistryEntry * startEntry,
1155 UInt32 cellsIn[],
1156 IOPhysicalAddress * phys, IOPhysicalLength * lenOut )
1c79356b 1157{
0a7de745
A
1158 IORegistryEntry * parent;
1159 IORegistryEntry * regEntry;
1160 OSData * prop;
5ba3f43e
A
1161 OSNumber * num;
1162 unsigned int index, count;
0a7de745
A
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 ));
cb323159 1195 if (NULL == prop) {
0a7de745
A
1196 /* end of the road */
1197 *phys = CellsValue( childAddressCells, cell );
1198 *phys += offset;
1199 if (regEntry != startEntry) {
1200 regEntry->release();
1201 }
1202 break;
5ba3f43e 1203 }
0a7de745
A
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;
1c79356b
A
1308}
1309
1310
0a7de745
A
1311OSArray *
1312IODTResolveAddressing( IORegistryEntry * regEntry,
1313 const char * addressPropertyName,
1314 IODeviceMemory * parent )
1c79356b 1315{
0a7de745
A
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
cb323159 1326 array = NULL;
0a7de745
A
1327 do{
1328 parentEntry = regEntry->copyParentEntry( gIODTPlane );
1329 addressProperty = (OSData *) regEntry->getProperty( addressPropertyName );
cb323159 1330 if ((NULL == addressProperty) || (NULL == parentEntry)) {
0a7de745
A
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 );
cb323159 1344 if (NULL == array) {
0a7de745
A
1345 break;
1346 }
1347
1348 for (i = 0; i < num; i++) {
1349 if (IODTResolveAddressCell( parentEntry, reg, &phys, &len )) {
cb323159 1350 range = NULL;
0a7de745
A
1351 if (parent) {
1352 range = IODeviceMemory::withSubRange( parent,
cb323159 1353 phys - parent->getPhysicalSegment(0, NULL, kIOMemoryMapperNone), len );
0a7de745 1354 }
cb323159 1355 if (NULL == range) {
0a7de745
A
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;
1c79356b
A
1372}
1373
0a7de745
A
1374OSData *
1375IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber )
1c79356b 1376{
0a7de745
A
1377 IORegistryEntry *parent;
1378 OSData *data;
cb323159 1379 OSData *ret = NULL;
0a7de745
A
1380 UInt32 *bits;
1381 UInt32 i;
f427ee49 1382 UInt32 nlen;
0a7de745
A
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)) {
f427ee49 1417 nlen = 1 + ((unsigned int) strnlen(names, lastName - names));
0a7de745
A
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;
1c79356b 1435}
91447636 1436
0a7de745
A
1437extern "C" IOReturn
1438IONDRVLibrariesInitialize( IOService * provider )
91447636 1439{
0a7de745 1440 return kIOReturnUnsupported;
91447636 1441}