]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOPlatformExpert.cpp
xnu-792.25.20.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPlatformExpert.cpp
index 7faa1698647e73b42b7b7cfae25b2ba81a97f786..084975498c48438e7d3cafe3daff11dee89478e1 100644 (file)
  * HISTORY
  */
  
-#include <IOKit/system.h>
-#include <IOKit/IOPlatformExpert.h>
 #include <IOKit/IOCPU.h>
 #include <IOKit/IODeviceTreeSupport.h>
-#include <IOKit/IORangeAllocator.h>
-#include <IOKit/IONVRAM.h>
 #include <IOKit/IOKitDebug.h>
+#include <IOKit/IOMapper.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/IONVRAM.h>
+#include <IOKit/IOPlatformExpert.h>
+#include <IOKit/IORangeAllocator.h>
 #include <IOKit/IOWorkLoop.h>
 #include <IOKit/pwr_mgt/RootDomain.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/IOTimeStamp.h>
 
-#include <libkern/c++/OSContainers.h>
+#include <IOKit/system.h>
 
+#include <libkern/c++/OSContainers.h>
 
 extern "C" {
 #include <machine/machine_routines.h>
 #include <pexpert/pexpert.h>
 }
 
+/* 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 ));