mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:52:43 +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:
		
							parent
							
								
									555d301e3b
								
							
						
					
					
						commit
						d9c557d0b4
					
				
					 5 changed files with 80 additions and 0 deletions
				
			
		
							
								
								
									
										47
									
								
								Kernel/Arch/aarch64/RPi/Watchdog.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Kernel/Arch/aarch64/RPi/Watchdog.cpp
									
										
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								Kernel/Arch/aarch64/RPi/Watchdog.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Kernel/Arch/aarch64/RPi/Watchdog.h
									
										
									
									
									
										Normal 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; | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | @ -446,6 +446,7 @@ elseif("${SERENITY_ARCH}" STREQUAL "aarch64") | ||||||
|         Arch/aarch64/RPi/SDHostController.cpp |         Arch/aarch64/RPi/SDHostController.cpp | ||||||
|         Arch/aarch64/RPi/Timer.cpp |         Arch/aarch64/RPi/Timer.cpp | ||||||
|         Arch/aarch64/RPi/UART.cpp |         Arch/aarch64/RPi/UART.cpp | ||||||
|  |         Arch/aarch64/RPi/Watchdog.cpp | ||||||
|     ) |     ) | ||||||
|     set(SOURCES_RUNNING_WITHOUT_MMU |     set(SOURCES_RUNNING_WITHOUT_MMU | ||||||
|         Arch/aarch64/Exceptions.cpp |         Arch/aarch64/Exceptions.cpp | ||||||
|  |  | ||||||
|  | @ -9,6 +9,8 @@ | ||||||
| #if ARCH(X86_64) | #if ARCH(X86_64) | ||||||
| #    include <Kernel/Arch/x86_64/I8042Reboot.h> | #    include <Kernel/Arch/x86_64/I8042Reboot.h> | ||||||
| #    include <Kernel/Arch/x86_64/Shutdown.h> | #    include <Kernel/Arch/x86_64/Shutdown.h> | ||||||
|  | #elif ARCH(AARCH64) | ||||||
|  | #    include <Kernel/Arch/aarch64/RPi/Watchdog.h> | ||||||
| #endif | #endif | ||||||
| #include <Kernel/FileSystem/FileSystem.h> | #include <Kernel/FileSystem/FileSystem.h> | ||||||
| #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/PowerStateSwitch.h> | #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/PowerStateSwitch.h> | ||||||
|  | @ -101,6 +103,8 @@ void SysFSPowerStateSwitchNode::poweroff() | ||||||
| #if ARCH(X86_64) | #if ARCH(X86_64) | ||||||
|     qemu_shutdown(); |     qemu_shutdown(); | ||||||
|     virtualbox_shutdown(); |     virtualbox_shutdown(); | ||||||
|  | #elif ARCH(AARCH64) | ||||||
|  |     RPi::Watchdog::the().system_shutdown(); | ||||||
| #endif | #endif | ||||||
|     dbgln("shutdown attempts failed, applications will stop responding."); |     dbgln("shutdown attempts failed, applications will stop responding."); | ||||||
|     dmesgln("Shutdown can't be completed. It's safe to turn off the computer!"); |     dmesgln("Shutdown can't be completed. It's safe to turn off the computer!"); | ||||||
|  |  | ||||||
|  | @ -8,6 +8,8 @@ | ||||||
| #include <Kernel/Arch/Processor.h> | #include <Kernel/Arch/Processor.h> | ||||||
| #if ARCH(X86_64) | #if ARCH(X86_64) | ||||||
| #    include <Kernel/Arch/x86_64/Shutdown.h> | #    include <Kernel/Arch/x86_64/Shutdown.h> | ||||||
|  | #elif ARCH(AARCH64) | ||||||
|  | #    include <Kernel/Arch/aarch64/RPi/Watchdog.h> | ||||||
| #endif | #endif | ||||||
| #include <Kernel/CommandLine.h> | #include <Kernel/CommandLine.h> | ||||||
| #include <Kernel/KSyms.h> | #include <Kernel/KSyms.h> | ||||||
|  | @ -21,6 +23,8 @@ namespace Kernel { | ||||||
| #if ARCH(X86_64) | #if ARCH(X86_64) | ||||||
|     qemu_shutdown(); |     qemu_shutdown(); | ||||||
|     virtualbox_shutdown(); |     virtualbox_shutdown(); | ||||||
|  | #elif ARCH(AARCH64) | ||||||
|  |     RPi::Watchdog::the().system_shutdown(); | ||||||
| #endif | #endif | ||||||
|     // Note: If we failed to invoke platform shutdown, we need to halt afterwards
 |     // Note: If we failed to invoke platform shutdown, we need to halt afterwards
 | ||||||
|     // to ensure no further execution on any CPU still happens.
 |     // to ensure no further execution on any CPU still happens.
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Daniel Bertalan
						Daniel Bertalan