X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/cb3231590a3c94ab4375e2228bd5e86b0cf1ad7e..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/iokit/Kernel/IOPlatformExpert.cpp diff --git a/iokit/Kernel/IOPlatformExpert.cpp b/iokit/Kernel/IOPlatformExpert.cpp index 1fb74c642..407dd5b02 100644 --- a/iokit/Kernel/IOPlatformExpert.cpp +++ b/iokit/Kernel/IOPlatformExpert.cpp @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -42,17 +43,25 @@ #include #include +#include "IOKitKernelInternal.h" + #include #include #include +#include #include #include +#if defined(__arm64__) +#include +#endif + extern "C" { #include #include #include +#include } #define kShutdownTimeout 30 //in secs @@ -83,14 +92,14 @@ uint32_t gEnforceQuiesceSafety = 0; OSDefineMetaClassAndStructors(IOPlatformExpert, IOService) -OSMetaClassDefineReservedUsed(IOPlatformExpert, 0); -OSMetaClassDefineReservedUsed(IOPlatformExpert, 1); -OSMetaClassDefineReservedUsed(IOPlatformExpert, 2); -OSMetaClassDefineReservedUsed(IOPlatformExpert, 3); -OSMetaClassDefineReservedUsed(IOPlatformExpert, 4); +OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 0); +OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 1); +OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 2); +OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 3); +OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 4); +OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 5); +OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 6); -OSMetaClassDefineReservedUnused(IOPlatformExpert, 5); -OSMetaClassDefineReservedUnused(IOPlatformExpert, 6); OSMetaClassDefineReservedUnused(IOPlatformExpert, 7); OSMetaClassDefineReservedUnused(IOPlatformExpert, 8); OSMetaClassDefineReservedUnused(IOPlatformExpert, 9); @@ -167,17 +176,11 @@ 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(); - } - } +#if !defined(__x86_64__) + publishPlatformUUIDAndSerial(); +#endif /* !defined(__x86_64__) */ -#if !CONFIG_EMBEDDED +#if defined (__x86_64__) if (PEGetCoprocessorVersion() >= kCoprocessorVersion2) { coprocessor_paniclog_flush = TRUE; extended_debug_log_init(); @@ -239,6 +242,16 @@ IOPlatformExpert::compareNubName( const IOService * nub, return nub->IORegistryEntry::compareName( name, matched ); } +bool +IOPlatformExpert::compareNubName( const IOService * nub, + OSString * name, OSSharedPtr& matched ) const +{ + OSString* matchedRaw = NULL; + bool result = compareNubName(nub, name, &matchedRaw); + matched.reset(matchedRaw, OSNoRetain); + return result; +} + IOReturn IOPlatformExpert::getNubResources( IOService * nub ) { @@ -293,6 +306,18 @@ IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/) return false; } +bool +IOPlatformExpert::getTargetName( char * /*name*/, int /*maxLength*/) +{ + return false; +} + +bool +IOPlatformExpert::getProductName( char * /*name*/, int /*maxLength*/) +{ + return false; +} + OSString* IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty) { @@ -325,7 +350,7 @@ IOPlatformExpert::haltRestart(unsigned int type) type = kPEHaltCPU; } -#if !CONFIG_EMBEDDED +#if defined (__x86_64__) // On ARM kPEPanicRestartCPU is supported in the drivers if (type == kPEPanicRestartCPU) { type = kPERestartCPU; @@ -439,9 +464,12 @@ IOPlatformExpert::lookUpInterruptController(OSSymbol *name) void IOPlatformExpert::setCPUInterruptProperties(IOService *service) { - IOCPUInterruptController *controller; + IOInterruptController *controller; + + OSDictionary *matching = serviceMatching("IOInterruptController"); + matching = propertyMatching(gPlatformInterruptControllerName, kOSBooleanTrue, matching); - controller = OSDynamicCast(IOCPUInterruptController, waitForService(serviceMatching("IOCPUInterruptController"))); + controller = OSDynamicCast(IOInterruptController, waitForService(matching)); if (controller) { controller->setCPUInterruptProperties(service); } @@ -840,7 +868,7 @@ getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen) /* IOShutdownNotificationsTimedOut * - Called from a timer installed by PEHaltRestart */ -#ifdef CONFIG_EMBEDDED +#if !defined(__x86_64) __abortlike #endif static void @@ -848,11 +876,11 @@ IOShutdownNotificationsTimedOut( thread_call_param_t p0, thread_call_param_t p1) { -#ifdef CONFIG_EMBEDDED +#if !defined(__x86_64__) /* 30 seconds has elapsed - panic */ panic("Halt/Restart Timed Out"); -#else /* ! CONFIG_EMBEDDED */ +#else /* !defined(__x86_64__) */ int type = (int)(long)p0; uint32_t timeout = (uint32_t)(uintptr_t)p1; @@ -867,7 +895,7 @@ IOShutdownNotificationsTimedOut( if (gIOPlatform) { gIOPlatform->haltRestart(type); } -#endif /* CONFIG_EMBEDDED */ +#endif /* defined(__x86_64__) */ } @@ -876,6 +904,11 @@ extern "C" { * Callouts from BSD for machine name & model */ +/* + * PEGetMachineName() and PEGetModelName() are inconsistent across + * architectures, and considered deprecated. Use PEGetTargetName() and + * PEGetProductName() instead. + */ boolean_t PEGetMachineName( char * name, int maxLength ) { @@ -886,6 +919,11 @@ PEGetMachineName( char * name, int maxLength ) } } +/* + * PEGetMachineName() and PEGetModelName() are inconsistent across + * architectures, and considered deprecated. Use PEGetTargetName() and + * PEGetProductName() instead. + */ boolean_t PEGetModelName( char * name, int maxLength ) { @@ -896,18 +934,51 @@ PEGetModelName( char * name, int maxLength ) } } +boolean_t +PEGetTargetName( char * name, int maxLength ) +{ + if (gIOPlatform) { + return gIOPlatform->getTargetName( name, maxLength ); + } else { + return false; + } +} + +boolean_t +PEGetProductName( char * name, int maxLength ) +{ + if (gIOPlatform) { + return gIOPlatform->getProductName( name, maxLength ); + } else { + return false; + } +} + int PEGetPlatformEpoch(void) { if (gIOPlatform) { - return gIOPlatform->getBootROMType(); + return (int) gIOPlatform->getBootROMType(); } else { return -1; } } +/* Handle necessary platform specific actions prior to panic */ +void +PEInitiatePanic(void) +{ +#if defined(__arm64__) + /* + * Trigger a TLB flush so any hard hangs exercise the SoC diagnostic + * collection flow rather than hanging late in panic (see rdar://58062030) + */ + flush_mmu_tlb_entry(0); +#endif +} + int -PEHaltRestart(unsigned int type) +PEHaltRestartInternal(unsigned int type, uint32_t details) { IOPMrootDomain *pmRootDomain; AbsoluteTime deadline; @@ -936,7 +1007,7 @@ PEHaltRestart(unsigned int type) * the timer expires. If the device wants a different * timeout, use that value instead of 30 seconds. */ -#if CONFIG_EMBEDDED +#if defined(__arm__) || defined(__arm64__) #define RESTART_NODE_PATH "/defaults" #else #define RESTART_NODE_PATH "/chosen" @@ -973,50 +1044,42 @@ PEHaltRestart(unsigned int type) * later. PM internals make it very hard to wait for asynchronous * replies. */ - } else if (type == kPEPanicRestartCPU || type == kPEPanicSync || type == kPEPanicRestartCPUNoPanicEndCallouts || - type == kPEPanicRestartCPUNoCallouts) { + } else if (type == kPEPanicRestartCPU || type == kPEPanicSync || type == kPEPanicRestartCPUNoCallouts) { if (type == kPEPanicRestartCPU) { // Notify any listeners that we're done collecting // panic data before we call through to do the restart -#if !CONFIG_EMBEDDED +#if defined(__x86_64__) if (coprocessor_cross_panic_enabled) #endif - IOCPURunPlatformPanicActions(kPEPanicEnd); - } - - if ((type == kPEPanicRestartCPU) || (type == kPEPanicRestartCPUNoPanicEndCallouts)) { - // Callout to shutdown the disk driver once we've returned from the - // kPEPanicEnd callbacks (if appropriate) and we know all coredumps - // on this system are complete). - IOCPURunPlatformPanicActions(kPEPanicDiskShutdown); - } - - if (type == kPEPanicRestartCPUNoPanicEndCallouts || type == kPEPanicRestartCPUNoCallouts) { - // Replace the wrapper type with the type drivers handle + IOCPURunPlatformPanicActions(kPEPanicEnd, details); + } else if (type == kPEPanicRestartCPUNoCallouts) { + // We skipped the callouts so now set the type to + // the variant that the platform uses for panic restarts. type = kPEPanicRestartCPU; } + // Do an initial sync to flush as much panic data as possible, // in case we have a problem in one of the platorm panic handlers. // After running the platform handlers, do a final sync w/ // platform hardware quiesced for the panic. PE_sync_panic_buffers(); - IOCPURunPlatformPanicActions(type); + IOCPURunPlatformPanicActions(type, details); PE_sync_panic_buffers(); } else if (type == kPEPanicEnd) { -#if !CONFIG_EMBEDDED +#if defined(__x86_64__) if (coprocessor_cross_panic_enabled) #endif - IOCPURunPlatformPanicActions(type); + IOCPURunPlatformPanicActions(type, details); } else if (type == kPEPanicBegin) { -#if !CONFIG_EMBEDDED +#if defined(__x86_64__) if (coprocessor_cross_panic_enabled) #endif { // Only call the kPEPanicBegin callout once if (!panic_begin_called) { panic_begin_called = TRUE; - IOCPURunPlatformPanicActions(type); + IOCPURunPlatformPanicActions(type, details); } } } @@ -1029,11 +1092,17 @@ skip_to_haltRestart: } } +int +PEHaltRestart(unsigned int type) +{ + return PEHaltRestartInternal(type, 0); +} + UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length) { if (gIOPlatform != NULL) { - return gIOPlatform->savePanicInfo(buffer, length); + return (UInt32) gIOPlatform->savePanicInfo(buffer, length); } else { return 0; } @@ -1047,6 +1116,12 @@ PESavePanicInfoAction(void *buffer, UInt32 offset, UInt32 length) } +/* + * Depending on the platform, the /options node may not be created + * until after IOKit matching has started, by an externally-supplied + * platform expert subclass. Therefore, we must check for its presence + * here and update gIOOptionsEntry for the platform code as necessary. + */ inline static int init_gIOOptionsEntry(void) { @@ -1290,7 +1365,7 @@ coprocessor_type_t PEGetCoprocessorVersion( void ) { coprocessor_type_t coprocessor_version = kCoprocessorVersionNone; -#if !CONFIG_EMBEDDED +#if defined(__x86_64__) IORegistryEntry *platform_entry = NULL; OSData *coprocessor_version_obj = NULL; @@ -1307,50 +1382,55 @@ PEGetCoprocessorVersion( void ) } } /* extern "C" */ -void -IOPlatformExpert::registerNVRAMController(IONVRAMController * caller) -{ - OSData * data; - IORegistryEntry * entry; - OSString * string = NULL; - uuid_string_t uuid; - -#if CONFIG_EMBEDDED - entry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ); - if (entry) { - OSData * data1; - - data1 = OSDynamicCast( OSData, entry->getProperty( "unique-chip-id" )); - if (data1 && data1->getLength() == 8) { - OSData * data2; +bool gIOPlatformUUIDAndSerialDone = false; - data2 = OSDynamicCast( OSData, entry->getProperty( "chip-id" )); - if (data2 && data2->getLength() == 4) { - SHA1_CTX context; - uint8_t digest[SHA_DIGEST_LENGTH]; - const uuid_t space = { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 }; - - SHA1Init( &context ); - SHA1Update( &context, space, sizeof(space)); - SHA1Update( &context, data1->getBytesNoCopy(), data1->getLength()); - SHA1Update( &context, data2->getBytesNoCopy(), data2->getLength()); - SHA1Final( digest, &context ); - - digest[6] = (digest[6] & 0x0F) | 0x50; - digest[8] = (digest[8] & 0x3F) | 0x80; - - uuid_unparse( digest, uuid ); - string = OSString::withCString( uuid ); +void +IOPlatformExpert::publishPlatformUUIDAndSerial( void ) +{ + if (!gIOPlatformUUIDAndSerialDone) { + // Parse the serial-number data and publish a user-readable string + if (NULL == getProvider()->getProperty(kIOPlatformSerialNumberKey)) { + OSData* mydata = (OSData*) (getProvider()->getProperty("serial-number")); + if (mydata != NULL) { + OSString *serNoString = createSystemSerialNumberString(mydata); + if (serNoString != NULL) { + getProvider()->setProperty(kIOPlatformSerialNumberKey, serNoString); + serNoString->release(); + } } } + IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider()); + assert(provider != NULL); + provider->generatePlatformUUID(); + } - entry->release(); + if (gIOPlatformUUIDAndSerialDone) { + publishResource(kIOPlatformUUIDKey, getProvider()->getProperty(kIOPlatformUUIDKey)); } -#endif /* CONFIG_EMBEDDED */ +} + +void +IOPlatformExpert::publishNVRAM( void ) +{ + if (init_gIOOptionsEntry() < 0) { + IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider()); + assert(provider != NULL); + provider->createNVRAM(); + } + if (gIOOptionsEntry != NULL) { + gIOOptionsEntry->registerService(); + } +} + +void +IOPlatformExpert::registerNVRAMController(IONVRAMController * caller) +{ +#if defined(__x86_64__) + OSData * data; + IORegistryEntry * entry; -#if defined(XNU_TARGET_OS_OSX) /* - * If we have panic debugging enabled and the bridgeOS panic SoC watchdog is enabled, + * If we have panic debugging enabled and a prod-fused coprocessor, * disable cross panics so that the co-processor doesn't cause the system * to reset when we enter the debugger or hit a panic on the x86 side. */ @@ -1370,49 +1450,26 @@ IOPlatformExpert::registerNVRAMController(IONVRAMController * caller) } } - entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane ); +#if (DEVELOPMENT || DEBUG) + entry = IORegistryEntry::fromPath( "/options", gIODTPlane ); if (entry) { - data = OSDynamicCast( OSData, entry->getProperty( "system-id" )); - if (data && data->getLength() == 16) { - SHA1_CTX context; - uint8_t digest[SHA_DIGEST_LENGTH]; - const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC }; - - SHA1Init( &context ); - SHA1Update( &context, space, sizeof(space)); - SHA1Update( &context, data->getBytesNoCopy(), data->getLength()); - SHA1Final( digest, &context ); - - digest[6] = (digest[6] & 0x0F) | 0x50; - digest[8] = (digest[8] & 0x3F) | 0x80; - - uuid_unparse( digest, uuid ); - string = OSString::withCString( uuid ); - } - - entry->release(); - } -#endif /* defined(XNU_TARGET_OS_OSX) */ - - if (string == NULL) { - entry = IORegistryEntry::fromPath( "/options", gIODTPlane ); - if (entry) { - data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" )); - if (data && data->getLength() == sizeof(uuid_t)) { - uuid_unparse((uint8_t *) data->getBytesNoCopy(), uuid ); - string = OSString::withCString( uuid ); + data = OSDynamicCast( OSData, entry->getProperty(nvram_osenvironment)); + if (data) { + sysctl_set_osenvironment(data->getLength(), data->getBytesNoCopy()); + entry->removeProperty(nvram_osenvironment); + IODTNVRAM * nvramOptionsEntry = OSDynamicCast(IODTNVRAM, entry); + if (nvramOptionsEntry) { + nvramOptionsEntry->sync(); } - - entry->release(); } + entry->release(); } + sysctl_unblock_osenvironment(); +#endif + /* on intel the UUID must be published after nvram is available */ + publishPlatformUUIDAndSerial(); - if (string) { - getProvider()->setProperty( kIOPlatformUUIDKey, string ); - publishResource( kIOPlatformUUIDKey, string ); - - string->release(); - } +#endif /* defined(__x86_64__) */ publishResource("IONVRAM"); } @@ -1536,6 +1593,45 @@ IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter ) } nub->attach( parent ); +#if !defined(__x86_64__) + OSData *tmpData = (OSData *)next->getProperty("device_type"); + if (tmpData == NULL) { + nub->registerService(); + continue; + } + + char *device_type = (char *)tmpData->getBytesNoCopy(); + if (strcmp(device_type, "cpu") != 0) { + nub->registerService(); + continue; + } + + tmpData = (OSData *)next->getProperty("reg"); + assert(tmpData != NULL); + assert(tmpData->getLength() >= sizeof(UInt32)); + + uint32_t phys_id = *(UInt32 *)tmpData->getBytesNoCopy(); + int logical_cpu_id = ml_get_cpu_number(phys_id); + int logical_cluster_id = ml_get_cluster_number(phys_id); + + /* + * If the following condition triggers, it means that a CPU that was present in the DT + * was ignored by XNU at topology parsing time. This can happen currently when using the + * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU. + * + * Note that this condition will not trigger for harvested cores because these do not show up + * in the DT/IORegistry in the first place. + */ + if (logical_cpu_id < 0) { + nub->registerService(); + continue; + } + + __assert_only bool logical_id_added_to_ioreg = nub->setProperty("logical-cpu-id", logical_cpu_id, 32U); + assert(logical_id_added_to_ioreg == true); + logical_id_added_to_ioreg = nub->setProperty("logical-cluster-id", logical_cluster_id, 32U); + assert(logical_id_added_to_ioreg == true); +#endif nub->registerService(); } iter->release(); @@ -1550,7 +1646,6 @@ IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry ) OSIterator * kids; IORegistryEntry * next; IORegistryEntry * cpus; - IORegistryEntry * options; // infanticide kids = IODTFindMatchingEntries( rootEntry, 0, deleteList()); @@ -1561,21 +1656,9 @@ IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry ) kids->release(); } - // Publish an IODTNVRAM class on /options. - options = rootEntry->childFromPath("options", gIODTPlane); - if (options) { - dtNVRAM = new IODTNVRAM; - if (dtNVRAM) { - if (!dtNVRAM->init(options, gIODTPlane)) { - dtNVRAM->release(); - dtNVRAM = NULL; - } else { - dtNVRAM->attach(this); - dtNVRAM->registerService(); - options->release(); - } - } - } + publishNVRAM(); + assert(gIOOptionsEntry != NULL); // subclasses that do their own NVRAM initialization shouldn't be calling this + dtNVRAM = gIOOptionsEntry; // Publish the cpus. cpus = rootEntry->childFromPath( "cpus", gIODTPlane); @@ -1608,6 +1691,20 @@ IODTPlatformExpert::compareNubName( const IOService * nub, || super::compareNubName( nub, name, matched); } + +/* + * Do not use this method directly, it returns inconsistent results + * across architectures and is considered deprecated. + * + * Use getTargetName and getProductName respectively. For example: + * + * targetName: J137AP + * productName: iMacPro1,1 + * + * targetName: D331pAP + * productName: iPhone11,6 + */ + bool IODTPlatformExpert::getModelName( char * name, int maxLength ) { @@ -1645,6 +1742,19 @@ IODTPlatformExpert::getModelName( char * name, int maxLength ) return ok; } +/* + * Do not use this method directly, it returns inconsistent results + * across architectures and is considered deprecated. + * + * Use getTargetName and getProductName respectively. For example: + * + * targetName: J137AP + * productName: iMacPro1,1 + * + * targetName: D331pAP + * productName: iPhone11,6 + */ + bool IODTPlatformExpert::getMachineName( char * name, int maxLength ) { @@ -1662,6 +1772,46 @@ IODTPlatformExpert::getMachineName( char * name, int maxLength ) return ok; } +/* Examples: J137AP, D331pAP... */ + +bool +IODTPlatformExpert::getTargetName( char * name, int maxLength ) +{ +#if __x86_64__ + OSData * prop; + + const OSSymbol * key = gIODTBridgeModelKey; + + maxLength--; + prop = (OSData *) getProvider()->getProperty( key ); + + if (prop == NULL) { + // This happens if there is no bridge. + char const * const unknown = ""; + + strlcpy( name, unknown, maxLength ); + } else { + strlcpy( name, (const char *)prop->getBytesNoCopy(), maxLength ); + } + + return true; +#else + return getModelName( name, maxLength ); +#endif +} + +/* Examples: iMacPro1,1, iPhone11,6... */ + +bool +IODTPlatformExpert::getProductName( char * name, int maxLength ) +{ +#if __x86_64__ + return getModelName( name, maxLength ); +#else + return getMachineName( name, maxLength ); +#endif +} + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void @@ -1718,6 +1868,22 @@ IODTPlatformExpert::readNVRAMProperty( } } +IOReturn +IODTPlatformExpert::readNVRAMProperty( + IORegistryEntry * entry, + OSSharedPtr& name, OSSharedPtr& value ) +{ + const OSSymbol* nameRaw = NULL; + OSData* valueRaw = NULL; + + IOReturn result = readNVRAMProperty(entry, &nameRaw, &valueRaw); + + name.reset(nameRaw, OSNoRetain); + value.reset(valueRaw, OSNoRetain); + + return result; +} + IOReturn IODTPlatformExpert::writeNVRAMProperty( IORegistryEntry * entry, @@ -1841,14 +2007,12 @@ IOPlatformExpertDevice::compareName( OSString * name, } bool -IOPlatformExpertDevice::initWithArgs( - void * dtTop, void * p2, void * p3, void * p4 ) +IOPlatformExpertDevice::init(void *dtRoot) { IORegistryEntry * dt = NULL; bool ok; - // dtTop may be zero on non- device tree systems - if (dtTop && (dt = IODeviceTreeAlloc( dtTop ))) { + if ((dtRoot != NULL) && (dt = IODeviceTreeAlloc(dtRoot))) { ok = super::init( dt, gIODTPlane ); } else { ok = super::init(); @@ -1858,11 +2022,19 @@ IOPlatformExpertDevice::initWithArgs( return false; } + return true; +} + +bool +IOPlatformExpertDevice::startIOServiceMatching(void) +{ workLoop = IOWorkLoop::workLoop(); if (!workLoop) { return false; } + registerService(); + return true; } @@ -1927,6 +2099,131 @@ IOPlatformExpertDevice::free() } } +void +IOPlatformExpertDevice::configureDefaults( void ) +{ + createNVRAM(); + // Parse the serial-number data and publish a user-readable string + OSData* mydata = (OSData*) (getProperty("serial-number")); + if (mydata != NULL) { + OSString *serNoString = OSString::withCString((const char *)mydata->getBytesNoCopy()); + if (serNoString != NULL) { + setProperty(kIOPlatformSerialNumberKey, serNoString); + serNoString->release(); + } + } + generatePlatformUUID(); +} + +void +IOPlatformExpertDevice::createNVRAM( void ) +{ + /* + * Publish an IODTNVRAM class on /options, if present. + * DT-based platforms may need NVRAM access prior to the start + * of IOKit matching, to support security-related operations + * that must happen before machine_lockdown(). + */ + IORegistryEntry *options = IORegistryEntry::fromPath("/options", gIODTPlane); + if (options == NULL) { + return; // /options may not be present + } + + assert(gIOOptionsEntry == NULL); + gIOOptionsEntry = new IODTNVRAM; + + assert(gIOOptionsEntry != NULL); + + gIOOptionsEntry->init(options, gIODTPlane); + + gIOOptionsEntry->attach(this); + options->release(); +} + +void +IOPlatformExpertDevice::generatePlatformUUID( void ) +{ + IORegistryEntry * entry; + OSString * string = NULL; + uuid_string_t uuid; + +#if !defined(__x86_64__) + entry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ); + if (entry) { + OSData * data1; + + data1 = OSDynamicCast( OSData, entry->getProperty( "unique-chip-id" )); + if (data1 && data1->getLength() == 8) { + OSData * data2; + + data2 = OSDynamicCast( OSData, entry->getProperty( "chip-id" )); + if (data2 && data2->getLength() == 4) { + SHA1_CTX context; + uint8_t digest[SHA_DIGEST_LENGTH]; + const uuid_t space = { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 }; + + SHA1Init( &context ); + SHA1Update( &context, space, sizeof(space)); + SHA1Update( &context, data1->getBytesNoCopy(), data1->getLength()); + SHA1Update( &context, data2->getBytesNoCopy(), data2->getLength()); + SHA1Final( digest, &context ); + + digest[6] = (digest[6] & 0x0F) | 0x50; + digest[8] = (digest[8] & 0x3F) | 0x80; + + uuid_unparse( digest, uuid ); + string = OSString::withCString( uuid ); + } + } + + entry->release(); + } +#else /* !defined(__x86_64__) */ + OSData * data; + + entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane ); + if (entry) { + data = OSDynamicCast( OSData, entry->getProperty( "system-id" )); + if (data && data->getLength() == 16) { + SHA1_CTX context; + uint8_t digest[SHA_DIGEST_LENGTH]; + const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC }; + + SHA1Init( &context ); + SHA1Update( &context, space, sizeof(space)); + SHA1Update( &context, data->getBytesNoCopy(), data->getLength()); + SHA1Final( digest, &context ); + + digest[6] = (digest[6] & 0x0F) | 0x50; + digest[8] = (digest[8] & 0x3F) | 0x80; + + uuid_unparse( digest, uuid ); + string = OSString::withCString( uuid ); + } + + entry->release(); + } + if (!string) { + /* vmware still runs this path */ + entry = IORegistryEntry::fromPath( "/options", gIODTPlane ); + if (entry) { + data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" )); + if (data && data->getLength() == sizeof(uuid_t)) { + uuid_unparse((uint8_t *) data->getBytesNoCopy(), uuid ); + string = OSString::withCString( uuid ); + } + entry->release(); + } + } +#endif /* defined(__x86_64__) */ + + if (string) { + setProperty( kIOPlatformUUIDKey, string ); + gIOPlatformUUIDAndSerialDone = true; + + string->release(); + } +} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super