]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOPlatformExpert.cpp
xnu-792.6.56.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPlatformExpert.cpp
index 2d4b2d5006f6c99189b05772869ec91a3f8ca0d5..849109fde4da5f0d8aa292f53e9cc43f0a4c7415 100644 (file)
@@ -3,19 +3,20 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
  * 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>
@@ -50,8 +55,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 +90,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 +123,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 +176,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 +226,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 +241,20 @@ int (*PE_halt_restart)(unsigned int type) = 0;
 
 int IOPlatformExpert::haltRestart(unsigned int type)
 {
+  IOPMrootDomain *rd = getPMRootDomain();
+  OSBoolean   *b = 0;
+    
+  if(rd) b = (OSBoolean *)OSDynamicCast(OSBoolean, rd->getProperty(OSString::withCString("StallSystemAtHalt")));
+
+  if (type == kPEHangCPU) while (1);
+
+  if (kOSBooleanTrue == b) {
+    // Stall shutdown for 5 minutes, and if no outside force has removed our power, continue with
+    // a reboot.
+    IOSleep(1000*60*5);
+    type = kPERestartCPU;
+  }
+  
   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);
+       }
     }
 }
 
@@ -697,34 +774,43 @@ int PEHaltRestart(unsigned int type)
   AbsoluteTime      deadline;
   thread_call_t     shutdown_hang;
   
-  /* 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)
+  {
+    /* 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 (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)
 {
     if( gIOPlatform)
@@ -767,6 +853,10 @@ IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
                                       param1, param2, param3, param4);
 }
 
+IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
+{
+  return 0;
+}
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -844,7 +934,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 +942,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 +951,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 +966,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 )
@@ -1019,6 +1109,49 @@ IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
   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;
+}
+
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -1035,7 +1168,7 @@ OSMetaClassDefineReservedUnused(IOPlatformExpertDevice,  3);
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 bool IOPlatformExpertDevice::compareName( OSString * name,
-                                        OSString ** matched = 0 ) const
+                                        OSString ** matched ) const
 {
     return( IODTCompareNubName( this, name, matched ));
 }
@@ -1097,7 +1230,7 @@ OSMetaClassDefineReservedUnused(IOPlatformDevice,  3);
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 bool IOPlatformDevice::compareName( OSString * name,
-                                       OSString ** matched = 0 ) const
+                                       OSString ** matched ) const
 {
     return( ((IOPlatformExpert *)getProvider())->
                compareNubName( this, name, matched ));