blob: 16b87152fa0d7369828079e5070874e63a75d6f6 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2012 Google, Inc.
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <debug.h>
#include <lib/boot-options/boot-options.h>
#include <lib/console.h>
#include <lib/crashlog.h>
#include <lib/debuglog.h>
#include <lib/jtrace/jtrace.h>
#include <lib/persistent-debuglog.h>
#include <platform.h>
#include <stdio.h>
#include <zircon/compiler.h>
#include <zircon/errors.h>
#include <dev/hw_watchdog.h>
#include <kernel/thread.h>
#include <platform/crashlog.h>
#include <platform/debug.h>
// Common platform halt path. This handles some tasks we always want to make
// sure we handle before dropping into the common platform specific halt
// routine.
void platform_halt(platform_halt_action suggested_action, zircon_crash_reason_t reason) {
// Disable the automatic uptime updating. We are going to attempt to
// deliberately halt the system, and we don't want the crashlog to indicate a
// spontaneous reboot.
PlatformCrashlog::Get().EnableCrashlogUptimeUpdates(false);
// We are haling on purpose. Disable the watchdog (if we have one, and if we
// can) if we plan to halt instead of instigate a reboot. If we are going to
// try to actually reboot, pet the dog one last time to give ourselves the
// maximum amount of time to arrange our graceful reboot.
bool halt_on_panic = gBootOptions->halt_on_panic;
if (ENABLE_PANIC_SHELL || halt_on_panic) {
hw_watchdog_set_enabled(false);
} else {
hw_watchdog_pet();
}
// Render and stash our crashlog. crashlog_to_string will decide what should
// be in the crashlog payload based on the provided crash reason.
{
size_t rendered_crashlog_len = 0;
auto& crashlog = PlatformCrashlog::Get();
if (ktl::span<char> target = crashlog.GetRenderTarget(); target.size() > 0) {
rendered_crashlog_len = crashlog_to_string(target, reason);
}
crashlog.Finalize(reason, rendered_crashlog_len);
}
// This is a graceful reboot, invalidate the persistent dlog (if we have one)
// and persistent trace buffer (if we have one) so that we don't attempt to
// recover it during a reboot.
if (reason == ZirconCrashReason::NoCrash) {
persistent_dlog_invalidate();
jtrace_invalidate();
}
// Finally, fall into the platform specific halt handler.
platform_specific_halt(suggested_action, reason, halt_on_panic);
}
namespace {
__NO_RETURN
int cmd_reboot(int argc, const cmd_args* argv, uint32_t flags) {
bool is_panic_shell = (flags & CMD_FLAG_PANIC) != 0;
// If we are already panicking, don't repeat the first half of `platform_halt`. Instead,
// just finish the reboot.
if (is_panic_shell) {
platform_specific_halt(HALT_ACTION_REBOOT, ZirconCrashReason::Panic,
/*halt_on_panic=*/false);
// unreachable
}
platform_halt(HALT_ACTION_REBOOT, ZirconCrashReason::NoCrash);
}
} // namespace
STATIC_COMMAND_START
STATIC_COMMAND_MASKED("reboot", "reboot the system", &cmd_reboot, CMD_AVAIL_ALWAYS)
STATIC_COMMAND_END(power)