X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3903760236c30e3b5ace7a4eefac3a269d68957c..d9a64523371fa019c4575bb400cbbc3a50ac9903:/iokit/Kernel/IODeviceTreeSupport.cpp diff --git a/iokit/Kernel/IODeviceTreeSupport.cpp b/iokit/Kernel/IODeviceTreeSupport.cpp index c66265be1..1a3b426d8 100644 --- a/iokit/Kernel/IODeviceTreeSupport.cpp +++ b/iokit/Kernel/IODeviceTreeSupport.cpp @@ -37,7 +37,11 @@ #include +#if __arm64__ +typedef UInt64 dtptr_t; +#else typedef UInt32 dtptr_t; +#endif #include @@ -55,8 +59,9 @@ int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize ); const IORegistryPlane * gIODTPlane; -static OSArray * gIODTPHandles; -static OSArray * gIODTPHandleMap; +static OSArray * gIODTPHandles; +static OSArray * gIODTPHandleMap; +static OSData * gIODTResolvers; const OSSymbol * gIODTNameKey; const OSSymbol * gIODTUnitKey; @@ -80,6 +85,8 @@ const OSSymbol * gIODTNWInterruptMappingKey; OSDictionary * gIODTSharedInterrupts; +static IOLock * gIODTResolversLock; + static IORegistryEntry * MakeReferenceTable( DTEntry dtEntry, bool copy ); static void AddPHandle( IORegistryEntry * regEntry ); static void FreePhysicalMemory( vm_offset_t * range ); @@ -91,7 +98,7 @@ IODeviceTreeAlloc( void * dtTop ) IORegistryEntry * parent; IORegistryEntry * child; IORegistryIterator * regIter; - DTEntryIterator iter; + OpaqueDTEntryIterator iter; DTEntry dtChild; DTEntry mapEntry; OSArray * stack; @@ -135,6 +142,9 @@ IODeviceTreeAlloc( void * dtTop ) gIODTPHandles = OSArray::withCapacity( 1 ); gIODTPHandleMap = OSArray::withCapacity( 1 ); + gIODTResolvers = OSData::withCapacity(16); + + gIODTResolversLock = IOLockAlloc(); gIODTInterruptCellKey = OSSymbol::withCStringNoCopy("#interrupt-cells"); @@ -142,7 +152,7 @@ IODeviceTreeAlloc( void * dtTop ) assert( gIODTDefaultInterruptController && gIODTNWInterruptMappingKey && gIODTAAPLInterruptsKey && gIODTPHandleKey && gIODTInterruptParentKey - && gIODTPHandles && gIODTPHandleMap + && gIODTPHandles && gIODTPHandleMap && gIODTResolvers && gIODTResolversLock && gIODTInterruptCellKey ); @@ -154,21 +164,21 @@ IODeviceTreeAlloc( void * dtTop ) parent = MakeReferenceTable( (DTEntry)dtTop, freeDT ); stack = OSArray::withObjects( (const OSObject **) &parent, 1, 10 ); - DTCreateEntryIterator( (DTEntry)dtTop, &iter ); + DTInitEntryIterator( (DTEntry)dtTop, &iter ); do { parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1); //parent->release(); stack->removeObject( stack->getCount() - 1); - while( kSuccess == DTIterateEntries( iter, &dtChild) ) { + while( kSuccess == DTIterateEntries( &iter, &dtChild) ) { child = MakeReferenceTable( dtChild, freeDT ); child->attachToParent( parent, gIODTPlane); AddPHandle( child ); - if( kSuccess == DTEnterEntry( iter, dtChild)) { + if( kSuccess == DTEnterEntry( &iter, dtChild)) { stack->setObject( parent); parent = child; } @@ -177,10 +187,10 @@ IODeviceTreeAlloc( void * dtTop ) } } while( stack->getCount() - && (kSuccess == DTExitEntry( iter, &dtChild))); + && (kSuccess == DTExitEntry( &iter, &dtChild))); stack->release(); - DTDisposeEntryIterator( iter); + assert(kSuccess != DTExitEntry(&iter, &dtChild)); // parent is now root of the created tree @@ -257,23 +267,29 @@ int IODTGetLoaderInfo( const char *key, void **infoAddr, int *infoSize ) OSData *propObj; dtptr_t *propPtr; unsigned int propSize; + int ret = -1; chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ); if ( chosen == 0 ) return -1; propObj = OSDynamicCast( OSData, chosen->getProperty(key) ); - if ( propObj == 0 ) return -1; + if ( propObj == 0 ) goto cleanup; propSize = propObj->getLength(); - if ( propSize != (2 * sizeof(dtptr_t)) ) return -1; + if ( propSize != (2 * sizeof(dtptr_t)) ) goto cleanup; propPtr = (dtptr_t *)propObj->getBytesNoCopy(); - if ( propPtr == 0 ) return -1; + if ( propPtr == 0 ) goto cleanup; *infoAddr = (void *)(uintptr_t) (propPtr[0]); *infoSize = (int) (propPtr[1]); - return 0; + ret = 0; + +cleanup: + chosen->release(); + + return ret; } void IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize ) @@ -289,6 +305,7 @@ void IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize ) chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ); if ( chosen != 0 ) { chosen->removeProperty(key); + chosen->release(); } } } @@ -331,12 +348,13 @@ MakeReferenceTable( DTEntry dtEntry, bool copy ) const OSSymbol *nameKey; OSData *data; const OSSymbol *sym; - DTPropertyIterator dtIter; + OpaqueDTPropertyIterator dtIter; void *prop; unsigned int propSize; char *name; char location[ 32 ]; bool noLocation = true; + bool kernelOnly; regEntry = new IOService; @@ -346,11 +364,12 @@ MakeReferenceTable( DTEntry dtEntry, bool copy ) } if( regEntry && - (kSuccess == DTCreatePropertyIterator( dtEntry, &dtIter))) { + (kSuccess == DTInitPropertyIterator( dtEntry, &dtIter))) { + kernelOnly = (kSuccess == DTGetProperty(dtEntry, "kernel-only", &prop, &propSize)); propTable = regEntry->getPropertyTable(); - while( kSuccess == DTIterateProperties( dtIter, &name)) { + while( kSuccess == DTIterateProperties( &dtIter, &name)) { if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize )) continue; @@ -364,6 +383,9 @@ MakeReferenceTable( DTEntry dtEntry, bool copy ) } assert( nameKey && data ); + if (kernelOnly) + data->setSerializable(false); + propTable->setObject( nameKey, data); data->release(); nameKey->release(); @@ -392,7 +414,6 @@ MakeReferenceTable( DTEntry dtEntry, bool copy ) regEntry->setLocation( location ); } } - DTDisposePropertyIterator( dtIter); } return( regEntry); @@ -914,29 +935,57 @@ OSCollectionIterator * IODTFindMatchingEntries( IORegistryEntry * from, struct IODTPersistent { IODTCompareAddressCellFunc compareFunc; - IODTNVLocationFunc locationFunc; }; void IODTSetResolving( IORegistryEntry * regEntry, IODTCompareAddressCellFunc compareFunc, - IODTNVLocationFunc locationFunc ) + IODTNVLocationFunc locationFunc __unused ) { - IODTPersistent persist; - OSData *prop; - - persist.compareFunc = compareFunc; - persist.locationFunc = locationFunc; - prop = OSData::withBytes( &persist, sizeof(persist)); - if( !prop) - return; - - prop->setSerializable(false); - regEntry->setProperty( gIODTPersistKey, prop); - prop->release(); + IODTPersistent persist; + IODTPersistent * entry; + OSNumber * num; + unsigned int index, count; + + IOLockLock(gIODTResolversLock); + + count = (gIODTResolvers->getLength() / sizeof(IODTPersistent)); + entry = (typeof(entry)) gIODTResolvers->getBytesNoCopy(); + for (index = 0; index < count; index++) + { + if (compareFunc == entry->compareFunc) break; + entry++; + } + if (index == count) + { + persist.compareFunc = compareFunc; + if (!gIODTResolvers->appendBytes(&persist, sizeof(IODTPersistent))) panic("IODTSetResolving"); + } + + IOLockUnlock(gIODTResolversLock); + + num = OSNumber::withNumber(index, 32); + regEntry->setProperty(gIODTPersistKey, num); + OSSafeReleaseNULL(num); + return; } -#if defined(__arm__) || defined(__i386__) || defined(__x86_64__) +#if defined(__arm64__) +static SInt64 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] ) +{ + SInt64 diff = 0; + + if (cellCount == 2) { + diff = IOPhysical32(left[1], left[0]) - IOPhysical32(right[1], right[0]); + } else if (cellCount == 1) { + diff = ( left[0] - right[0] ); + } else { + panic("DefaultCompare only knows how to handle 1 or 2 cells."); + } + + return diff; +} +#elif defined(__arm__) || defined(__i386__) || defined(__x86_64__) static SInt32 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] ) { cellCount--; @@ -953,11 +1002,19 @@ static void AddLengthToCells( UInt32 numCells, UInt32 *cells, UInt64 offset) cells[0] += (UInt32)offset; } else { +#if defined(__arm64__) || defined(__arm__) + UInt64 sum = cells[numCells - 2] + offset; + cells[numCells - 2] = (UInt32)sum; + if (sum > UINT32_MAX) { + cells[numCells - 1] += (UInt32)(sum >> 32); + } +#else UInt64 sum = cells[numCells - 1] + offset; cells[numCells - 1] = (UInt32)sum; if (sum > UINT32_MAX) { cells[numCells - 2] += (UInt32)(sum >> 32); } +#endif } } @@ -966,7 +1023,11 @@ static IOPhysicalAddress CellsValue( UInt32 numCells, UInt32 *cells) if (numCells == 1) { return IOPhysical32( 0, cells[0] ); } else { +#if defined(__arm64__) || defined(arm) + return IOPhysical32( cells[numCells - 1], cells[numCells - 2] ); +#else return IOPhysical32( cells[numCells - 2], cells[numCells - 1] ); +#endif } } @@ -986,12 +1047,15 @@ void IODTGetCellCounts( IORegistryEntry * regEntry, // Range[]: child-addr our-addr child-len // #cells: child ours child -bool IODTResolveAddressCell( IORegistryEntry * regEntry, +bool IODTResolveAddressCell( IORegistryEntry * startEntry, UInt32 cellsIn[], IOPhysicalAddress * phys, IOPhysicalLength * lenOut ) { - IORegistryEntry *parent; - OSData *prop; + IORegistryEntry * parent; + IORegistryEntry * regEntry; + OSData * prop; + OSNumber * num; + unsigned int index, count; // cells in addresses at regEntry UInt32 sizeCells, addressCells; // cells in addresses below regEntry @@ -1011,6 +1075,7 @@ bool IODTResolveAddressCell( IORegistryEntry * regEntry, IODTPersistent *persist; IODTCompareAddressCellFunc compare; + regEntry = startEntry; IODTGetCellCounts( regEntry, &childSizeCells, &childAddressCells ); childCells = childAddressCells + childSizeCells; @@ -1027,10 +1092,11 @@ bool IODTResolveAddressCell( IORegistryEntry * regEntry, /* end of the road */ *phys = CellsValue( childAddressCells, cell ); *phys += offset; + if (regEntry != startEntry) regEntry->release(); break; } - parent = regEntry->getParentEntry( gIODTPlane ); + parent = regEntry->copyParentEntry( gIODTPlane ); IODTGetCellCounts( parent, &sizeCells, &addressCells ); if( (propLen = prop->getLength())) { @@ -1039,13 +1105,25 @@ bool IODTResolveAddressCell( IORegistryEntry * regEntry, range = startRange; endRanges = range + (propLen / sizeof(UInt32)); - prop = (OSData *) regEntry->getProperty( gIODTPersistKey ); - if( prop) { - persist = (IODTPersistent *) prop->getBytesNoCopy(); - compare = persist->compareFunc; - } else if (addressCells == childAddressCells) { + compare = NULL; + num = OSDynamicCast(OSNumber, regEntry->getProperty(gIODTPersistKey)); + if (num) + { + IOLockLock(gIODTResolversLock); + index = num->unsigned32BitValue(); + count = gIODTResolvers->getLength() / sizeof(IODTPersistent); + if (index < count) + { + persist = ((IODTPersistent *) gIODTResolvers->getBytesNoCopy()) + index; + compare = persist->compareFunc; + } + IOLockUnlock(gIODTResolversLock); + } + + if (!compare && (addressCells == childAddressCells)) { compare = DefaultCompare; - } else { + } + if (!compare) { panic("There is no mixed comparison function yet..."); } @@ -1113,6 +1191,7 @@ bool IODTResolveAddressCell( IORegistryEntry * regEntry, } /* else zero length range => pass thru to parent */ + if (regEntry != startEntry) regEntry->release(); regEntry = parent; childSizeCells = sizeCells; childAddressCells = addressCells; @@ -1138,107 +1217,45 @@ OSArray * IODTResolveAddressing( IORegistryEntry * regEntry, OSArray *array; IODeviceMemory *range; - parentEntry = regEntry->getParentEntry( gIODTPlane ); - addressProperty = (OSData *) regEntry->getProperty( addressPropertyName ); - if( (0 == addressProperty) || (0 == parentEntry)) - return( 0); - - IODTGetCellCounts( parentEntry, &sizeCells, &addressCells ); - if( 0 == sizeCells) - return( 0); - - cells = sizeCells + addressCells; - reg = (UInt32 *) addressProperty->getBytesNoCopy(); - num = addressProperty->getLength() / (4 * cells); - - array = OSArray::withCapacity( 1 ); - if( 0 == array) - return( 0); - - for( i = 0; i < num; i++) { - if( IODTResolveAddressCell( parentEntry, reg, &phys, &len )) { - range = 0; - if( parent) - range = IODeviceMemory::withSubRange( parent, - phys - parent->getPhysicalSegment(0, 0, kIOMemoryMapperNone), len ); - if( 0 == range) - range = IODeviceMemory::withRange( phys, len ); - if( range) - array->setObject( range ); + array = 0; + do + { + parentEntry = regEntry->copyParentEntry( gIODTPlane ); + addressProperty = (OSData *) regEntry->getProperty( addressPropertyName ); + if( (0 == addressProperty) || (0 == parentEntry)) break; + + IODTGetCellCounts( parentEntry, &sizeCells, &addressCells ); + if( 0 == sizeCells) break; + + cells = sizeCells + addressCells; + reg = (UInt32 *) addressProperty->getBytesNoCopy(); + num = addressProperty->getLength() / (4 * cells); + + array = OSArray::withCapacity( 1 ); + if( 0 == array) break; + + for( i = 0; i < num; i++) { + if( IODTResolveAddressCell( parentEntry, reg, &phys, &len )) { + range = 0; + if( parent) + range = IODeviceMemory::withSubRange( parent, + phys - parent->getPhysicalSegment(0, 0, kIOMemoryMapperNone), len ); + if( 0 == range) + range = IODeviceMemory::withRange( phys, len ); + if( range) + array->setObject( range ); + } + reg += cells; } - reg += cells; - } - regEntry->setProperty( gIODeviceMemoryKey, array); - array->release(); /* ??? */ - - return( array); -} - -static void IODTGetNVLocation( - IORegistryEntry * parent, - IORegistryEntry * regEntry, - UInt8 * busNum, UInt8 * deviceNum, UInt8 * functionNum ) -{ - - OSData *prop; - IODTPersistent *persist; - UInt32 *cell; - - prop = (OSData *) parent->getProperty( gIODTPersistKey ); - if( prop) { - persist = (IODTPersistent *) prop->getBytesNoCopy(); - (*persist->locationFunc)( regEntry, busNum, deviceNum, functionNum ); - } else { - prop = (OSData *) regEntry->getProperty( "reg" ); - *functionNum = 0; - if( prop) { - cell = (UInt32 *) prop->getBytesNoCopy(); - *busNum = 3; - *deviceNum = 0x1f & (cell[ 0 ] >> 24); - } else { - *busNum = 0; - *deviceNum = 0; - } + regEntry->setProperty( gIODeviceMemoryKey, array); + array->release(); /* ??? */ } - return; -} + while (false); -/* - * Try to make the same messed up descriptor as Mac OS - */ - -IOReturn IODTMakeNVDescriptor( IORegistryEntry * regEntry, - IONVRAMDescriptor * hdr ) -{ - IORegistryEntry *parent; - UInt32 level; - UInt32 bridgeDevices; - UInt8 busNum; - UInt8 deviceNum; - UInt8 functionNum; - - hdr->format = 1; - hdr->marker = 0; - - for(level = 0, bridgeDevices = 0; - (parent = regEntry->getParentEntry( gIODTPlane )) && (level < 7); level++ ) { - - IODTGetNVLocation( parent, regEntry, - &busNum, &deviceNum, &functionNum ); - if( level) - bridgeDevices |= ((deviceNum & 0x1f) << ((level - 1) * 5)); - else { - hdr->busNum = busNum; - hdr->deviceNum = deviceNum; - hdr->functionNum = functionNum; - } - regEntry = parent; - } - hdr->bridgeCount = level - 2; - hdr->bridgeDevices = bridgeDevices; + OSSafeReleaseNULL(parentEntry); - return( kIOReturnSuccess ); + return (array); } OSData * IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber ) @@ -1254,40 +1271,43 @@ OSData * IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber ) UInt32 mask; data = (OSData *) regEntry->getProperty("AAPL,slot-name"); - if( data) - return( data); - parent = regEntry->getParentEntry( gIODTPlane ); - if( !parent) - return( 0 ); - data = OSDynamicCast( OSData, parent->getProperty("slot-names")); - if( !data) - return( 0 ); - if( data->getLength() <= 4) - return( 0 ); - - bits = (UInt32 *) data->getBytesNoCopy(); - mask = *bits; - if( (0 == (mask & (1 << deviceNumber)))) - return( 0 ); - - names = (char *)(bits + 1); - lastName = names + (data->getLength() - 4); - - for( i = 0; (i <= deviceNumber) && (names < lastName); i++ ) { - - if( mask & (1 << i)) { - nlen = 1 + strnlen(names, lastName - names); - if( i == deviceNumber) { - data = OSData::withBytesNoCopy(names, nlen); - if( data) { - regEntry->setProperty("AAPL,slot-name", data); - ret = data; - data->release(); - } - } else - names += nlen; + if (data) return (data); + + do + { + parent = regEntry->copyParentEntry( gIODTPlane ); + if (!parent) break; + + data = OSDynamicCast( OSData, parent->getProperty("slot-names")); + if (!data) break; + if (data->getLength() <= 4) break; + + bits = (UInt32 *) data->getBytesNoCopy(); + mask = *bits; + if ((0 == (mask & (1 << deviceNumber)))) break; + + names = (char *)(bits + 1); + lastName = names + (data->getLength() - 4); + + for( i = 0; (i <= deviceNumber) && (names < lastName); i++ ) { + + if( mask & (1 << i)) { + nlen = 1 + strnlen(names, lastName - names); + if( i == deviceNumber) { + data = OSData::withBytesNoCopy(names, nlen); + if( data) { + regEntry->setProperty("AAPL,slot-name", data); + ret = data; + data->release(); + } + } else + names += nlen; + } } } + while (false); + + OSSafeReleaseNULL(parent); return( ret ); }