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 <IOKit/IODeviceMemory.h>
32 #include <IOKit/IOService.h>
33 #include <IOKit/IOCatalogue.h>
35 #include <IOKit/IOLib.h>
36 #include <IOKit/IOKitKeys.h>
38 #include <pexpert/device_tree.h>
41 typedef UInt64 dtptr_t
;
43 typedef UInt32 dtptr_t
;
46 #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
);
56 #include <IOKit/assert.h>
58 #define IODTSUPPORTDEBUG 0
60 const IORegistryPlane
* gIODTPlane
;
62 static OSArray
* gIODTPHandles
;
63 static OSArray
* gIODTPHandleMap
;
64 static OSData
* gIODTResolvers
;
66 const OSSymbol
* gIODTNameKey
;
67 const OSSymbol
* gIODTUnitKey
;
68 const OSSymbol
* gIODTCompatibleKey
;
69 const OSSymbol
* gIODTTypeKey
;
70 const OSSymbol
* gIODTModelKey
;
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
);
96 IODeviceTreeAlloc( void * dtTop
)
98 IORegistryEntry
* parent
;
99 IORegistryEntry
* child
;
100 IORegistryIterator
* regIter
;
101 OpaqueDTEntryIterator iter
;
106 OSDictionary
* allInts
;
108 unsigned int propSize
;
112 gIODTPlane
= IORegistryEntry::makePlane( kIODeviceTreePlane
);
114 gIODTNameKey
= OSSymbol::withCStringNoCopy( "name" );
115 gIODTUnitKey
= OSSymbol::withCStringNoCopy( "AAPL,unit-string" );
116 gIODTCompatibleKey
= OSSymbol::withCStringNoCopy( "compatible" );
117 gIODTTypeKey
= OSSymbol::withCStringNoCopy( "device_type" );
118 gIODTModelKey
= OSSymbol::withCStringNoCopy( "model" );
119 gIODTTargetTypeKey
= OSSymbol::withCStringNoCopy( "target-type" );
120 gIODTSizeCellKey
= OSSymbol::withCStringNoCopy( "#size-cells" );
121 gIODTAddressCellKey
= OSSymbol::withCStringNoCopy( "#address-cells" );
122 gIODTRangeKey
= OSSymbol::withCStringNoCopy( "ranges" );
123 gIODTPersistKey
= OSSymbol::withCStringNoCopy( "IODTPersist" );
125 assert( gIODTPlane
&& gIODTCompatibleKey
126 && gIODTTypeKey
&& gIODTModelKey
127 && gIODTSizeCellKey
&& gIODTAddressCellKey
&& gIODTRangeKey
128 && gIODTPersistKey
);
130 gIODTDefaultInterruptController
131 = OSSymbol::withCStringNoCopy("IOPrimaryInterruptController");
132 gIODTNWInterruptMappingKey
133 = OSSymbol::withCStringNoCopy("IONWInterrupts");
135 gIODTAAPLInterruptsKey
136 = OSSymbol::withCStringNoCopy("AAPL,interrupts");
138 = OSSymbol::withCStringNoCopy("AAPL,phandle");
140 gIODTInterruptParentKey
141 = OSSymbol::withCStringNoCopy("interrupt-parent");
143 gIODTPHandles
= OSArray::withCapacity( 1 );
144 gIODTPHandleMap
= OSArray::withCapacity( 1 );
145 gIODTResolvers
= OSData::withCapacity(16);
147 gIODTResolversLock
= IOLockAlloc();
149 gIODTInterruptCellKey
150 = OSSymbol::withCStringNoCopy("#interrupt-cells");
152 assert( gIODTDefaultInterruptController
&& gIODTNWInterruptMappingKey
153 && gIODTAAPLInterruptsKey
154 && gIODTPHandleKey
&& gIODTInterruptParentKey
155 && gIODTPHandles
&& gIODTPHandleMap
&& gIODTResolvers
&& gIODTResolversLock
156 && gIODTInterruptCellKey
159 freeDT
= (kSuccess
== DTLookupEntry( 0, "/chosen/memory-map", &mapEntry
))
160 && (kSuccess
== DTGetProperty( mapEntry
,
161 "DeviceTree", (void **) &dtMap
, &propSize
))
162 && ((2 * sizeof(uint32_t)) == propSize
);
164 parent
= MakeReferenceTable( (DTEntry
)dtTop
, freeDT
);
166 stack
= OSArray::withObjects( (const OSObject
**) &parent
, 1, 10 );
167 DTInitEntryIterator( (DTEntry
)dtTop
, &iter
);
170 parent
= (IORegistryEntry
*)stack
->getObject( stack
->getCount() - 1);
172 stack
->removeObject( stack
->getCount() - 1);
174 while( kSuccess
== DTIterateEntries( &iter
, &dtChild
) ) {
176 child
= MakeReferenceTable( dtChild
, freeDT
);
177 child
->attachToParent( parent
, gIODTPlane
);
181 if( kSuccess
== DTEnterEntry( &iter
, dtChild
)) {
182 stack
->setObject( parent
);
185 // only registry holds retain
189 } while( stack
->getCount()
190 && (kSuccess
== DTExitEntry( &iter
, &dtChild
)));
193 assert(kSuccess
!= DTExitEntry(&iter
, &dtChild
));
195 // parent is now root of the created tree
197 // make root name first compatible entry (purely cosmetic)
198 if( (prop
= (OSData
*) parent
->getProperty( gIODTCompatibleKey
))) {
199 parent
->setName( parent
->getName(), gIODTPlane
);
200 parent
->setName( (const char *) prop
->getBytesNoCopy() );
203 // attach tree to meta root
204 parent
->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane
);
208 // free original device tree
210 IODTFreeLoaderInfo( "DeviceTree",
211 (void *)dtMap
[0], (int) round_page(dtMap
[1]) );
216 gIODTSharedInterrupts
= OSDictionary::withCapacity(4);
217 allInts
= OSDictionary::withCapacity(4);
219 regIter
= IORegistryIterator::iterateOver( gIODTPlane
,
220 kIORegistryIterateRecursively
);
221 assert( regIter
&& allInts
&& gIODTSharedInterrupts
);
222 if( regIter
&& allInts
&& gIODTSharedInterrupts
) {
223 while( (child
= regIter
->getNextObject())) {
224 IODTMapInterruptsSharing( child
, allInts
);
225 if( !intMap
&& child
->getProperty( gIODTInterruptParentKey
))
233 parent
->setProperty("allInts", allInts
);
234 parent
->setProperty("sharedInts", gIODTSharedInterrupts
);
236 regIter
= IORegistryIterator::iterateOver( gIODTPlane
,
237 kIORegistryIterateRecursively
);
239 while( (child
= regIter
->getNextObject())) {
241 array
= OSDynamicCast(OSArray
, child
->getProperty( gIOInterruptSpecifiersKey
));
242 for( UInt32 i
= 0; array
&& (i
< array
->getCount()); i
++)
244 IOOptionBits options
;
245 IOReturn ret
= IODTGetInterruptOptions( child
, i
, &options
);
246 if( (ret
!= kIOReturnSuccess
) || options
)
247 IOLog("%s[%ld] %ld (%x)\n", child
->getName(), i
, options
, ret
);
257 // set a key in the root to indicate we found NW interrupt mapping
258 parent
->setProperty( gIODTNWInterruptMappingKey
,
259 (OSObject
*) gIODTNWInterruptMappingKey
);
264 int IODTGetLoaderInfo( const char *key
, void **infoAddr
, int *infoSize
)
266 IORegistryEntry
*chosen
;
269 unsigned int propSize
;
272 chosen
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
273 if ( chosen
== 0 ) return -1;
275 propObj
= OSDynamicCast( OSData
, chosen
->getProperty(key
) );
276 if ( propObj
== 0 ) goto cleanup
;
278 propSize
= propObj
->getLength();
279 if ( propSize
!= (2 * sizeof(dtptr_t
)) ) goto cleanup
;
281 propPtr
= (dtptr_t
*)propObj
->getBytesNoCopy();
282 if ( propPtr
== 0 ) goto cleanup
;
284 *infoAddr
= (void *)(uintptr_t) (propPtr
[0]);
285 *infoSize
= (int) (propPtr
[1]);
295 void IODTFreeLoaderInfo( const char *key
, void *infoAddr
, int infoSize
)
297 vm_offset_t range
[2];
298 IORegistryEntry
*chosen
;
300 range
[0] = (vm_offset_t
)infoAddr
;
301 range
[1] = (vm_offset_t
)infoSize
;
302 FreePhysicalMemory( range
);
305 chosen
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
307 chosen
->removeProperty(key
);
313 int IODTGetDefault(const char *key
, void *infoAddr
, unsigned int infoSize
)
315 IORegistryEntry
*defaults
;
317 unsigned int defaultSize
;
319 defaults
= IORegistryEntry::fromPath( "/defaults", gIODTPlane
);
320 if ( defaults
== 0 ) return -1;
322 defaultObj
= OSDynamicCast( OSData
, defaults
->getProperty(key
) );
323 if ( defaultObj
== 0 ) return -1;
325 defaultSize
= defaultObj
->getLength();
326 if ( defaultSize
> infoSize
) return -1;
328 memcpy( infoAddr
, defaultObj
->getBytesNoCopy(), defaultSize
);
333 static void FreePhysicalMemory( vm_offset_t
* range
)
337 virt
= ml_static_ptovirt( range
[0] );
339 ml_static_mfree( virt
, range
[1] );
343 static IORegistryEntry
*
344 MakeReferenceTable( DTEntry dtEntry
, bool copy
)
346 IORegistryEntry
*regEntry
;
347 OSDictionary
*propTable
;
348 const OSSymbol
*nameKey
;
351 OpaqueDTPropertyIterator dtIter
;
353 unsigned int propSize
;
356 bool noLocation
= true;
359 regEntry
= new IOService
;
361 if( regEntry
&& (false == regEntry
->init())) {
367 (kSuccess
== DTInitPropertyIterator( dtEntry
, &dtIter
))) {
369 kernelOnly
= (kSuccess
== DTGetProperty(dtEntry
, "kernel-only", &prop
, &propSize
));
370 propTable
= regEntry
->getPropertyTable();
372 while( kSuccess
== DTIterateProperties( &dtIter
, &name
)) {
374 if( kSuccess
!= DTGetProperty( dtEntry
, name
, &prop
, &propSize
))
378 nameKey
= OSSymbol::withCString(name
);
379 data
= OSData::withBytes(prop
, propSize
);
381 nameKey
= OSSymbol::withCStringNoCopy(name
);
382 data
= OSData::withBytesNoCopy(prop
, propSize
);
384 assert( nameKey
&& data
);
387 data
->setSerializable(false);
389 propTable
->setObject( nameKey
, data
);
393 if( nameKey
== gIODTNameKey
) {
395 sym
= OSSymbol::withCString( (const char *) prop
);
397 sym
= OSSymbol::withCStringNoCopy( (const char *) prop
);
398 regEntry
->setName( sym
);
401 } else if( nameKey
== gIODTUnitKey
) {
402 // all OF strings are null terminated... except this one
403 if( propSize
>= (int) sizeof(location
))
404 propSize
= sizeof(location
) - 1;
405 strncpy( location
, (const char *) prop
, propSize
);
406 location
[ propSize
] = 0;
407 regEntry
->setLocation( location
);
408 propTable
->removeObject( gIODTUnitKey
);
411 } else if(noLocation
&& (!strncmp(name
, "reg", sizeof("reg")))) {
412 // default location - override later
413 snprintf(location
, sizeof(location
), "%X", *((uint32_t *) prop
));
414 regEntry
->setLocation( location
);
422 static void AddPHandle( IORegistryEntry
* regEntry
)
426 if( regEntry
->getProperty( gIODTInterruptCellKey
)
427 && (data
= OSDynamicCast( OSData
, regEntry
->getProperty( gIODTPHandleKey
)))) {
428 // a possible interrupt-parent
429 gIODTPHandles
->setObject( data
);
430 gIODTPHandleMap
->setObject( regEntry
);
434 static IORegistryEntry
* FindPHandle( UInt32 phandle
)
437 IORegistryEntry
*regEntry
= 0;
440 for( i
= 0; (data
= (OSData
*)gIODTPHandles
->getObject( i
)); i
++ ) {
441 if( phandle
== *((UInt32
*)data
->getBytesNoCopy())) {
442 regEntry
= (IORegistryEntry
*)
443 gIODTPHandleMap
->getObject( i
);
451 static bool GetUInt32( IORegistryEntry
* regEntry
, const OSSymbol
* name
,
458 if (!(obj
= regEntry
->copyProperty(name
))) return (false);
460 result
= ((data
= OSDynamicCast(OSData
, obj
)) && (sizeof(UInt32
) == data
->getLength()));
461 if (result
) *value
= *((UInt32
*) data
->getBytesNoCopy());
467 static IORegistryEntry
* IODTFindInterruptParent( IORegistryEntry
* regEntry
, IOItemCount index
)
469 IORegistryEntry
* parent
;
474 if( (data
= OSDynamicCast( OSData
, regEntry
->getProperty( gIODTInterruptParentKey
)))
475 && (sizeof(UInt32
) <= (len
= data
->getLength()))) {
476 if (((index
+ 1) * sizeof(UInt32
)) > len
)
478 phandle
= ((UInt32
*) data
->getBytesNoCopy())[index
];
479 parent
= FindPHandle( phandle
);
481 } else if( 0 == regEntry
->getProperty( "interrupt-controller"))
482 parent
= regEntry
->getParentEntry( gIODTPlane
);
489 const OSSymbol
* IODTInterruptControllerName( IORegistryEntry
* regEntry
)
496 ok
= GetUInt32( regEntry
, gIODTPHandleKey
, &phandle
);
500 snprintf(buf
, sizeof(buf
), "IOInterruptController%08X", (uint32_t)phandle
);
501 sym
= OSSymbol::withCString( buf
);
508 #define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; }
510 static void IODTGetICellCounts( IORegistryEntry
* regEntry
,
511 UInt32
* iCellCount
, UInt32
* aCellCount
)
513 if( !GetUInt32( regEntry
, gIODTInterruptCellKey
, iCellCount
))
514 unexpected( *iCellCount
= 1 );
515 if( !GetUInt32( regEntry
, gIODTAddressCellKey
, aCellCount
))
519 static UInt32
IODTMapOneInterrupt( IORegistryEntry
* regEntry
, UInt32
* intSpec
, UInt32 index
,
520 OSData
** spec
, const OSSymbol
** controller
)
522 IORegistryEntry
*parent
= 0;
528 UInt32 acells
, icells
, pacells
, picells
, cell
;
529 UInt32 i
, original_icells
;
530 bool cmp
, ok
= false;
532 parent
= IODTFindInterruptParent( regEntry
, index
);
533 IODTGetICellCounts( parent
, &icells
, &acells
);
536 data
= OSDynamicCast( OSData
, regEntry
->getProperty( "reg" ));
537 if( data
&& (data
->getLength() >= (acells
* sizeof(UInt32
))))
538 addrCmp
= (UInt32
*) data
->getBytesNoCopy();
540 original_icells
= icells
;
545 kprintf ("IODTMapOneInterrupt: current regEntry name %s\n", regEntry
->getName());
546 kprintf ("acells - icells: ");
547 for (i
= 0; i
< acells
; i
++) kprintf ("0x%08X ", addrCmp
[i
]);
549 for (i
= 0; i
< icells
; i
++) kprintf ("0x%08X ", intSpec
[i
]);
553 if( parent
&& (data
= OSDynamicCast( OSData
,
554 regEntry
->getProperty( "interrupt-controller")))) {
555 // found a controller - don't want to follow cascaded controllers
557 *spec
= OSData::withBytesNoCopy( (void *) intSpec
,
558 icells
* sizeof(UInt32
));
559 *controller
= IODTInterruptControllerName( regEntry
);
560 ok
= (*spec
&& *controller
);
561 } else if( parent
&& (data
= OSDynamicCast( OSData
,
562 regEntry
->getProperty( "interrupt-map")))) {
564 map
= (UInt32
*) data
->getBytesNoCopy();
565 endMap
= map
+ (data
->getLength() / sizeof(UInt32
));
566 data
= OSDynamicCast( OSData
, regEntry
->getProperty( "interrupt-map-mask" ));
567 if( data
&& (data
->getLength() >= ((acells
+ icells
) * sizeof(UInt32
))))
568 maskCmp
= (UInt32
*) data
->getBytesNoCopy();
574 kprintf (" maskCmp: ");
575 for (i
= 0; i
< acells
+ icells
; i
++) {
578 kprintf ("0x%08X ", maskCmp
[i
]);
581 kprintf (" masked: ");
582 for (i
= 0; i
< acells
+ icells
; i
++) {
585 kprintf ("0x%08X ", ((i
< acells
) ? addrCmp
[i
] : intSpec
[i
-acells
]) & maskCmp
[i
]);
589 kprintf ("no maskCmp\n");
594 for (i
= 0; i
< acells
+ icells
; i
++) {
597 kprintf ("0x%08X ", map
[i
]);
601 for( i
= 0, cmp
= true; cmp
&& (i
< (acells
+ icells
)); i
++) {
602 cell
= (i
< acells
) ? addrCmp
[i
] : intSpec
[ i
- acells
];
605 cmp
= (cell
== map
[i
]);
608 map
+= acells
+ icells
;
609 if( 0 == (parent
= FindPHandle( *(map
++) )))
612 IODTGetICellCounts( parent
, &picells
, &pacells
);
615 intSpec
= map
+ pacells
;
618 map
+= pacells
+ picells
;
620 } while( !cmp
&& (map
< endMap
) );
626 IODTGetICellCounts( parent
, &icells
, &acells
);
632 return( ok
? original_icells
: 0 );
635 IOReturn
IODTGetInterruptOptions( IORegistryEntry
* regEntry
, int source
, IOOptionBits
* options
)
637 OSArray
* controllers
;
638 OSArray
* specifiers
;
645 controllers
= OSDynamicCast(OSArray
, regEntry
->getProperty(gIOInterruptControllersKey
));
646 specifiers
= OSDynamicCast(OSArray
, regEntry
->getProperty(gIOInterruptSpecifiersKey
));
648 if( !controllers
|| !specifiers
)
649 return (kIOReturnNoInterrupt
);
651 shared
= (OSArray
*) gIODTSharedInterrupts
->getObject(
652 (const OSSymbol
*) controllers
->getObject(source
) );
654 return (kIOReturnSuccess
);
656 spec
= specifiers
->getObject(source
);
658 return (kIOReturnNoInterrupt
);
660 for (unsigned int i
= 0;
661 (oneSpec
= shared
->getObject(i
))
662 && (!oneSpec
->isEqualTo(spec
));
666 *options
= kIODTInterruptShared
;
668 return (kIOReturnSuccess
);
671 static bool IODTMapInterruptsSharing( IORegistryEntry
* regEntry
, OSDictionary
* allInts
)
673 IORegistryEntry
* parent
;
682 OSArray
* controllerInts
;
683 const OSSymbol
* controller
= 0;
684 OSArray
* controllers
;
688 nw
= (0 == (local
= OSDynamicCast( OSData
,
689 regEntry
->getProperty( gIODTAAPLInterruptsKey
))));
690 if( nw
&& (0 == (local
= OSDynamicCast( OSData
,
691 regEntry
->getProperty( "interrupts")))))
692 return( true ); // nothing to see here
694 if( nw
&& (parent
= regEntry
->getParentEntry( gIODTPlane
))) {
695 // check for bridges on old world
696 if( (local2
= OSDynamicCast( OSData
,
697 parent
->getProperty( gIODTAAPLInterruptsKey
)))) {
703 localBits
= (UInt32
*) local
->getBytesNoCopy();
704 localEnd
= localBits
+ (local
->getLength() / sizeof(UInt32
));
706 mapped
= OSArray::withCapacity( 1 );
707 controllers
= OSArray::withCapacity( 1 );
709 ok
= (mapped
&& controllers
);
713 skip
= IODTMapOneInterrupt( regEntry
, localBits
, index
, &map
, &controller
);
715 IOLog("%s: error mapping interrupt[%d]\n",
716 regEntry
->getName(), mapped
->getCount());
720 map
= OSData::withData( local
, mapped
->getCount() * sizeof(UInt32
),
722 controller
= gIODTDefaultInterruptController
;
723 controller
->retain();
728 mapped
->setObject( map
);
729 controllers
->setObject( controller
);
733 controllerInts
= (OSArray
*) allInts
->getObject( controller
);
736 for (unsigned int i
= 0; (oneMap
= controllerInts
->getObject(i
)); i
++)
738 if (map
->isEqualTo(oneMap
))
740 controllerInts
= (OSArray
*) gIODTSharedInterrupts
->getObject( controller
);
742 controllerInts
->setObject(map
);
745 controllerInts
= OSArray::withObjects( (const OSObject
**) &map
, 1, 4 );
748 gIODTSharedInterrupts
->setObject( controller
, controllerInts
);
749 controllerInts
->release();
756 controllerInts
->setObject(map
);
760 controllerInts
= OSArray::withObjects( (const OSObject
**) &map
, 1, 16 );
763 allInts
->setObject( controller
, controllerInts
);
764 controllerInts
->release();
770 controller
->release();
772 } while( localBits
< localEnd
);
774 ok
&= (localBits
== localEnd
);
778 ok
= regEntry
->setProperty( gIOInterruptControllersKey
, controllers
);
779 ok
&= regEntry
->setProperty( gIOInterruptSpecifiersKey
, mapped
);
783 controllers
->release();
790 bool IODTMapInterrupts( IORegistryEntry
* regEntry
)
792 return( IODTMapInterruptsSharing( regEntry
, 0 ));
799 CompareKey( OSString
* key
,
800 const IORegistryEntry
* table
, const OSSymbol
* propName
,
801 OSString
** matchingName
)
810 const char *lastName
;
813 const char *result
= 0;
815 if( 0 == (prop
= table
->copyProperty( propName
))) return( 0 );
817 if( (data
= OSDynamicCast( OSData
, prop
))) {
818 names
= (const char *) data
->getBytesNoCopy();
819 lastName
= names
+ data
->getLength();
820 } else if( (string
= OSDynamicCast( OSString
, prop
))) {
821 names
= string
->getCStringNoCopy();
822 lastName
= names
+ string
->getLength() + 1;
826 ckey
= key
->getCStringNoCopy();
827 keyLen
= key
->getLength();
828 wild
= ('*' == key
->getChar( keyLen
- 1 ));
831 // for each name in the property
832 nlen
= strnlen(names
, lastName
- names
);
834 matched
= ((nlen
>= (keyLen
- 1)) && (0 == strncmp(ckey
, names
, keyLen
- 1)));
836 matched
= (keyLen
== nlen
) && (0 == strncmp(ckey
, names
, keyLen
));
841 names
= names
+ nlen
+ 1;
843 } while( (names
< lastName
) && (false == matched
));
846 if (result
&& matchingName
) *matchingName
= OSString::withCString( result
);
848 if (prop
) prop
->release();
850 return (result
!= 0);
854 bool IODTCompareNubName( const IORegistryEntry
* regEntry
,
855 OSString
* name
, OSString
** matchingName
)
859 matched
= CompareKey( name
, regEntry
, gIODTNameKey
, matchingName
)
860 || CompareKey( name
, regEntry
, gIODTCompatibleKey
, matchingName
)
861 || CompareKey( name
, regEntry
, gIODTTypeKey
, matchingName
)
862 || CompareKey( name
, regEntry
, gIODTModelKey
, matchingName
);
867 bool IODTMatchNubWithKeys( IORegistryEntry
* regEntry
,
873 obj
= OSUnserialize( keys
, 0 );
876 result
= regEntry
->compareNames( obj
);
880 else IOLog("Couldn't unserialize %s\n", keys
);
886 OSCollectionIterator
* IODTFindMatchingEntries( IORegistryEntry
* from
,
887 IOOptionBits options
, const char * keys
)
890 IORegistryEntry
*next
;
891 IORegistryIterator
*iter
;
892 OSCollectionIterator
*cIter
;
894 bool minus
= options
& kIODTExclusive
;
897 iter
= IORegistryIterator::iterateOver( from
, gIODTPlane
,
898 (options
& kIODTRecursive
) ? kIORegistryIterateRecursively
: 0 );
905 result
= OSSet::withCapacity( 3 );
910 while( (next
= iter
->getNextObject())) {
912 // Look for existence of a debug property to skip
913 if( next
->getProperty("AAPL,ignore"))
917 cmp
= IODTMatchNubWithKeys( next
, keys
);
918 if( (minus
&& (false == cmp
))
919 || ((false == minus
) && (false != cmp
)) )
920 result
->setObject( next
);
922 result
->setObject( next
);
924 } while( !iter
->isValid());
929 cIter
= OSCollectionIterator::withCollection( result
);
930 if (result
) result
->release();
936 struct IODTPersistent
{
937 IODTCompareAddressCellFunc compareFunc
;
940 void IODTSetResolving( IORegistryEntry
* regEntry
,
941 IODTCompareAddressCellFunc compareFunc
,
942 IODTNVLocationFunc locationFunc __unused
)
944 IODTPersistent persist
;
945 IODTPersistent
* entry
;
947 unsigned int index
, count
;
949 IOLockLock(gIODTResolversLock
);
951 count
= (gIODTResolvers
->getLength() / sizeof(IODTPersistent
));
952 entry
= (typeof(entry
)) gIODTResolvers
->getBytesNoCopy();
953 for (index
= 0; index
< count
; index
++)
955 if (compareFunc
== entry
->compareFunc
) break;
960 persist
.compareFunc
= compareFunc
;
961 if (!gIODTResolvers
->appendBytes(&persist
, sizeof(IODTPersistent
))) panic("IODTSetResolving");
964 IOLockUnlock(gIODTResolversLock
);
966 num
= OSNumber::withNumber(index
, 32);
967 regEntry
->setProperty(gIODTPersistKey
, num
);
968 OSSafeReleaseNULL(num
);
973 #if defined(__arm64__)
974 static SInt64
DefaultCompare( UInt32 cellCount
, UInt32 left
[], UInt32 right
[] )
978 if (cellCount
== 2) {
979 diff
= IOPhysical32(left
[1], left
[0]) - IOPhysical32(right
[1], right
[0]);
980 } else if (cellCount
== 1) {
981 diff
= ( left
[0] - right
[0] );
983 panic("DefaultCompare only knows how to handle 1 or 2 cells.");
988 #elif defined(__arm__) || defined(__i386__) || defined(__x86_64__)
989 static SInt32
DefaultCompare( UInt32 cellCount
, UInt32 left
[], UInt32 right
[] )
992 return( left
[ cellCount
] - right
[ cellCount
] );
995 #error Unknown architecture.
998 static void AddLengthToCells( UInt32 numCells
, UInt32
*cells
, UInt64 offset
)
1002 cells
[0] += (UInt32
)offset
;
1005 #if defined(__arm64__) || defined(__arm__)
1006 UInt64 sum
= cells
[numCells
- 2] + offset
;
1007 cells
[numCells
- 2] = (UInt32
)sum
;
1008 if (sum
> UINT32_MAX
) {
1009 cells
[numCells
- 1] += (UInt32
)(sum
>> 32);
1012 UInt64 sum
= cells
[numCells
- 1] + offset
;
1013 cells
[numCells
- 1] = (UInt32
)sum
;
1014 if (sum
> UINT32_MAX
) {
1015 cells
[numCells
- 2] += (UInt32
)(sum
>> 32);
1021 static IOPhysicalAddress
CellsValue( UInt32 numCells
, UInt32
*cells
)
1023 if (numCells
== 1) {
1024 return IOPhysical32( 0, cells
[0] );
1026 #if defined(__arm64__) || defined(arm)
1027 return IOPhysical32( cells
[numCells
- 1], cells
[numCells
- 2] );
1029 return IOPhysical32( cells
[numCells
- 2], cells
[numCells
- 1] );
1034 void IODTGetCellCounts( IORegistryEntry
* regEntry
,
1035 UInt32
* sizeCount
, UInt32
* addressCount
)
1037 if( !GetUInt32( regEntry
, gIODTSizeCellKey
, sizeCount
))
1039 if( !GetUInt32( regEntry
, gIODTAddressCellKey
, addressCount
))
1044 // Given addr & len cells from our child, find it in our ranges property, then
1045 // look in our parent to resolve the base of the range for us.
1047 // Range[]: child-addr our-addr child-len
1048 // #cells: child ours child
1050 bool IODTResolveAddressCell( IORegistryEntry
* startEntry
,
1052 IOPhysicalAddress
* phys
, IOPhysicalLength
* lenOut
)
1054 IORegistryEntry
* parent
;
1055 IORegistryEntry
* regEntry
;
1058 unsigned int index
, count
;
1059 // cells in addresses at regEntry
1060 UInt32 sizeCells
, addressCells
;
1061 // cells in addresses below regEntry
1062 UInt32 childSizeCells
, childAddressCells
;
1064 UInt32 cell
[ 8 ], propLen
;
1066 UInt32 endCell
[ 8 ];
1072 SInt64 diff
, diff2
, endDiff
;
1073 UInt64 len
, rangeLen
;
1075 IODTPersistent
*persist
;
1076 IODTCompareAddressCellFunc compare
;
1078 regEntry
= startEntry
;
1079 IODTGetCellCounts( regEntry
, &childSizeCells
, &childAddressCells
);
1080 childCells
= childAddressCells
+ childSizeCells
;
1082 if (childCells
> sizeof(cell
)/sizeof(cell
[0]))
1083 panic("IODTResolveAddressCell: Invalid device tree (%u,%u)", (uint32_t)childAddressCells
, (uint32_t)childSizeCells
);
1085 bcopy( cellsIn
, cell
, sizeof(UInt32
) * childCells
);
1086 *lenOut
= CellsValue( childSizeCells
, cellsIn
+ childAddressCells
);
1090 prop
= OSDynamicCast( OSData
, regEntry
->getProperty( gIODTRangeKey
));
1092 /* end of the road */
1093 *phys
= CellsValue( childAddressCells
, cell
);
1095 if (regEntry
!= startEntry
) regEntry
->release();
1099 parent
= regEntry
->copyParentEntry( gIODTPlane
);
1100 IODTGetCellCounts( parent
, &sizeCells
, &addressCells
);
1102 if( (propLen
= prop
->getLength())) {
1104 startRange
= (UInt32
*) prop
->getBytesNoCopy();
1106 endRanges
= range
+ (propLen
/ sizeof(UInt32
));
1109 num
= OSDynamicCast(OSNumber
, regEntry
->getProperty(gIODTPersistKey
));
1112 IOLockLock(gIODTResolversLock
);
1113 index
= num
->unsigned32BitValue();
1114 count
= gIODTResolvers
->getLength() / sizeof(IODTPersistent
);
1117 persist
= ((IODTPersistent
*) gIODTResolvers
->getBytesNoCopy()) + index
;
1118 compare
= persist
->compareFunc
;
1120 IOLockUnlock(gIODTResolversLock
);
1123 if (!compare
&& (addressCells
== childAddressCells
)) {
1124 compare
= DefaultCompare
;
1127 panic("There is no mixed comparison function yet...");
1132 range
+= (childCells
+ addressCells
) ) {
1134 // is cell start within range?
1135 diff
= (*compare
)( childAddressCells
, cell
, range
);
1137 if (childAddressCells
> sizeof(endCell
)/sizeof(endCell
[0]))
1138 panic("IODTResolveAddressCell: Invalid device tree (%u)", (uint32_t)childAddressCells
);
1140 bcopy(range
, endCell
, childAddressCells
* sizeof(UInt32
));
1142 rangeLen
= CellsValue(childSizeCells
, range
+ childAddressCells
+ addressCells
);
1143 AddLengthToCells(childAddressCells
, endCell
, rangeLen
);
1145 diff2
= (*compare
)( childAddressCells
, cell
, endCell
);
1147 // if start of cell < start of range, or end of range >= start of cell, skip
1148 if ((diff
< 0) || (diff2
>= 0))
1151 len
= CellsValue(childSizeCells
, cell
+ childAddressCells
);
1156 // search for cell end
1157 bcopy(cell
, endCell
, childAddressCells
* sizeof(UInt32
));
1159 AddLengthToCells(childAddressCells
, endCell
, len
- 1);
1161 for( lookRange
= startRange
;
1162 lookRange
< endRanges
;
1163 lookRange
+= (childCells
+ addressCells
) )
1165 // make sure end of cell >= range start
1166 endDiff
= (*compare
)( childAddressCells
, endCell
, lookRange
);
1170 UInt64 rangeStart
= CellsValue(addressCells
, range
+ childAddressCells
);
1171 UInt64 lookRangeStart
= CellsValue(addressCells
, lookRange
+ childAddressCells
);
1172 if ((endDiff
- len
+ 1 + lookRangeStart
) == (diff
+ rangeStart
))
1185 if (addressCells
+ sizeCells
> sizeof(cell
)/sizeof(cell
[0]))
1186 panic("IODTResolveAddressCell: Invalid device tree (%u, %u)", (uint32_t)addressCells
, (uint32_t)sizeCells
);
1188 // Get the physical start of the range from our parent
1189 bcopy( range
+ childAddressCells
, cell
, sizeof(UInt32
) * addressCells
);
1190 bzero( cell
+ addressCells
, sizeof(UInt32
) * sizeCells
);
1192 } /* else zero length range => pass thru to parent */
1194 if (regEntry
!= startEntry
) regEntry
->release();
1196 childSizeCells
= sizeCells
;
1197 childAddressCells
= addressCells
;
1198 childCells
= childAddressCells
+ childSizeCells
;
1200 while( ok
&& regEntry
);
1206 OSArray
* IODTResolveAddressing( IORegistryEntry
* regEntry
,
1207 const char * addressPropertyName
,
1208 IODeviceMemory
* parent
)
1210 IORegistryEntry
*parentEntry
;
1211 OSData
*addressProperty
;
1212 UInt32 sizeCells
, addressCells
, cells
;
1215 IOPhysicalAddress phys
;
1216 IOPhysicalLength len
;
1218 IODeviceMemory
*range
;
1223 parentEntry
= regEntry
->copyParentEntry( gIODTPlane
);
1224 addressProperty
= (OSData
*) regEntry
->getProperty( addressPropertyName
);
1225 if( (0 == addressProperty
) || (0 == parentEntry
)) break;
1227 IODTGetCellCounts( parentEntry
, &sizeCells
, &addressCells
);
1228 if( 0 == sizeCells
) break;
1230 cells
= sizeCells
+ addressCells
;
1231 reg
= (UInt32
*) addressProperty
->getBytesNoCopy();
1232 num
= addressProperty
->getLength() / (4 * cells
);
1234 array
= OSArray::withCapacity( 1 );
1235 if( 0 == array
) break;
1237 for( i
= 0; i
< num
; i
++) {
1238 if( IODTResolveAddressCell( parentEntry
, reg
, &phys
, &len
)) {
1241 range
= IODeviceMemory::withSubRange( parent
,
1242 phys
- parent
->getPhysicalSegment(0, 0, kIOMemoryMapperNone
), len
);
1244 range
= IODeviceMemory::withRange( phys
, len
);
1246 array
->setObject( range
);
1251 regEntry
->setProperty( gIODeviceMemoryKey
, array
);
1252 array
->release(); /* ??? */
1256 OSSafeReleaseNULL(parentEntry
);
1261 OSData
* IODTFindSlotName( IORegistryEntry
* regEntry
, UInt32 deviceNumber
)
1263 IORegistryEntry
*parent
;
1273 data
= (OSData
*) regEntry
->getProperty("AAPL,slot-name");
1274 if (data
) return (data
);
1278 parent
= regEntry
->copyParentEntry( gIODTPlane
);
1281 data
= OSDynamicCast( OSData
, parent
->getProperty("slot-names"));
1283 if (data
->getLength() <= 4) break;
1285 bits
= (UInt32
*) data
->getBytesNoCopy();
1287 if ((0 == (mask
& (1 << deviceNumber
)))) break;
1289 names
= (char *)(bits
+ 1);
1290 lastName
= names
+ (data
->getLength() - 4);
1292 for( i
= 0; (i
<= deviceNumber
) && (names
< lastName
); i
++ ) {
1294 if( mask
& (1 << i
)) {
1295 nlen
= 1 + strnlen(names
, lastName
- names
);
1296 if( i
== deviceNumber
) {
1297 data
= OSData::withBytesNoCopy(names
, nlen
);
1299 regEntry
->setProperty("AAPL,slot-name", data
);
1310 OSSafeReleaseNULL(parent
);
1315 extern "C" IOReturn
IONDRVLibrariesInitialize( IOService
* provider
)
1317 return( kIOReturnUnsupported
);