- IOPMrootDomain *pmRootDomain;
- AbsoluteTime deadline;
- thread_call_t shutdown_hang;
-
- if(type == kPEHaltCPU || type == kPERestartCPU || type == kPEUPSDelayHaltCPU)
- {
- pmRootDomain = IOService::getPMRootDomain();
- /* 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)(uintptr_t) type);
- clock_interval_to_deadline( 30, kSecondScale, &deadline );
- thread_call_enter1_delayed( shutdown_hang, 0, deadline );
+ if (gIOPlatform) {
+ return gIOPlatform->getProductName( name, maxLength );
+ } else {
+ return false;
+ }
+}
+
+int
+PEGetPlatformEpoch(void)
+{
+ if (gIOPlatform) {
+ 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
+PEHaltRestartInternal(unsigned int type, uint32_t details)
+{
+ IOPMrootDomain *pmRootDomain;
+ AbsoluteTime deadline;
+ thread_call_t shutdown_hang;
+ IORegistryEntry *node;
+ OSData *data;
+ uint32_t timeout = kShutdownTimeout;
+ 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
+ * 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. If the device wants a different
+ * timeout, use that value instead of 30 seconds.
+ */
+#if defined(__arm__) || defined(__arm64__)
+#define RESTART_NODE_PATH "/defaults"
+#else
+#define RESTART_NODE_PATH "/chosen"
+#endif
+ node = IORegistryEntry::fromPath( RESTART_NODE_PATH, gIODTPlane );
+ if (node) {
+ data = OSDynamicCast( OSData, node->getProperty( "halt-restart-timeout" ));
+ if (data && data->getLength() == 4) {
+ timeout = *((uint32_t *) data->getBytesNoCopy());
+ }
+ }
+
+#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
+ * 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.
+ */
+ } 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 defined(__x86_64__)
+ if (coprocessor_cross_panic_enabled)
+#endif
+ 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, details);
+ PE_sync_panic_buffers();
+ } else if (type == kPEPanicEnd) {
+#if defined(__x86_64__)
+ if (coprocessor_cross_panic_enabled)
+#endif
+ IOCPURunPlatformPanicActions(type, details);
+ } else if (type == kPEPanicBegin) {
+#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, details);
+ }
+ }
+ }