-static OSArray *gIOCPUs;
-static const OSSymbol *gIOCPUStateKey;
-static OSString *gIOCPUStateNames[kIOCPUStateCount];
-
-void IOCPUSleepKernel(void)
-{
- long cnt, numCPUs;
- IOCPU *target;
-
- numCPUs = gIOCPUs->getCount();
-
- // Sleep the CPUs.
- cnt = numCPUs;
- while (cnt--) {
- target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
- if (target->getCPUState() == kIOCPUStateRunning) {
- target->haltCPU();
- }
- }
-
- // Wake the other CPUs.
- for (cnt = 1; cnt < numCPUs; cnt++) {
- target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
- if (target->getCPUState() == kIOCPUStateStopped) {
- processor_start(target->getMachProcessor());
- }
- }
-}
-
-void IOCPU::initCPUs(void)
-{
- if (gIOCPUs == 0) {
- gIOCPUs = OSArray::withCapacity(1);
-
- gIOCPUStateKey = OSSymbol::withCStringNoCopy("IOCPUState");
-
- gIOCPUStateNames[kIOCPUStateUnregistered] =
- OSString::withCStringNoCopy("Unregistered");
- gIOCPUStateNames[kIOCPUStateUninitalized] =
- OSString::withCStringNoCopy("Uninitalized");
- gIOCPUStateNames[kIOCPUStateStopped] =
- OSString::withCStringNoCopy("Stopped");
- gIOCPUStateNames[kIOCPUStateRunning] =
- OSString::withCStringNoCopy("Running");
- }
-}
-
-bool IOCPU::start(IOService *provider)
-{
- OSData *busFrequency, *cpuFrequency, *timebaseFrequency;
-
- if (!super::start(provider)) return false;
-
- initCPUs();
-
- _cpuGroup = gIOCPUs;
- cpuNub = provider;
-
- gIOCPUs->setObject(this);
-
- // Correct the bus, cpu and dec frequencies in the device tree.
- busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
- cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_clock_rate_hz, 4);
- timebaseFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.timebase_frequency_hz, 4);
- provider->setProperty("bus-frequency", busFrequency);
- provider->setProperty("clock-frequency", cpuFrequency);
- provider->setProperty("timebase-frequency", timebaseFrequency);
- busFrequency->release();
- cpuFrequency->release();
- timebaseFrequency->release();
-
- setProperty("IOCPUID", (UInt32)this, 32);
-
- setCPUNumber(0);
- setCPUState(kIOCPUStateUnregistered);
-
- return true;
-}
-
-IOReturn IOCPU::setProperties(OSObject *properties)
-{
- OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
- OSString *stateStr;
-
- if (dict == 0) return kIOReturnUnsupported;
-
- stateStr = OSDynamicCast(OSString, dict->getObject(gIOCPUStateKey));
- if (stateStr != 0) {
- if (!IOUserClient::clientHasPrivilege(current_task(), "root"))
- return kIOReturnNotPrivileged;
-
- if (_cpuNumber == 0) return kIOReturnUnsupported;
-
- if (stateStr->isEqualTo("running")) {
- if (_cpuState == kIOCPUStateStopped) {
- processor_start(machProcessor);
- } else if (_cpuState != kIOCPUStateRunning) {
+#if !USE_APPLEARMSMP
+void
+IOCPUSleepKernel(void)
+{
+#if defined(__x86_64__)
+ extern IOCPU *currentShutdownTarget;
+#endif
+ unsigned int cnt, numCPUs;
+ IOCPU *target;
+ IOCPU *bootCPU = NULL;
+ IOPMrootDomain *rootDomain = IOService::getPMRootDomain();
+
+ printf("IOCPUSleepKernel enter\n");
+#if defined(__arm64__)
+ sched_override_recommended_cores_for_sleep();
+#endif
+
+ rootDomain->tracePoint( kIOPMTracePointSleepPlatformActions );
+ IOPlatformActionsPreSleep();
+ rootDomain->tracePoint( kIOPMTracePointSleepCPUs );
+
+ numCPUs = gIOCPUs->getCount();
+#if defined(__x86_64__)
+ currentShutdownTarget = NULL;
+#endif
+
+ integer_t old_pri;
+ thread_t self = current_thread();
+
+ /*
+ * We need to boost this thread's priority to the maximum kernel priority to
+ * ensure we can urgently preempt ANY thread currently executing on the
+ * target CPU. Note that realtime threads have their own mechanism to eventually
+ * demote their priority below MAXPRI_KERNEL if they hog the CPU for too long.
+ */
+ old_pri = thread_kern_get_pri(self);
+ thread_kern_set_pri(self, thread_kern_get_kernel_maxpri());
+
+ // Sleep the CPUs.
+ ml_set_is_quiescing(true);
+ cnt = numCPUs;
+ while (cnt--) {
+ target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
+
+ // We make certain that the bootCPU is the last to sleep
+ // We'll skip it for now, and halt it after finishing the
+ // non-boot CPU's.
+ if (target->getCPUNumber() == (UInt32)master_cpu) {
+ bootCPU = target;
+ } else if (target->getCPUState() == kIOCPUStateRunning) {
+#if defined(__x86_64__)
+ currentShutdownTarget = target;
+#endif
+ target->haltCPU();
+ }
+ }
+
+ assert(bootCPU != NULL);
+ assert(cpu_number() == master_cpu);
+
+ console_suspend();
+
+ rootDomain->tracePoint( kIOPMTracePointSleepPlatformDriver );
+ rootDomain->stop_watchdog_timer();
+
+ /*
+ * Now sleep the boot CPU, including calling the kQueueQuiesce actions.
+ * The system sleeps here.
+ */
+
+ bootCPU->haltCPU();
+ ml_set_is_quiescing(false);
+
+ /*
+ * The system is now coming back from sleep on the boot CPU.
+ * The kQueueActive actions have already been called.
+ */
+
+ rootDomain->start_watchdog_timer();
+ rootDomain->tracePoint( kIOPMTracePointWakePlatformActions );
+
+ console_resume();
+
+ IOPlatformActionsPostResume();
+ rootDomain->tracePoint( kIOPMTracePointWakeCPUs );
+
+ // Wake the other CPUs.
+ for (cnt = 0; cnt < numCPUs; cnt++) {
+ target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
+
+ // Skip the already-woken boot CPU.
+ if (target->getCPUNumber() != (UInt32)master_cpu) {
+ if (target->getCPUState() == kIOCPUStateRunning) {
+ panic("Spurious wakeup of cpu %u", (unsigned int)(target->getCPUNumber()));
+ }
+
+ if (target->getCPUState() == kIOCPUStateStopped) {
+ processor_start(target->getMachProcessor());
+ }
+ }
+ }
+
+#if defined(__arm64__)
+ sched_restore_recommended_cores_after_sleep();
+#endif
+
+ thread_kern_set_pri(self, old_pri);
+ printf("IOCPUSleepKernel exit\n");
+}
+
+static bool
+is_IOCPU_disabled(void)
+{
+ return false;
+}
+#else /* !USE_APPLEARMSMP */
+static bool
+is_IOCPU_disabled(void)
+{
+ return true;
+}
+#endif /* !USE_APPLEARMSMP */
+
+bool
+IOCPU::start(IOService *provider)
+{
+ if (is_IOCPU_disabled()) {
+ return false;
+ }
+
+ if (!super::start(provider)) {
+ return false;
+ }
+
+ _cpuGroup = gIOCPUs;
+ cpuNub = provider;
+
+ IOLockLock(gIOCPUsLock);
+ gIOCPUs->setObject(this);
+ IOLockUnlock(gIOCPUsLock);
+
+ // Correct the bus, cpu and timebase frequencies in the device tree.
+ if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
+ OSSharedPtr<OSData> busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
+ provider->setProperty("bus-frequency", busFrequency.get());
+ } else {
+ OSSharedPtr<OSData> busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_frequency_hz, 8);
+ provider->setProperty("bus-frequency", busFrequency.get());
+ }
+
+ if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
+ OSSharedPtr<OSData> cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_clock_rate_hz, 4);
+ provider->setProperty("clock-frequency", cpuFrequency.get());
+ } else {
+ OSSharedPtr<OSData> cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_frequency_hz, 8);
+ provider->setProperty("clock-frequency", cpuFrequency.get());
+ }
+
+ OSSharedPtr<OSData> timebaseFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.timebase_frequency_hz, 4);
+ provider->setProperty("timebase-frequency", timebaseFrequency.get());
+
+ super::setProperty("IOCPUID", getRegistryEntryID(), sizeof(uint64_t) * 8);
+
+ setCPUNumber(0);
+ setCPUState(kIOCPUStateUnregistered);
+
+ return true;
+}
+
+void
+IOCPU::detach(IOService *provider)
+{
+ if (is_IOCPU_disabled()) {
+ return;
+ }
+
+ super::detach(provider);
+ IOLockLock(gIOCPUsLock);
+ unsigned int index = gIOCPUs->getNextIndexOfObject(this, 0);
+ if (index != (unsigned int)-1) {
+ gIOCPUs->removeObject(index);
+ }
+ IOLockUnlock(gIOCPUsLock);
+}
+
+OSObject *
+IOCPU::getProperty(const OSSymbol *aKey) const
+{
+ if (aKey == gIOCPUStateKey) {
+ return gIOCPUStateNames[_cpuState].get();
+ }
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ return super::getProperty(aKey);
+#pragma clang diagnostic pop
+}
+
+bool
+IOCPU::setProperty(const OSSymbol *aKey, OSObject *anObject)
+{
+ if (aKey == gIOCPUStateKey) {
+ return false;
+ }
+
+ return super::setProperty(aKey, anObject);
+}
+
+bool
+IOCPU::serializeProperties(OSSerialize *serialize) const
+{
+ bool result;
+ OSSharedPtr<OSDictionary> dict = dictionaryWithProperties();
+ if (!dict) {
+ return false;
+ }
+ dict->setObject(gIOCPUStateKey.get(), gIOCPUStateNames[_cpuState].get());
+ result = dict->serialize(serialize);
+ return result;
+}
+
+IOReturn
+IOCPU::setProperties(OSObject *properties)
+{
+ OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
+ OSString *stateStr;
+ IOReturn result;
+
+ if (dict == NULL) {
+ return kIOReturnUnsupported;
+ }
+
+ stateStr = OSDynamicCast(OSString, dict->getObject(gIOCPUStateKey.get()));
+ if (stateStr != NULL) {
+ result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
+ if (result != kIOReturnSuccess) {
+ return result;
+ }
+
+ if (setProperty(gIOCPUStateKey.get(), stateStr)) {
+ return kIOReturnSuccess;
+ }
+
+ return kIOReturnUnsupported;
+ }
+