* 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);
OSDefineMetaClassAndStructors(IOPlatformExpert, IOService)
-OSMetaClassDefineReservedUnused(IOPlatformExpert, 0);
-OSMetaClassDefineReservedUnused(IOPlatformExpert, 1);
+OSMetaClassDefineReservedUsed(IOPlatformExpert, 0);
+
+OSMetaClassDefineReservedUsed(IOPlatformExpert, 1);
OSMetaClassDefineReservedUnused(IOPlatformExpert, 2);
OSMetaClassDefineReservedUnused(IOPlatformExpert, 3);
OSMetaClassDefineReservedUnused(IOPlatformExpert, 4);
OSMetaClassDefineReservedUnused(IOPlatformExpert, 11);
static IOPlatformExpert * gIOPlatform;
+static OSDictionary * gIOInterruptControllers;
+static IOLock * gIOInterruptControllersLock;
OSSymbol * gPlatformInterruptControllerName;
{
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);
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) );
}
}
bool IOPlatformExpert::compareNubName( const IOService * nub,
- OSString * name, OSString ** matched = 0 ) const
+ OSString * name, OSString ** matched ) const
{
return( nub->IORegistryEntry::compareName( name, matched ));
}
return( false );
}
+OSString* IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
+{
+ return NULL;
+}
+
IORangeAllocator * IOPlatformExpert::getPhysicalRangeAllocator(void)
{
return(OSDynamicCast(IORangeAllocator,
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;
}
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);
}
//
//*********************************************************************************
-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);
+ }
}
}
}
}
+/* 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" {
/*
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" */
param1, param2, param3, param4);
}
+IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
+{
+ return 0;
+}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
return( ok );
}
-void IODTPlatformExpert::processTopLevel( IORegistryEntry * root )
+void IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
{
OSIterator * kids;
IORegistryEntry * next;
IORegistryEntry * options;
// infanticide
- kids = IODTFindMatchingEntries( root, 0, deleteList() );
+ kids = IODTFindMatchingEntries( rootEntry, 0, deleteList() );
if( kids) {
while( (next = (IORegistryEntry *)kids->getNextObject())) {
next->detachAll( gIODTPlane);
}
// Publish an IODTNVRAM class on /options.
- options = root->childFromPath("options", gIODTPlane);
+ options = rootEntry->childFromPath("options", gIODTPlane);
if (options) {
dtNVRAM = new IODTNVRAM;
if (dtNVRAM) {
}
// 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 )
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
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool IOPlatformExpertDevice::compareName( OSString * name,
- OSString ** matched = 0 ) const
+ OSString ** matched ) const
{
return( IODTCompareNubName( this, name, matched ));
}
workLoop->release();
}
+bool IOPlatformExpertDevice::attachToChild( IORegistryEntry * child,
+ const IORegistryPlane * plane )
+{
+ return IOService::attachToChild( child, plane );
+}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#undef super
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool IOPlatformDevice::compareName( OSString * name,
- OSString ** matched = 0 ) const
+ OSString ** matched ) const
{
return( ((IOPlatformExpert *)getProvider())->
compareNubName( this, name, matched ));