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