blob: 61e6ae59c52f24d29bc4e41a789259fdddd028e9 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2008 Travis Geiselbrecht
//
// 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
#ifndef ZIRCON_KERNEL_INCLUDE_PLATFORM_H_
#define ZIRCON_KERNEL_INCLUDE_PLATFORM_H_
#include <lib/zbi-format/reboot.h>
#include <lib/zx/result.h>
#include <sys/types.h>
#include <zircon/boot/crash-reason.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <dev/power.h>
#include <kernel/cpu.h>
#define BOOT_CPU_ID 0
typedef enum {
HALT_ACTION_HALT = 0, // Spin forever.
HALT_ACTION_REBOOT, // Reset the CPU.
HALT_ACTION_REBOOT_BOOTLOADER, // Reboot into the bootloader.
HALT_ACTION_REBOOT_RECOVERY, // Reboot into the recovery partition.
HALT_ACTION_SHUTDOWN, // Shutdown and power off.
} platform_halt_action;
// Holds platform-specific, per-cpu state used to suspend/resume a CPU.
struct PlatformCpuResumeState {
#if defined(__aarch64__)
uint64_t cntkctl_el1{};
#endif
};
/* super early platform initialization, before almost everything */
void platform_early_init();
/* Perform any set up required before virtual memory is enabled, or the heap is set up. */
void platform_prevm_init();
/* later init, after the kernel has come up */
void platform_init();
/* platform_halt halts the system and performs the |suggested_action|.
*
* This function is used in both the graceful shutdown and panic paths so it
* does not perform more complex actions like switching to the primary CPU,
* unloading the run queue of secondary CPUs, stopping secondary CPUs, etc.
*
* There is no returning from this function.
*/
void platform_halt(platform_halt_action suggested_action, zircon_crash_reason_t reason) __NO_RETURN;
/* The platform specific actions to be taken in a halt situation. This is a
* weak symbol meant to be overloaded by platform specific implementations and
* called from the common |platform_halt| implementation. Do not call this
* function directly, call |platform_halt| instead.
*
* There is no returning from this function.
*/
void platform_specific_halt(platform_halt_action suggested_action, zircon_crash_reason_t reason,
bool halt_on_panic) __NO_RETURN;
/* optionally stop the current cpu in a way the platform finds appropriate */
void platform_halt_cpu();
// Returns true iff this platform supports |platform_suspend_cpu|.
bool platform_supports_suspend_cpu();
// Specifies whether this suspend operation is limited to the calling CPU or may
// power down the encapsulating power domain.
enum class PlatformAllowDomainPowerDown : bool { No, Yes };
// Suspend the calling CPU.
//
// On success, the CPU will enter an implementation-defined suspend state.
//
// If |allow_domain| is No, then the operation will only target the calling CPU.
// However, if Yes is specified, then, depending on the implementation, the
// power domain encapsulating the calling CPU may also be suspended and powered
// down.
//
// Prior to calling this function, it's critical to set up some kind of
// interrupt that will wake the CPU and resume execution. Upon successful
// suspend and resume, this call returns ZX_OK.
//
// Prior to calling, interrupts must be disabled, preemption must be disabled,
// and the caller must be pinned to the calling CPU.
//
// The calling thread must be a kernel-only thread. Because this routine saves
// only the minimum required register state, it is an error to call this
// function on a thread that has a "user half" (ThreadDispatcher).
//
// Possible error results include (but are not limited to),
//
// ZX_ERR_NOT_SUPPORTED if unsupported on this platform.
//
// ZX_ERR_ACCESS_DENIED or ZX_ERR_INVALID_ARGS if the suspend power state is
// incompatible with the current power state of other CPUs. This is a somewhat
// normal error and must be handled by callers.
//
// TODO(https://fxbug.dev/417556024): Consider adding a platform-specific or
// custom result type to differentiates between success-but-did-not-power-down
// and powered-down.
//
// TODO(https://fxbug.dev/417558115): Consider checking the state of the
// secondary CPUs in order to determine which power state value to use so that
// we can eliminate the need to return ZX_ERR_ACCESS_DENIED or
// ZX_ERR_INVALID_ARGS in "normal" situations.
//
// TODO(https://fxbug.dev/417558115): Currently, the caller is responsible for
// determining if pausing/resuming the monotonic clock is necessary and then
// actually doing it. More thought needs to be given to where that logic should
// live. Right now, it's done in |IdlePowerThread::UpdateMonotonicClock|,
// however, it might be better to move some of that logic down into the platform
// layer (perhaps within |platform_suspend_cpu|).
zx_status_t platform_suspend_cpu(PlatformAllowDomainPowerDown allow_domain);
// Returns true if this system has a debug serial port that is enabled
bool platform_serial_enabled();
// Prepare the kernel debug UART for a suspend operation which might result in
// de-clocking, or de-clocking+power-gating, the UART hardware.
//
// This function should only be called by the BOOT_CPU idle/power thread, with
// interrupts off, after the secondaries have all suspended, just before it
// transfers control to a higher authority (Secure Monitor, ACPI call, etc) to
// enter into its low power state.
//
// This method is *not* idempotent. `platform_serial_prepare_for_suspend`
// should not be called again until a matching call to
// `platform_serial_wakeup_from_suspend` has been made.
//
// That said, it is safe to call this method when `platform_serial_enabled`
// returns false, as well as when the underlying serial driver does not
// support/require suspension. The operation will simply be a no-op.
//
void platform_serial_prepare_for_suspend();
// Wake the kernel debug UART up after bringing the BOOT_CPU out of a low power
// state where the UART hardware may have been de-clocked or power gated.
//
// This function should only be called by the BOOT_CPU idle/power thread, with
// interrupts off, immediately after control is returned to it by its higher
// authority. See `platform_serial_prepare_for_suspend`.
//
// This method is *not* idempotent. `platform_serial_wakeup_from_suspend` should
// not be called again until a matching call to
// `platform_serial_prepare_for_suspend` has been made.
//
// That said, it is safe to call this method when `platform_serial_enabled`
// returns false, as well as when the underlying serial driver does not
// support/require suspension. The operation will simply be a no-op.
//
void platform_serial_wakeup_from_suspend();
// Accessors for the HW reboot reason which may or may not have been delivered
// by the bootloader.
void platform_set_hw_reboot_reason(zbi_hw_reboot_reason_t reason);
zbi_hw_reboot_reason_t platform_hw_reboot_reason();
// platform_panic_start informs the system that a panic message is about
// to be printed and that platform_halt will be called shortly. The
// platform should stop other CPUs if requested and do whatever is necessary
// to safely ensure that the panic message will be visible to the user.
enum class PanicStartHaltOtherCpus { No = 0, Yes };
void platform_panic_start(PanicStartHaltOtherCpus option = PanicStartHaltOtherCpus::Yes);
/* start the given cpu in a way the platform finds appropriate */
zx_status_t platform_start_cpu(cpu_num_t cpu_id, uint64_t mpid);
// Get the state of a CPU.
zx::result<power_cpu_state> platform_get_cpu_state(cpu_num_t cpu_id);
#endif // ZIRCON_KERNEL_INCLUDE_PLATFORM_H_