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