*/
#include <IOKit/IOCPU.h>
+#include <IOKit/IOPlatformActions.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOKitDebug.h>
#include <IOKit/IOMapper.h>
#include <IOKit/IOTimeStamp.h>
#include <IOKit/IOUserClient.h>
#include <IOKit/IOKitDiagnosticsUserClient.h>
+#include <IOKit/IOUserServer.h>
+
+#include "IOKitKernelInternal.h"
#include <IOKit/system.h>
#include <sys/csr.h>
#include <libkern/c++/OSContainers.h>
+#include <libkern/c++/OSSharedPtr.h>
#include <libkern/crypto/sha1.h>
#include <libkern/OSAtomic.h>
+#if defined(__arm64__)
+#include <arm64/tlb.h>
+#endif
+
extern "C" {
#include <machine/machine_routines.h>
#include <pexpert/pexpert.h>
#include <uuid/uuid.h>
+#include <sys/sysctl.h>
}
#define kShutdownTimeout 30 //in secs
-#if !CONFIG_EMBEDDED
+#if defined(XNU_TARGET_OS_OSX)
boolean_t coprocessor_cross_panic_enabled = TRUE;
-#define APPLE_SECURE_BOOT_VARIABLE_GUID "94b73556-2197-4702-82a8-3e1337dafbfb"
-#endif /* !CONFIG_EMBEDDED */
+#define APPLE_VENDOR_VARIABLE_GUID "4d1ede05-38c7-4a6a-9cc6-4bcca8b38c14"
+#endif /* defined(XNU_TARGET_OS_OSX) */
void printDictionaryKeys(OSDictionary * inDictionary, char * inMsg);
static void getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen);
+/*
+ * There are drivers which take mutexes in the quiesce callout or pass
+ * the quiesce/active action to super. Even though it sometimes panics,
+ * because it doesn't *always* panic, they get away with it.
+ * We need a chicken bit to diagnose and fix them all before this
+ * can be enabled by default.
+ *
+ * <rdar://problem/33831837> tracks turning this on by default.
+ */
+uint32_t gEnforceQuiesceSafety = 0;
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define super IOService
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);
// Register the presence or lack thereof a system
// PCI address mapper with the IOMapper class
- IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey));
+ IOMapper::setMapperRequired(NULL != getProperty(kIOPlatformMapperPresentKey));
gIOInterruptControllers = OSDictionary::withCapacity(1);
gIOInterruptControllersLock = IOLockAlloc();
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();
}
#endif
+ PE_parse_boot_argn("enforce_quiesce_safety", &gEnforceQuiesceSafety,
+ sizeof(gEnforceQuiesceSafety));
+
return configure(provider);
}
dict->retain();
topLevel->removeObject( dict );
nub = createNub( dict );
- if (0 == nub) {
+ if (NULL == nub) {
continue;
}
dict->release();
if (nub) {
if (!nub->init( from )) {
nub->release();
- nub = 0;
+ nub = NULL;
}
}
return nub;
return nub->IORegistryEntry::compareName( name, matched );
}
+bool
+IOPlatformExpert::compareNubName( const IOService * nub,
+ OSString * name, OSSharedPtr<OSString>& matched ) const
+{
+ OSString* matchedRaw = NULL;
+ bool result = compareNubName(nub, name, &matchedRaw);
+ matched.reset(matchedRaw, OSNoRetain);
+ return result;
+}
+
IOReturn
IOPlatformExpert::getNubResources( IOService * nub )
{
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)
{
getProperty("Platform Memory Ranges"));
}
-int (*PE_halt_restart)(unsigned int type) = 0;
+int (*PE_halt_restart)(unsigned int type) = NULL;
int
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;
while (1) {
object = gIOInterruptControllers->getObject(name);
- if (object != 0) {
+ if (object != NULL) {
break;
}
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);
}
/* IOShutdownNotificationsTimedOut
* - Called from a timer installed by PEHaltRestart
*/
+#if !defined(__x86_64)
+__abortlike
+#endif
static void
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;
if (gIOPlatform) {
gIOPlatform->haltRestart(type);
}
-#endif /* CONFIG_EMBEDDED */
+#endif /* defined(__x86_64__) */
}
* 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 )
{
}
}
+/*
+ * PEGetMachineName() and PEGetModelName() are inconsistent across
+ * architectures, and considered deprecated. Use PEGetTargetName() and
+ * PEGetProductName() instead.
+ */
boolean_t
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;
static boolean_t panic_begin_called = FALSE;
if (type == kPEHaltCPU || type == kPERestartCPU || type == kPEUPSDelayHaltCPU) {
+ /* If we're in the panic path, the locks and memory allocations required below
+ * could fail. So just try to reboot instead of risking a nested panic.
+ */
+ if (panic_begin_called) {
+ goto skip_to_haltRestart;
+ }
+
pmRootDomain = IOService::getPMRootDomain();
/* Notify IOKit PM clients of shutdown/restart
* Clients subscribe to this message with a call to
* 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"
}
}
- shutdown_hang = thread_call_allocate( &IOShutdownNotificationsTimedOut,
- (thread_call_param_t)(uintptr_t) type);
- clock_interval_to_deadline( timeout, kSecondScale, &deadline );
- thread_call_enter1_delayed( shutdown_hang, (thread_call_param_t)(uintptr_t)timeout, deadline );
+#if (DEVELOPMENT || DEBUG)
+ /* Override the default timeout via a boot-arg */
+ uint32_t boot_arg_val;
+ if (PE_parse_boot_argn("halt_restart_timeout", &boot_arg_val, sizeof(boot_arg_val))) {
+ timeout = boot_arg_val;
+ }
+#endif
+
+ if (timeout) {
+ shutdown_hang = thread_call_allocate( &IOShutdownNotificationsTimedOut,
+ (thread_call_param_t)(uintptr_t) type);
+ clock_interval_to_deadline( timeout, kSecondScale, &deadline );
+ thread_call_enter1_delayed( shutdown_hang, (thread_call_param_t)(uintptr_t)timeout, deadline );
+ }
pmRootDomain->handlePlatformHaltRestart(type);
/* This notification should have few clients who all do
* later. PM internals make it very hard to wait for asynchronous
* replies.
*/
- } else if (type == kPEPanicRestartCPU || type == kPEPanicSync) {
+ } 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);
-
- // Callout to shutdown the disk driver once we've returned from the
- // kPEPanicEnd callback (and we know all core dumps on this system
- // are complete).
- IOCPURunPlatformPanicActions(kPEPanicDiskShutdown);
+ 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);
}
}
}
+skip_to_haltRestart:
if (gIOPlatform) {
return gIOPlatform->haltRestart(type);
} else {
}
}
+int
+PEHaltRestart(unsigned int type)
+{
+ return PEHaltRestartInternal(type, 0);
+}
+
UInt32
PESavePanicInfo(UInt8 *buffer, UInt32 length)
{
- if (gIOPlatform != 0) {
- return gIOPlatform->savePanicInfo(buffer, length);
+ if (gIOPlatform != NULL) {
+ return (UInt32) gIOPlatform->savePanicInfo(buffer, length);
} else {
return 0;
}
}
+/*
+ * 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)
{
PEGetCoprocessorVersion( void )
{
coprocessor_type_t coprocessor_version = kCoprocessorVersionNone;
-#if !CONFIG_EMBEDDED
+#if defined(__x86_64__)
IORegistryEntry *platform_entry = NULL;
OSData *coprocessor_version_obj = NULL;
}
} /* extern "C" */
+bool gIOPlatformUUIDAndSerialDone = false;
+
+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();
+ }
+
+ if (gIOPlatformUUIDAndSerialDone) {
+ publishResource(kIOPlatformUUIDKey, getProvider()->getProperty(kIOPlatformUUIDKey));
+ }
+}
+
+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;
- OSString * string = 0;
- 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;
-
- 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 /* !CONFIG_EMBEDDED */
/*
* If we have panic debugging enabled and a prod-fused coprocessor,
* disable cross panics so that the co-processor doesn't cause the system
if (panicDebugging) {
entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
if (entry) {
- data = OSDynamicCast( OSData, entry->getProperty( APPLE_SECURE_BOOT_VARIABLE_GUID":EffectiveProductionStatus" ));
+ data = OSDynamicCast( OSData, entry->getProperty( APPLE_VENDOR_VARIABLE_GUID":BridgeOSPanicWatchdogEnabled" ));
if (data && (data->getLength() == sizeof(UInt8))) {
- UInt8 *isProdFused = (UInt8 *) data->getBytesNoCopy();
+ UInt8 *panicWatchdogEnabled = (UInt8 *) data->getBytesNoCopy();
UInt32 debug_flags = 0;
- if (*isProdFused || (PE_i_can_has_debugger(&debug_flags) &&
+ if (*panicWatchdogEnabled || (PE_i_can_has_debugger(&debug_flags) &&
(debug_flags & DB_DISABLE_CROSS_PANIC))) {
coprocessor_cross_panic_enabled = FALSE;
}
}
}
- 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 /* !CONFIG_EMBEDDED */
-
- if (string == 0) {
- 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");
}
{
IOService *service, *_resources;
+ if (functionName == gIOPlatformQuiesceActionKey ||
+ functionName == gIOPlatformActiveActionKey) {
+ /*
+ * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
+ * must consume that event themselves, without passing it up to super/IOPlatformExpert.
+ */
+ if (gEnforceQuiesceSafety) {
+ panic("Class %s passed the quiesce/active action to IOPlatformExpert",
+ getMetaClass()->getClassName());
+ }
+ }
+
if (waitForFunction) {
_resources = waitForService(resourceMatching(functionName));
} else {
_resources = getResourceService();
}
- if (_resources == 0) {
+ if (_resources == NULL) {
return kIOReturnUnsupported;
}
service = OSDynamicCast(IOService, _resources->getProperty(functionName));
- if (service == 0) {
+ if (service == NULL) {
return kIOReturnUnsupported;
}
SInt32 * score )
{
if (!super::probe( provider, score)) {
- return 0;
+ return NULL;
}
// check machine types
if (!provider->compareNames( getProperty( gIONameMatchKey ))) {
- return 0;
+ return NULL;
}
return this;
if (nub) {
if (!nub->init( from, gIODTPlane )) {
nub->free();
- nub = 0;
+ nub = NULL;
}
}
return nub;
if (iter) {
while ((next = (IORegistryEntry *) iter->getNextObject())) {
- if (0 == (nub = createNub( next ))) {
+ if (NULL == (nub = createNub( next ))) {
continue;
}
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();
OSIterator * kids;
IORegistryEntry * next;
IORegistryEntry * cpus;
- IORegistryEntry * options;
// infanticide
kids = IODTFindMatchingEntries( rootEntry, 0, deleteList());
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 = 0;
- } 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);
if (cpus) {
- createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, 0));
+ createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, NULL));
cpus->release();
}
return kIOReturnSuccess;
}
- IODTResolveAddressing( nub, "reg", 0);
+ IODTResolveAddressing( nub, "reg", NULL);
return kIOReturnSuccess;
}
|| 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 )
{
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 )
{
maxLength--;
prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
- ok = (0 != prop);
+ ok = (NULL != prop);
if (ok) {
strlcpy( name, (const char *) prop->getBytesNoCopy(), 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
}
}
+IOReturn
+IODTPlatformExpert::readNVRAMProperty(
+ IORegistryEntry * entry,
+ OSSharedPtr<const OSSymbol>& name, OSSharedPtr<OSData>& 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,
if (dtNVRAM) {
return dtNVRAM->getNVRAMPartitions();
} else {
- return 0;
+ return NULL;
}
}
}
bool
-IOPlatformExpertDevice::initWithArgs(
- void * dtTop, void * p2, void * p3, void * p4 )
+IOPlatformExpertDevice::init(void *dtRoot)
{
- IORegistryEntry * dt = 0;
+ 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();
return false;
}
+ return true;
+}
+
+bool
+IOPlatformExpertDevice::startIOServiceMatching(void)
+{
workLoop = IOWorkLoop::workLoop();
if (!workLoop) {
return false;
}
+ registerService();
+
return true;
}
IOUserClient ** handler )
{
IOReturn err = kIOReturnSuccess;
- IOUserClient * newConnect = 0;
- IOUserClient * theConnect = 0;
+ IOUserClient * newConnect = NULL;
+ IOUserClient * theConnect = NULL;
switch (type) {
case kIOKitDiagnosticsClientType:
err = kIOReturnNotPermitted;
}
break;
+ case kIOKitUserServerClientType:
+ newConnect = IOUserServer::withTask(owningTask);
+ if (!newConnect) {
+ err = kIOReturnNotPermitted;
+ }
+ break;
default:
err = kIOReturnBadArgument;
}
}
}
+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