X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..0c530ab8987f0ae6a1a3d9284f40182b88852816:/iokit/Kernel/IOPlatformExpert.cpp diff --git a/iokit/Kernel/IOPlatformExpert.cpp b/iokit/Kernel/IOPlatformExpert.cpp index 7faa16986..084975498 100644 --- a/iokit/Kernel/IOPlatformExpert.cpp +++ b/iokit/Kernel/IOPlatformExpert.cpp @@ -23,24 +23,31 @@ * HISTORY */ -#include -#include #include #include -#include -#include #include +#include +#include +#include +#include +#include #include #include +#include +#include -#include +#include +#include extern "C" { #include #include } +/* Delay period for UPS halt */ +#define kUPSDelayHaltCPU_msec (1000*60*5) + void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg); static void getCStringForObject (OSObject * inObj, char * outStr); @@ -50,8 +57,9 @@ static void getCStringForObject (OSObject * inObj, char * outStr); OSDefineMetaClassAndStructors(IOPlatformExpert, IOService) -OSMetaClassDefineReservedUnused(IOPlatformExpert, 0); -OSMetaClassDefineReservedUnused(IOPlatformExpert, 1); +OSMetaClassDefineReservedUsed(IOPlatformExpert, 0); + +OSMetaClassDefineReservedUsed(IOPlatformExpert, 1); OSMetaClassDefineReservedUnused(IOPlatformExpert, 2); OSMetaClassDefineReservedUnused(IOPlatformExpert, 3); OSMetaClassDefineReservedUnused(IOPlatformExpert, 4); @@ -64,6 +72,8 @@ OSMetaClassDefineReservedUnused(IOPlatformExpert, 10); OSMetaClassDefineReservedUnused(IOPlatformExpert, 11); static IOPlatformExpert * gIOPlatform; +static OSDictionary * gIOInterruptControllers; +static IOLock * gIOInterruptControllersLock; OSSymbol * gPlatformInterruptControllerName; @@ -82,10 +92,22 @@ bool IOPlatformExpert::start( IOService * provider ) { IORangeAllocator * physicalRanges; OSData * busFrequency; + uint32_t debugFlags; if (!super::start(provider)) return false; + // Override the mapper present flag is requested by boot arguments. + if (PE_parse_boot_arg("dart", &debugFlags) && (debugFlags == 0)) + removeProperty(kIOPlatformMapperPresentKey); + + // Register the presence or lack thereof a system + // PCI address mapper with the IOMapper class + IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey)); + + gIOInterruptControllers = OSDictionary::withCapacity(1); + gIOInterruptControllersLock = IOLockAlloc(); + // Correct the bus frequency in the device tree. busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4); provider->setProperty("clock-frequency", busFrequency); @@ -103,6 +125,16 @@ bool IOPlatformExpert::start( IOService * provider ) PMInstantiatePowerDomains(); + // Parse the serial-number data and publish a user-readable string + OSData* mydata = (OSData*) (provider->getProperty("serial-number")); + if (mydata != NULL) { + OSString *serNoString = createSystemSerialNumberString(mydata); + if (serNoString != NULL) { + provider->setProperty(kIOPlatformSerialNumberKey, serNoString); + serNoString->release(); + } + } + return( configure(provider) ); } @@ -146,7 +178,7 @@ IOService * IOPlatformExpert::createNub( OSDictionary * from ) } bool IOPlatformExpert::compareNubName( const IOService * nub, - OSString * name, OSString ** matched = 0 ) const + OSString * name, OSString ** matched ) const { return( nub->IORegistryEntry::compareName( name, matched )); } @@ -196,6 +228,11 @@ bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/) return( false ); } +OSString* IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty) +{ + return NULL; +} + IORangeAllocator * IOPlatformExpert::getPhysicalRangeAllocator(void) { return(OSDynamicCast(IORangeAllocator, @@ -206,6 +243,18 @@ int (*PE_halt_restart)(unsigned int type) = 0; int IOPlatformExpert::haltRestart(unsigned int type) { + if (type == kPEHangCPU) while (1); + + if (type == kPEUPSDelayHaltCPU) { + // Stall shutdown for 5 minutes, and if no outside force has + // removed our power at that point, proceed with a reboot. + IOSleep( kUPSDelayHaltCPU_msec ); + + // Ideally we never reach this point. + + type = kPERestartCPU; + } + kprintf("platform halt restart\n"); if (PE_halt_restart) return (*PE_halt_restart)(type); else return -1; } @@ -255,21 +304,36 @@ IOReturn IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo, IOReturn IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterruptController *interruptController) { - publishResource(name, interruptController); + IOLockLock(gIOInterruptControllersLock); + + gIOInterruptControllers->setObject(name, interruptController); + + IOLockWakeup(gIOInterruptControllersLock, + gIOInterruptControllers, /* one-thread */ false); + + IOLockUnlock(gIOInterruptControllersLock); return kIOReturnSuccess; } IOInterruptController *IOPlatformExpert::lookUpInterruptController(OSSymbol *name) { - IOInterruptController *interruptController; - IOService *service; + OSObject *object; - service = waitForService(resourceMatching(name)); - - interruptController = OSDynamicCast(IOInterruptController, service->getProperty(name)); + IOLockLock(gIOInterruptControllersLock); + while (1) { + + object = gIOInterruptControllers->getObject(name); + + if (object != 0) + break; + + IOLockSleep(gIOInterruptControllersLock, + gIOInterruptControllers, THREAD_UNINT); + } - return interruptController; + IOLockUnlock(gIOInterruptControllersLock); + return OSDynamicCast(IOInterruptController, object); } @@ -297,11 +361,44 @@ bool IOPlatformExpert::platformAdjustService(IOService */*service*/) // //********************************************************************************* -void IOPlatformExpert::PMLog(const char * who,unsigned long event,unsigned long param1, unsigned long param2) +void IOPlatformExpert:: +PMLog(const char *who, unsigned long event, + unsigned long param1, unsigned long param2) { - if( gIOKitDebug & kIOLogPower) { - kprintf("%s %02d %08x %08x\n",who,event,param1,param2); -// IOLog("%s %02d %08x %08x\n",who,event,param1,param2); + UInt32 debugFlags = gIOKitDebug; + + if (debugFlags & kIOLogPower) { + + uint32_t nows, nowus; + clock_get_system_microtime(&nows, &nowus); + nowus += (nows % 1000) * 1000000; + + kprintf("pm%u %x %.30s %d %x %x\n", + nowus, (unsigned) current_thread(), who, // Identity + (int) event, param1, param2); // Args + + if (debugFlags & kIOLogTracePower) { + static const UInt32 sStartStopBitField[] = + { 0x00000000, 0x00000040 }; // Only Program Hardware so far + + // Arcane formula from Hacker's Delight by Warren + // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31)) + UInt32 sgnevent = ((long) event >> 31); + UInt32 absevent = sgnevent ^ (event + sgnevent); + UInt32 code = IODBG_POWER(absevent); + + UInt32 bit = 1 << (absevent & 0x1f); + if (absevent < sizeof(sStartStopBitField) * 8 + && (sStartStopBitField[absevent >> 5] & bit) ) { + // Or in the START or END bits, Start = 1 & END = 2 + // If sgnevent == 0 then START - 0 => START + // else if sgnevent == -1 then START - -1 => END + code |= DBG_FUNC_START - sgnevent; + } + + // Record the timestamp, wish I had a this pointer + IOTimeStampConstant(code, (UInt32) who, event, param1, param2); + } } } @@ -628,6 +725,20 @@ static void getCStringForObject (OSObject * inObj, char * outStr) } } +/* IOShutdownNotificationsTimedOut + * - Called from a timer installed by PEHaltRestart + */ +static void IOShutdownNotificationsTimedOut( + thread_call_param_t p0, + thread_call_param_t p1) +{ + int type = (int)p0; + + /* 30 seconds has elapsed - resume shutdown */ + if(gIOPlatform) gIOPlatform->haltRestart(type); +} + + extern "C" { /* @@ -660,22 +771,71 @@ int PEGetPlatformEpoch(void) int PEHaltRestart(unsigned int type) { + IOPMrootDomain *pmRootDomain = IOService::getPMRootDomain(); + bool noWaitForResponses; + AbsoluteTime deadline; + thread_call_t shutdown_hang; + unsigned int tell_type; + + if(type == kPEHaltCPU || type == kPERestartCPU || type == kPEUPSDelayHaltCPU) + { + /* Notify IOKit PM clients of shutdown/restart + Clients subscribe to this message with a call to + IOService::registerInterest() + */ + + /* Spawn a thread that will panic in 30 seconds. + If all goes well the machine will be off by the time + the timer expires. + */ + shutdown_hang = thread_call_allocate( &IOShutdownNotificationsTimedOut, + (thread_call_param_t) type); + clock_interval_to_deadline( 30, kSecondScale, &deadline ); + thread_call_enter1_delayed( shutdown_hang, 0, deadline ); + + + if( kPEUPSDelayHaltCPU == type ) { + tell_type = kPEHaltCPU; + } else { + tell_type = type; + } + + noWaitForResponses = pmRootDomain->tellChangeDown2(tell_type); + /* This notification should have few clients who all do + their work synchronously. + + In this "shutdown notification" context we don't give + drivers the option of working asynchronously and responding + later. PM internals make it very hard to wait for asynchronous + replies. In fact, it's a bad idea to even be calling + tellChangeDown2 from here at all. + */ + } + if (gIOPlatform) return gIOPlatform->haltRestart(type); else return -1; } +UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length) +{ + if (gIOPlatform != 0) return gIOPlatform->savePanicInfo(buffer, length); + else return 0; +} + long PEGetGMTTimeOfDay(void) { + long result = 0; + if( gIOPlatform) - return( gIOPlatform->getGMTTimeOfDay()); - else - return( 0 ); + result = gIOPlatform->getGMTTimeOfDay(); + + return (result); } void PESetGMTTimeOfDay(long secs) { if( gIOPlatform) - gIOPlatform->setGMTTimeOfDay(secs); + gIOPlatform->setGMTTimeOfDay(secs); } } /* extern "C" */ @@ -706,6 +866,10 @@ IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName, param1, param2, param3, param4); } +IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length) +{ + return 0; +} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -783,7 +947,7 @@ bool IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter ) return( ok ); } -void IODTPlatformExpert::processTopLevel( IORegistryEntry * root ) +void IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry ) { OSIterator * kids; IORegistryEntry * next; @@ -791,7 +955,7 @@ void IODTPlatformExpert::processTopLevel( IORegistryEntry * root ) IORegistryEntry * options; // infanticide - kids = IODTFindMatchingEntries( root, 0, deleteList() ); + kids = IODTFindMatchingEntries( rootEntry, 0, deleteList() ); if( kids) { while( (next = (IORegistryEntry *)kids->getNextObject())) { next->detachAll( gIODTPlane); @@ -800,7 +964,7 @@ void IODTPlatformExpert::processTopLevel( IORegistryEntry * root ) } // Publish an IODTNVRAM class on /options. - options = root->childFromPath("options", gIODTPlane); + options = rootEntry->childFromPath("options", gIODTPlane); if (options) { dtNVRAM = new IODTNVRAM; if (dtNVRAM) { @@ -815,12 +979,12 @@ void IODTPlatformExpert::processTopLevel( IORegistryEntry * root ) } // Publish the cpus. - cpus = root->childFromPath( "cpus", gIODTPlane); + cpus = rootEntry->childFromPath( "cpus", gIODTPlane); if ( cpus) createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, 0)); // publish top level, minus excludeList - createNubs( this, IODTFindMatchingEntries( root, kIODTExclusive, excludeList())); + createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList())); } IOReturn IODTPlatformExpert::getNubResources( IOService * nub ) @@ -934,6 +1098,74 @@ IOReturn IODTPlatformExpert::writeNVRAMProperty( else return kIOReturnNotReady; } +OSDictionary *IODTPlatformExpert::getNVRAMPartitions(void) +{ + if (dtNVRAM) return dtNVRAM->getNVRAMPartitions(); + else return 0; +} + +IOReturn IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID, + IOByteCount offset, UInt8 * buffer, + IOByteCount length) +{ + if (dtNVRAM) return dtNVRAM->readNVRAMPartition(partitionID, offset, + buffer, length); + else return kIOReturnNotReady; +} + +IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID, + IOByteCount offset, UInt8 * buffer, + IOByteCount length) +{ + if (dtNVRAM) return dtNVRAM->writeNVRAMPartition(partitionID, offset, + buffer, length); + else return kIOReturnNotReady; +} + +IOByteCount IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length) +{ + IOByteCount lengthSaved = 0; + + if (dtNVRAM) lengthSaved = dtNVRAM->savePanicInfo(buffer, length); + + if (lengthSaved == 0) lengthSaved = super::savePanicInfo(buffer, length); + + return lengthSaved; +} + +OSString* IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty) { + UInt8* serialNumber; + unsigned int serialNumberSize; + unsigned short pos = 0; + char* temp; + char SerialNo[30]; + + if (myProperty != NULL) { + serialNumberSize = myProperty->getLength(); + serialNumber = (UInt8*)(myProperty->getBytesNoCopy()); + temp = (char*)serialNumber; + if (serialNumberSize > 0) { + // check to see if this is a CTO serial number... + while (pos < serialNumberSize && temp[pos] != '-') pos++; + + if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number + memcpy(SerialNo, serialNumber + 12, 8); + memcpy(&SerialNo[8], serialNumber, 3); + SerialNo[11] = '-'; + memcpy(&SerialNo[12], serialNumber + 3, 8); + SerialNo[20] = 0; + } else { // just a normal serial number + memcpy(SerialNo, serialNumber + 13, 8); + memcpy(&SerialNo[8], serialNumber, 3); + SerialNo[11] = 0; + } + return OSString::withCString(SerialNo); + } + } + return NULL; +} + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super @@ -949,7 +1181,7 @@ OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool IOPlatformExpertDevice::compareName( OSString * name, - OSString ** matched = 0 ) const + OSString ** matched ) const { return( IODTCompareNubName( this, name, matched )); } @@ -996,6 +1228,12 @@ void IOPlatformExpertDevice::free() workLoop->release(); } +bool IOPlatformExpertDevice::attachToChild( IORegistryEntry * child, + const IORegistryPlane * plane ) +{ + return IOService::attachToChild( child, plane ); +} + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super @@ -1011,7 +1249,7 @@ OSMetaClassDefineReservedUnused(IOPlatformDevice, 3); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool IOPlatformDevice::compareName( OSString * name, - OSString ** matched = 0 ) const + OSString ** matched ) const { return( ((IOPlatformExpert *)getProvider())-> compareNubName( this, name, matched ));