]> 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 0f07f4e757f90745c4d30fb98f2030081d2fab41..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/IOMessage.h>
-#include <libkern/c++/OSContainers.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/IOTimeStamp.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);
@@ -84,10 +92,19 @@ 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();
     
@@ -108,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) );
 }
 
@@ -151,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 ));
 }
@@ -201,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,
@@ -211,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;
 }
@@ -264,8 +308,9 @@ IOReturn IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterru
   
   gIOInterruptControllers->setObject(name, interruptController);
   
-  thread_wakeup(gIOInterruptControllers);
-  
+  IOLockWakeup(gIOInterruptControllersLock,
+               gIOInterruptControllers, /* one-thread */ false);
+
   IOLockUnlock(gIOInterruptControllersLock);
   
   return kIOReturnSuccess;
@@ -275,20 +320,19 @@ IOInterruptController *IOPlatformExpert::lookUpInterruptController(OSSymbol *nam
 {
   OSObject              *object;
   
+  IOLockLock(gIOInterruptControllersLock);
   while (1) {
-    IOLockLock(gIOInterruptControllersLock);
     
     object = gIOInterruptControllers->getObject(name);
     
-    if (object == 0) assert_wait(gIOInterruptControllers, THREAD_UNINT);
-    
-    IOLockUnlock(gIOInterruptControllersLock);
-    
-    if (object != 0) break;
+    if (object != 0)
+       break;
     
-    thread_block(0);
+    IOLockSleep(gIOInterruptControllersLock,
+               gIOInterruptControllers, THREAD_UNINT);
   }
   
+  IOLockUnlock(gIOInterruptControllersLock);
   return OSDynamicCast(IOInterruptController, object);
 }
 
@@ -317,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);
+       }
     }
 }
 
@@ -648,15 +725,17 @@ static void getCStringForObject (OSObject * inObj, char * outStr)
    }
 }
 
-/* IOPMPanicOnShutdownHang
+/* IOShutdownNotificationsTimedOut
  * - Called from a timer installed by PEHaltRestart
  */
-static void IOPMPanicOnShutdownHang(thread_call_param_t p0, thread_call_param_t p1)
+static void IOShutdownNotificationsTimedOut(
+    thread_call_param_t p0, 
+    thread_call_param_t p1)
 {
     int type = (int)p0;
 
     /* 30 seconds has elapsed - resume shutdown */
-    gIOPlatform->haltRestart(type);
+    if(gIOPlatform) gIOPlatform->haltRestart(type);
 }
 
 
@@ -696,47 +775,67 @@ int PEHaltRestart(unsigned int type)
   bool              noWaitForResponses;
   AbsoluteTime      deadline;
   thread_call_t     shutdown_hang;
+  unsigned int      tell_type;
   
-  /* 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( &IOPMPanicOnShutdownHang, (thread_call_param_t) type);
-  clock_interval_to_deadline( 30, kSecondScale, &deadline );
-  thread_call_enter1_delayed( shutdown_hang, 0, deadline );
-  
-  noWaitForResponses = pmRootDomain->tellChangeDown2(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(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" */
@@ -767,6 +866,10 @@ IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
                                       param1, param2, param3, param4);
 }
 
+IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
+{
+  return 0;
+}
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -844,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;
@@ -852,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);
@@ -861,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) {
@@ -876,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 )
@@ -995,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
@@ -1010,7 +1181,7 @@ OSMetaClassDefineReservedUnused(IOPlatformExpertDevice,  3);
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 bool IOPlatformExpertDevice::compareName( OSString * name,
-                                        OSString ** matched = 0 ) const
+                                        OSString ** matched ) const
 {
     return( IODTCompareNubName( this, name, matched ));
 }
@@ -1057,6 +1228,12 @@ void IOPlatformExpertDevice::free()
         workLoop->release();
 }
 
+bool IOPlatformExpertDevice::attachToChild( IORegistryEntry * child,
+                                        const IORegistryPlane * plane )
+{
+    return IOService::attachToChild( child, plane );
+}
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 #undef super
@@ -1072,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 ));