2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
36 #include <IOKit/IOLib.h>
37 #include <IOKit/IOKitKeys.h>
39 #include <pexpert/device_tree.h>
42 typedef UInt64 dtptr_t
;
44 typedef UInt32 dtptr_t
;
47 #include <machine/machine_routines.h>
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
);
55 #include <IOKit/assert.h>
57 #define IODTSUPPORTDEBUG 0
59 const IORegistryPlane
* gIODTPlane
;
61 static OSArray
* gIODTPHandles
;
62 static OSArray
* gIODTPHandleMap
;
63 static OSData
* gIODTResolvers
;
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
;
73 const OSSymbol
* gIODTSizeCellKey
;
74 const OSSymbol
* gIODTAddressCellKey
;
75 const OSSymbol
* gIODTRangeKey
;
77 const OSSymbol
* gIODTPersistKey
;
79 const OSSymbol
* gIODTDefaultInterruptController
;
80 const OSSymbol
* gIODTAAPLInterruptsKey
;
81 const OSSymbol
* gIODTPHandleKey
;
82 const OSSymbol
* gIODTInterruptCellKey
;
83 const OSSymbol
* gIODTInterruptParentKey
;
84 const OSSymbol
* gIODTNWInterruptMappingKey
;
86 OSDictionary
* gIODTSharedInterrupts
;
88 static IOLock
* gIODTResolversLock
;
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
);
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__
101 IODeviceTreeAlloc( void * dtTop
)
103 IORegistryEntry
* parent
;
104 IORegistryEntry
* child
;
105 IORegistryIterator
* regIter
;
106 OpaqueDTEntryIterator iter
;
111 OSDictionary
* allInts
;
113 unsigned int propSize
;
118 gIODTPlane
= IORegistryEntry::makePlane( kIODeviceTreePlane
);
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" );
132 assert( gIODTPlane
&& gIODTCompatibleKey
133 && gIODTTypeKey
&& gIODTModelKey
134 && gIODTSizeCellKey
&& gIODTAddressCellKey
&& gIODTRangeKey
135 && gIODTPersistKey
);
137 gIODTDefaultInterruptController
138 = OSSymbol::withCStringNoCopy("IOPrimaryInterruptController");
139 gIODTNWInterruptMappingKey
140 = OSSymbol::withCStringNoCopy("IONWInterrupts");
142 gIODTAAPLInterruptsKey
143 = OSSymbol::withCStringNoCopy("AAPL,interrupts");
145 = OSSymbol::withCStringNoCopy("AAPL,phandle");
147 gIODTInterruptParentKey
148 = OSSymbol::withCStringNoCopy("interrupt-parent");
150 gIODTPHandles
= OSArray::withCapacity( 1 );
151 gIODTPHandleMap
= OSArray::withCapacity( 1 );
152 gIODTResolvers
= OSData::withCapacity(16);
154 gIODTResolversLock
= IOLockAlloc();
156 gIODTInterruptCellKey
157 = OSSymbol::withCStringNoCopy("#interrupt-cells");
159 assert( gIODTDefaultInterruptController
&& gIODTNWInterruptMappingKey
160 && gIODTAAPLInterruptsKey
161 && gIODTPHandleKey
&& gIODTInterruptParentKey
162 && gIODTPHandles
&& gIODTPHandleMap
&& gIODTResolvers
&& gIODTResolversLock
163 && gIODTInterruptCellKey
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
);
171 freeDT
= foundDTNode
&& !SecureDTIsLockedDown();
173 parent
= MakeReferenceTable((DTEntry
)dtTop
, freeDT
);
175 stack
= OSArray::withObjects((const OSObject
**) &parent
, 1, 10 );
176 SecureDTInitEntryIterator((DTEntry
)dtTop
, &iter
);
179 parent
= (IORegistryEntry
*)stack
->getObject( stack
->getCount() - 1);
181 stack
->removeObject( stack
->getCount() - 1);
183 while (kSuccess
== SecureDTIterateEntries( &iter
, &dtChild
)) {
184 child
= MakeReferenceTable( dtChild
, freeDT
);
185 child
->attachToParent( parent
, gIODTPlane
);
189 if (kSuccess
== SecureDTEnterEntry( &iter
, dtChild
)) {
190 stack
->setObject( parent
);
193 // only registry holds retain
196 } while (stack
->getCount()
197 && (kSuccess
== SecureDTExitEntry( &iter
, &dtChild
)));
200 assert(kSuccess
!= SecureDTExitEntry(&iter
, &dtChild
));
202 // parent is now root of the created tree
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());
210 // attach tree to meta root
211 parent
->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane
);
215 // free original device tree
216 SecureDTInit(NULL
, 0);
217 IODTFreeLoaderInfo( "DeviceTree",
218 (void *)dtMap
[0], (int) round_page(dtMap
[1]));
223 gIODTSharedInterrupts
= OSDictionary::withCapacity(4);
224 allInts
= OSDictionary::withCapacity(4);
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
)) {
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
));
246 parent
->setProperty("allInts", allInts
);
247 parent
->setProperty("sharedInts", gIODTSharedInterrupts
);
249 regIter
= IORegistryIterator::iterateOver( gIODTPlane
,
250 kIORegistryIterateRecursively
);
252 while ((child
= regIter
->getNextObject())) {
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
);
270 // set a key in the root to indicate we found NW interrupt mapping
271 parent
->setProperty( gIODTNWInterruptMappingKey
,
272 (OSObject
*) gIODTNWInterruptMappingKey
);
280 IODTGetLoaderInfo( const char *key
, void **infoAddr
, int *infoSize
)
282 IORegistryEntry
*chosen
;
285 unsigned int propSize
;
288 chosen
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
289 if (chosen
== NULL
) {
293 propObj
= OSDynamicCast( OSData
, chosen
->getProperty(key
));
294 if (propObj
== NULL
) {
298 propSize
= propObj
->getLength();
299 if (propSize
!= (2 * sizeof(dtptr_t
))) {
303 propPtr
= (dtptr_t
*)propObj
->getBytesNoCopy();
304 if (propPtr
== NULL
) {
308 *infoAddr
= (void *)(uintptr_t) (propPtr
[0]);
309 *infoSize
= (int) (propPtr
[1]);
320 IODTFreeLoaderInfo( const char *key
, void *infoAddr
, int infoSize
)
322 vm_offset_t range
[2];
323 IORegistryEntry
*chosen
;
325 range
[0] = (vm_offset_t
)infoAddr
;
326 range
[1] = (vm_offset_t
)infoSize
;
327 FreePhysicalMemory( range
);
330 chosen
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
331 if (chosen
!= NULL
) {
332 chosen
->removeProperty(key
);
339 IODTGetDefault(const char *key
, void *infoAddr
, unsigned int infoSize
)
341 IORegistryEntry
*defaults
;
343 unsigned int defaultSize
;
345 defaults
= IORegistryEntry::fromPath( "/defaults", gIODTPlane
);
346 if (defaults
== NULL
) {
350 defaultObj
= OSDynamicCast( OSData
, defaults
->getProperty(key
));
351 if (defaultObj
== NULL
) {
355 defaultSize
= defaultObj
->getLength();
356 if (defaultSize
> infoSize
) {
360 memcpy( infoAddr
, defaultObj
->getBytesNoCopy(), defaultSize
);
366 FreePhysicalMemory( vm_offset_t
* range
)
370 virt
= ml_static_ptovirt( range
[0] );
372 ml_static_mfree( virt
, range
[1] );
376 static IORegistryEntry
*
377 MakeReferenceTable( DTEntry dtEntry
, bool copy
)
379 IORegistryEntry
*regEntry
;
380 OSDictionary
*propTable
;
381 const OSSymbol
*nameKey
;
384 OpaqueDTPropertyIterator dtIter
;
386 unsigned int propSize
;
389 bool noLocation
= true;
392 regEntry
= new IOService
;
394 if (regEntry
&& (false == regEntry
->init())) {
400 (kSuccess
== SecureDTInitPropertyIterator( dtEntry
, &dtIter
))) {
401 kernelOnly
= (kSuccess
== SecureDTGetProperty(dtEntry
, "kernel-only", &prop
, &propSize
));
402 propTable
= regEntry
->getPropertyTable();
404 while (kSuccess
== SecureDTIterateProperties( &dtIter
, &name
)) {
405 if (kSuccess
!= SecureDTGetProperty( dtEntry
, name
, &prop
, &propSize
)) {
410 nameKey
= OSSymbol::withCString(name
);
411 data
= OSData::withBytes(prop
, propSize
);
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
);
419 assert( nameKey
&& data
);
422 data
->setSerializable(false);
425 propTable
->setObject( nameKey
, data
);
429 if (nameKey
== gIODTNameKey
) {
431 sym
= OSSymbol::withCString((const char *) prop
);
433 sym
= OSSymbol::withCStringNoCopy((const char *) prop
);
435 regEntry
->setName( sym
);
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;
442 strncpy( location
, (const char *) prop
, propSize
);
443 location
[propSize
] = 0;
444 regEntry
->setLocation( location
);
445 propTable
->removeObject( gIODTUnitKey
);
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
);
459 AddPHandle( IORegistryEntry
* regEntry
)
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
);
471 static IORegistryEntry
*
472 FindPHandle( UInt32 phandle
)
475 IORegistryEntry
*regEntry
= NULL
;
478 for (i
= 0; (data
= (OSData
*)gIODTPHandles
->getObject( i
)); i
++) {
479 if (phandle
== *((UInt32
*)data
->getBytesNoCopy())) {
480 regEntry
= (IORegistryEntry
*)
481 gIODTPHandleMap
->getObject( i
);
490 GetUInt32( IORegistryEntry
* regEntry
, const OSSymbol
* name
,
497 if (!(obj
= regEntry
->copyProperty(name
))) {
501 result
= ((data
= OSDynamicCast(OSData
, obj
)) && (sizeof(UInt32
) == data
->getLength()));
503 *value
= *((UInt32
*) data
->getBytesNoCopy());
510 static IORegistryEntry
*
511 IODTFindInterruptParent( IORegistryEntry
* regEntry
, IOItemCount index
)
513 IORegistryEntry
* parent
;
518 if ((data
= OSDynamicCast( OSData
, regEntry
->getProperty( gIODTInterruptParentKey
)))
519 && (sizeof(UInt32
) <= (len
= data
->getLength()))) {
520 if (((index
+ 1) * sizeof(UInt32
)) > len
) {
523 phandle
= ((UInt32
*) data
->getBytesNoCopy())[index
];
524 parent
= FindPHandle( phandle
);
525 } else if (NULL
== regEntry
->getProperty( "interrupt-controller")) {
526 parent
= regEntry
->getParentEntry( gIODTPlane
);
535 IODTInterruptControllerName( IORegistryEntry
* regEntry
)
542 ok
= GetUInt32( regEntry
, gIODTPHandleKey
, &phandle
);
546 snprintf(buf
, sizeof(buf
), "IOInterruptController%08X", (uint32_t)phandle
);
547 sym
= OSSymbol::withCString( buf
);
555 #define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; }
558 IODTGetICellCounts( IORegistryEntry
* regEntry
,
559 UInt32
* iCellCount
, UInt32
* aCellCount
)
561 if (!GetUInt32( regEntry
, gIODTInterruptCellKey
, iCellCount
)) {
562 unexpected( *iCellCount
= 1 );
564 if (!GetUInt32( regEntry
, gIODTAddressCellKey
, aCellCount
)) {
570 IODTMapOneInterrupt( IORegistryEntry
* regEntry
, UInt32
* intSpec
, UInt32 index
,
571 LIBKERN_RETURNS_RETAINED OSData
** spec
,
572 LIBKERN_RETURNS_RETAINED
const OSSymbol
** controller
)
574 IORegistryEntry
*parent
= NULL
;
580 UInt32 acells
, icells
, pacells
, picells
, cell
;
581 UInt32 i
, original_icells
;
582 bool cmp
, ok
= false;
584 parent
= IODTFindInterruptParent( regEntry
, index
);
585 IODTGetICellCounts( parent
, &icells
, &acells
);
588 data
= OSDynamicCast( OSData
, regEntry
->getProperty( "reg" ));
589 if (data
&& (data
->getLength() >= (acells
* sizeof(UInt32
)))) {
590 addrCmp
= (UInt32
*) data
->getBytesNoCopy();
593 original_icells
= icells
;
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
]);
604 for (i
= 0; i
< icells
; i
++) {
605 kprintf("0x%08X ", intSpec
[i
]);
610 if (parent
&& (data
= OSDynamicCast( OSData
,
611 regEntry
->getProperty( "interrupt-controller")))) {
612 // found a controller - don't want to follow cascaded controllers
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")))) {
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();
632 kprintf(" maskCmp: ");
633 for (i
= 0; i
< acells
+ icells
; i
++) {
637 kprintf("0x%08X ", maskCmp
[i
]);
640 kprintf(" masked: ");
641 for (i
= 0; i
< acells
+ icells
; i
++) {
645 kprintf("0x%08X ", ((i
< acells
) ? addrCmp
[i
] : intSpec
[i
- acells
]) & maskCmp
[i
]);
649 kprintf("no maskCmp\n");
655 for (i
= 0; i
< acells
+ icells
; i
++) {
659 kprintf("0x%08X ", map
[i
]);
663 for (i
= 0, cmp
= true; cmp
&& (i
< (acells
+ icells
)); i
++) {
664 cell
= (i
< acells
) ? addrCmp
[i
] : intSpec
[i
- acells
];
668 cmp
= (cell
== map
[i
]);
671 map
+= acells
+ icells
;
672 if (NULL
== (parent
= FindPHandle( *(map
++)))) {
676 IODTGetICellCounts( parent
, &picells
, &pacells
);
679 intSpec
= map
+ pacells
;
682 map
+= pacells
+ picells
;
684 } while (!cmp
&& (map
< endMap
));
691 IODTGetICellCounts( parent
, &icells
, &acells
);
696 return ok
? original_icells
: 0;
700 IODTGetInterruptOptions( IORegistryEntry
* regEntry
, int source
, IOOptionBits
* options
)
702 OSArray
* controllers
;
703 OSArray
* specifiers
;
710 controllers
= OSDynamicCast(OSArray
, regEntry
->getProperty(gIOInterruptControllersKey
));
711 specifiers
= OSDynamicCast(OSArray
, regEntry
->getProperty(gIOInterruptSpecifiersKey
));
713 if (!controllers
|| !specifiers
) {
714 return kIOReturnNoInterrupt
;
717 shared
= (OSArray
*) gIODTSharedInterrupts
->getObject(
718 (const OSSymbol
*) controllers
->getObject(source
));
720 return kIOReturnSuccess
;
723 spec
= specifiers
->getObject(source
);
725 return kIOReturnNoInterrupt
;
728 for (unsigned int i
= 0;
729 (oneSpec
= shared
->getObject(i
))
730 && (!oneSpec
->isEqualTo(spec
));
735 *options
= kIODTInterruptShared
;
738 return kIOReturnSuccess
;
742 IODTMapInterruptsSharing( IORegistryEntry
* regEntry
, OSDictionary
* allInts
)
744 IORegistryEntry
* parent
;
753 OSArray
* controllerInts
;
754 const OSSymbol
* controller
= NULL
;
755 OSArray
* controllers
;
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
765 if (nw
&& (parent
= regEntry
->getParentEntry( gIODTPlane
))) {
766 // check for bridges on old world
767 if ((local2
= OSDynamicCast( OSData
,
768 parent
->getProperty( gIODTAAPLInterruptsKey
)))) {
774 localBits
= (UInt32
*) local
->getBytesNoCopy();
775 localEnd
= localBits
+ (local
->getLength() / sizeof(UInt32
));
777 mapped
= OSArray::withCapacity( 1 );
778 controllers
= OSArray::withCapacity( 1 );
780 ok
= (mapped
&& controllers
);
785 skip
= IODTMapOneInterrupt( regEntry
, localBits
, index
, &map
, &controller
);
787 IOLog("%s: error mapping interrupt[%d]\n",
788 regEntry
->getName(), mapped
->getCount());
792 map
= OSData::withData( local
, mapped
->getCount() * sizeof(UInt32
),
794 controller
= gIODTDefaultInterruptController
;
795 controller
->retain();
800 mapped
->setObject( map
);
801 controllers
->setObject( controller
);
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
);
812 controllerInts
= OSArray::withObjects((const OSObject
**) &map
, 1, 4 );
813 if (controllerInts
) {
814 gIODTSharedInterrupts
->setObject( controller
, controllerInts
);
815 controllerInts
->release();
822 controllerInts
->setObject(map
);
825 controllerInts
= OSArray::withObjects((const OSObject
**) &map
, 1, 16 );
826 if (controllerInts
) {
827 allInts
->setObject( controller
, controllerInts
);
828 controllerInts
->release();
834 controller
->release();
835 } while (localBits
< localEnd
);
838 ok
&= (localBits
== localEnd
);
842 ok
= regEntry
->setProperty( gIOInterruptControllersKey
, controllers
);
843 ok
&= regEntry
->setProperty( gIOInterruptSpecifiersKey
, mapped
);
847 controllers
->release();
857 IODTMapInterrupts( IORegistryEntry
* regEntry
)
859 return IODTMapInterruptsSharing( regEntry
, NULL
);
866 CompareKey( OSString
* key
,
867 const IORegistryEntry
* table
, const OSSymbol
* propName
,
868 LIBKERN_RETURNS_RETAINED OSString
** matchingName
)
877 const char *lastName
;
880 const char *result
= NULL
;
882 if (NULL
== (prop
= table
->copyProperty( propName
))) {
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;
897 ckey
= key
->getCStringNoCopy();
898 keyLen
= key
->getLength();
899 wild
= ('*' == key
->getChar( keyLen
- 1 ));
902 // for each name in the property
903 nlen
= (unsigned int) strnlen(names
, lastName
- names
);
905 matched
= ((nlen
>= (keyLen
- 1)) && (0 == strncmp(ckey
, names
, keyLen
- 1)));
907 matched
= (keyLen
== nlen
) && (0 == strncmp(ckey
, names
, keyLen
));
914 names
= names
+ nlen
+ 1;
915 } while ((names
< lastName
) && (false == matched
));
918 if (result
&& matchingName
) {
919 *matchingName
= OSString::withCString( result
);
926 return result
!= NULL
;
931 IODTCompareNubName( const IORegistryEntry
* regEntry
,
932 OSString
* name
, OSString
** matchingName
)
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
);
945 IODTCompareNubName( const IORegistryEntry
* regEntry
,
946 OSString
* name
, OSSharedPtr
<OSString
>& matchingName
)
948 OSString
* matchingNameRaw
= NULL
;
949 bool result
= IODTCompareNubName(regEntry
, name
, &matchingNameRaw
);
950 matchingName
.reset(matchingNameRaw
, OSNoRetain
);
955 IODTMatchNubWithKeys( IORegistryEntry
* regEntry
,
961 obj
= OSUnserialize( keys
, NULL
);
964 result
= regEntry
->compareNames( obj
);
969 IOLog("Couldn't unserialize %s\n", keys
);
976 OSCollectionIterator
*
977 IODTFindMatchingEntries( IORegistryEntry
* from
,
978 IOOptionBits options
, const char * keys
)
980 OSSet
*result
= NULL
;
981 IORegistryEntry
*next
;
982 IORegistryIterator
*iter
;
983 OSCollectionIterator
*cIter
;
985 bool minus
= options
& kIODTExclusive
;
988 iter
= IORegistryIterator::iterateOver( from
, gIODTPlane
,
989 (options
& kIODTRecursive
) ? kIORegistryIterateRecursively
: 0 );
995 result
= OSSet::withCapacity( 3 );
1001 while ((next
= iter
->getNextObject())) {
1002 // Look for existence of a debug property to skip
1003 if (next
->getProperty("AAPL,ignore")) {
1008 cmp
= IODTMatchNubWithKeys( next
, keys
);
1009 if ((minus
&& (false == cmp
))
1010 || ((false == minus
) && (false != cmp
))) {
1011 result
->setObject( next
);
1014 result
->setObject( next
);
1017 } while (!iter
->isValid());
1022 cIter
= OSCollectionIterator::withCollection( result
);
1031 struct IODTPersistent
{
1032 IODTCompareAddressCellFunc compareFunc
;
1036 IODTSetResolving( IORegistryEntry
* regEntry
,
1037 IODTCompareAddressCellFunc compareFunc
,
1038 IODTNVLocationFunc locationFunc __unused
)
1040 IODTPersistent persist
;
1041 IODTPersistent
* entry
;
1043 unsigned int index
, count
;
1045 IOLockLock(gIODTResolversLock
);
1047 count
= (gIODTResolvers
->getLength() / sizeof(IODTPersistent
));
1048 entry
= (typeof(entry
))gIODTResolvers
->getBytesNoCopy();
1049 for (index
= 0; index
< count
; index
++) {
1050 if (compareFunc
== entry
->compareFunc
) {
1055 if (index
== count
) {
1056 persist
.compareFunc
= compareFunc
;
1057 if (!gIODTResolvers
->appendBytes(&persist
, sizeof(IODTPersistent
))) {
1058 panic("IODTSetResolving");
1062 IOLockUnlock(gIODTResolversLock
);
1064 num
= OSNumber::withNumber(index
, 32);
1065 regEntry
->setProperty(gIODTPersistKey
, num
);
1066 OSSafeReleaseNULL(num
);
1071 #if defined(__arm64__)
1073 DefaultCompare( UInt32 cellCount
, UInt32 left
[], UInt32 right
[] )
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]);
1082 panic("DefaultCompare only knows how to handle 1 or 2 cells.");
1087 #elif defined(__arm__) || defined(__i386__) || defined(__x86_64__)
1089 DefaultCompare( UInt32 cellCount
, UInt32 left
[], UInt32 right
[] )
1092 return left
[cellCount
] - right
[cellCount
];
1095 #error Unknown architecture.
1099 AddLengthToCells( UInt32 numCells
, UInt32
*cells
, UInt64 offset
)
1101 if (numCells
== 1) {
1102 cells
[0] += (UInt32
)offset
;
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);
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);
1120 static IOPhysicalAddress
1121 CellsValue( UInt32 numCells
, UInt32
*cells
)
1123 if (numCells
== 1) {
1124 return IOPhysical32( 0, cells
[0] );
1126 #if defined(__arm64__) || defined(arm)
1127 return IOPhysical32( cells
[numCells
- 1], cells
[numCells
- 2] );
1129 return IOPhysical32( cells
[numCells
- 2], cells
[numCells
- 1] );
1135 IODTGetCellCounts( IORegistryEntry
* regEntry
,
1136 UInt32
* sizeCount
, UInt32
* addressCount
)
1138 if (!GetUInt32( regEntry
, gIODTSizeCellKey
, sizeCount
)) {
1141 if (!GetUInt32( regEntry
, gIODTAddressCellKey
, addressCount
)) {
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.
1150 // Range[]: child-addr our-addr child-len
1151 // #cells: child ours child
1154 IODTResolveAddressCell( IORegistryEntry
* startEntry
,
1156 IOPhysicalAddress
* phys
, IOPhysicalLength
* lenOut
)
1158 IORegistryEntry
* parent
;
1159 IORegistryEntry
* regEntry
;
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
;
1168 UInt32 cell
[8], propLen
;
1176 SInt64 diff
, diff2
, endDiff
;
1177 UInt64 len
, rangeLen
;
1179 IODTPersistent
*persist
;
1180 IODTCompareAddressCellFunc compare
;
1182 regEntry
= startEntry
;
1183 IODTGetCellCounts( regEntry
, &childSizeCells
, &childAddressCells
);
1184 childCells
= childAddressCells
+ childSizeCells
;
1186 if (childCells
> sizeof(cell
) / sizeof(cell
[0])) {
1187 panic("IODTResolveAddressCell: Invalid device tree (%u,%u)", (uint32_t)childAddressCells
, (uint32_t)childSizeCells
);
1190 bcopy( cellsIn
, cell
, sizeof(UInt32
) * childCells
);
1191 *lenOut
= CellsValue( childSizeCells
, cellsIn
+ childAddressCells
);
1194 prop
= OSDynamicCast( OSData
, regEntry
->getProperty( gIODTRangeKey
));
1196 /* end of the road */
1197 *phys
= CellsValue( childAddressCells
, cell
);
1199 if (regEntry
!= startEntry
) {
1200 regEntry
->release();
1205 parent
= regEntry
->copyParentEntry( gIODTPlane
);
1206 IODTGetCellCounts( parent
, &sizeCells
, &addressCells
);
1208 if ((propLen
= prop
->getLength())) {
1210 startRange
= (UInt32
*) prop
->getBytesNoCopy();
1212 endRanges
= range
+ (propLen
/ sizeof(UInt32
));
1215 num
= OSDynamicCast(OSNumber
, regEntry
->getProperty(gIODTPersistKey
));
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
;
1224 IOLockUnlock(gIODTResolversLock
);
1227 if (!compare
&& (addressCells
== childAddressCells
)) {
1228 compare
= DefaultCompare
;
1231 panic("There is no mixed comparison function yet...");
1236 range
+= (childCells
+ addressCells
)) {
1237 // is cell start within range?
1238 diff
= (*compare
)( childAddressCells
, cell
, range
);
1240 if (childAddressCells
> sizeof(endCell
) / sizeof(endCell
[0])) {
1241 panic("IODTResolveAddressCell: Invalid device tree (%u)", (uint32_t)childAddressCells
);
1244 bcopy(range
, endCell
, childAddressCells
* sizeof(UInt32
));
1246 rangeLen
= CellsValue(childSizeCells
, range
+ childAddressCells
+ addressCells
);
1247 AddLengthToCells(childAddressCells
, endCell
, rangeLen
);
1249 diff2
= (*compare
)( childAddressCells
, cell
, endCell
);
1251 // if start of cell < start of range, or end of range >= start of cell, skip
1252 if ((diff
< 0) || (diff2
>= 0)) {
1256 len
= CellsValue(childSizeCells
, cell
+ childAddressCells
);
1260 // search for cell end
1261 bcopy(cell
, endCell
, childAddressCells
* sizeof(UInt32
));
1263 AddLengthToCells(childAddressCells
, endCell
, len
- 1);
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
);
1274 UInt64 rangeStart
= CellsValue(addressCells
, range
+ childAddressCells
);
1275 UInt64 lookRangeStart
= CellsValue(addressCells
, lookRange
+ childAddressCells
);
1276 if ((endDiff
- len
+ 1 + lookRangeStart
) == (diff
+ rangeStart
)) {
1289 if (addressCells
+ sizeCells
> sizeof(cell
) / sizeof(cell
[0])) {
1290 panic("IODTResolveAddressCell: Invalid device tree (%u, %u)", (uint32_t)addressCells
, (uint32_t)sizeCells
);
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 */
1298 if (regEntry
!= startEntry
) {
1299 regEntry
->release();
1302 childSizeCells
= sizeCells
;
1303 childAddressCells
= addressCells
;
1304 childCells
= childAddressCells
+ childSizeCells
;
1305 }while (ok
&& regEntry
);
1312 IODTResolveAddressing( IORegistryEntry
* regEntry
,
1313 const char * addressPropertyName
,
1314 IODeviceMemory
* parent
)
1316 IORegistryEntry
*parentEntry
;
1317 OSData
*addressProperty
;
1318 UInt32 sizeCells
, addressCells
, cells
;
1321 IOPhysicalAddress phys
;
1322 IOPhysicalLength len
;
1324 IODeviceMemory
*range
;
1328 parentEntry
= regEntry
->copyParentEntry( gIODTPlane
);
1329 addressProperty
= (OSData
*) regEntry
->getProperty( addressPropertyName
);
1330 if ((NULL
== addressProperty
) || (NULL
== parentEntry
)) {
1334 IODTGetCellCounts( parentEntry
, &sizeCells
, &addressCells
);
1335 if (0 == sizeCells
) {
1339 cells
= sizeCells
+ addressCells
;
1340 reg
= (UInt32
*) addressProperty
->getBytesNoCopy();
1341 num
= addressProperty
->getLength() / (4 * cells
);
1343 array
= OSArray::withCapacity( 1 );
1344 if (NULL
== array
) {
1348 for (i
= 0; i
< num
; i
++) {
1349 if (IODTResolveAddressCell( parentEntry
, reg
, &phys
, &len
)) {
1352 range
= IODeviceMemory::withSubRange( parent
,
1353 phys
- parent
->getPhysicalSegment(0, NULL
, kIOMemoryMapperNone
), len
);
1355 if (NULL
== range
) {
1356 range
= IODeviceMemory::withRange( phys
, len
);
1359 array
->setObject( range
);
1365 regEntry
->setProperty( gIODeviceMemoryKey
, array
);
1366 array
->release(); /* ??? */
1369 OSSafeReleaseNULL(parentEntry
);
1375 IODTFindSlotName( IORegistryEntry
* regEntry
, UInt32 deviceNumber
)
1377 IORegistryEntry
*parent
;
1387 data
= (OSData
*) regEntry
->getProperty("AAPL,slot-name");
1393 parent
= regEntry
->copyParentEntry( gIODTPlane
);
1398 data
= OSDynamicCast( OSData
, parent
->getProperty("slot-names"));
1402 if (data
->getLength() <= 4) {
1406 bits
= (UInt32
*) data
->getBytesNoCopy();
1408 if ((0 == (mask
& (1 << deviceNumber
)))) {
1412 names
= (char *)(bits
+ 1);
1413 lastName
= names
+ (data
->getLength() - 4);
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
);
1421 regEntry
->setProperty("AAPL,slot-name", data
);
1432 OSSafeReleaseNULL(parent
);
1438 IONDRVLibrariesInitialize( IOService
* provider
)
1440 return kIOReturnUnsupported
;