1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 01:57:45 +00:00

Kernel: Add RPi Watchdog and use it for system shutdown

The Raspberry Pi hardware doesn't support a proper software-initiated
shutdown, so this instead uses the watchdog to reboot to a special
partition which the firmware interprets as an immediate halt on
shutdown. When running under Qemu, this causes the emulator to exit.
This commit is contained in:
Daniel Bertalan 2023-05-15 07:34:19 +02:00 committed by Andrew Kaster
parent 555d301e3b
commit d9c557d0b4
5 changed files with 80 additions and 0 deletions

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2023, Daniel Bertalan <dani@danielbertalan.dev>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/aarch64/RPi/MMIO.h>
#include <Kernel/Arch/aarch64/RPi/Watchdog.h>
namespace Kernel::RPi {
struct WatchdogRegisters {
u32 rstc;
u32 rsts;
u32 wdog;
};
constexpr u32 PASSWORD = 0x5a000000;
constexpr u32 RSTS_PARTITION_MASK = 0xfffffaaa;
constexpr u32 RSTS_PARTITION_SHUTDOWN = 0x00000555;
constexpr u32 RSTC_WRCFG_MASK = 0xffffffcf;
constexpr u32 RSTC_WRCFG_FULL_RESET = 0x00000020;
Watchdog::Watchdog()
: m_registers(MMIO::the().peripheral<WatchdogRegisters>(0x10'001c))
{
}
Watchdog& Watchdog::the()
{
static Watchdog watchdog;
return watchdog;
}
// This is the same mechanism used by Linux, the ARM Trusted Firmware and U-Boot to trigger a system shutdown.
// See e.g. https://github.com/ARM-software/arm-trusted-firmware/blob/dcf430656ca8ef964fa55ad9eb81cf838c7837f2/plat/rpi/common/rpi3_pm.c#L231-L249
void Watchdog::system_shutdown()
{
// The Raspberry Pi hardware doesn't support powering off. Setting the reboot target partition to this
// special value will cause the firmware to halt the CPU and put it in a low power state when the watchdog
// timer expires. When running under Qemu, this will cause the emulator to exit.
m_registers->rsts = PASSWORD | (m_registers->rsts & RSTS_PARTITION_MASK) | RSTS_PARTITION_SHUTDOWN;
// Set the timeout to 10 ticks (~150us).
m_registers->wdog = PASSWORD | 10;
// Start the watchdog.
m_registers->rstc = PASSWORD | (m_registers->rstc & RSTC_WRCFG_MASK) | RSTC_WRCFG_FULL_RESET;
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023, Daniel Bertalan <dani@danielbertalan.dev>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
namespace Kernel::RPi {
struct WatchdogRegisters;
class Watchdog {
public:
static Watchdog& the();
void system_shutdown();
private:
Watchdog();
WatchdogRegisters volatile* m_registers;
};
}