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