diff --git a/01_wait_forever/src/panic_wait.rs b/01_wait_forever/src/panic_wait.rs index c0ee2be3..c9a8f5e4 100644 --- a/01_wait_forever/src/panic_wait.rs +++ b/01_wait_forever/src/panic_wait.rs @@ -6,6 +6,10 @@ use core::panic::PanicInfo; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + #[panic_handler] fn panic(_info: &PanicInfo) -> ! { unimplemented!() diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index bcb3f8c3..221113ef 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -327,13 +327,16 @@ diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs --- 01_wait_forever/src/panic_wait.rs +++ 02_runtime_init/src/panic_wait.rs -@@ -4,9 +4,10 @@ +@@ -4,6 +4,7 @@ //! A panic handler that infinitely waits. +use crate::cpu; use core::panic::PanicInfo; + //-------------------------------------------------------------------------------------------------- +@@ -12,5 +13,5 @@ + #[panic_handler] fn panic(_info: &PanicInfo) -> ! { - unimplemented!() diff --git a/02_runtime_init/src/panic_wait.rs b/02_runtime_init/src/panic_wait.rs index cc0e1ae0..7e9adfce 100644 --- a/02_runtime_init/src/panic_wait.rs +++ b/02_runtime_init/src/panic_wait.rs @@ -7,6 +7,10 @@ use crate::cpu; use core::panic::PanicInfo; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + #[panic_handler] fn panic(_info: &PanicInfo) -> ! { cpu::wait_forever() diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index 131e45b3..dffbbb8a 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -238,7 +238,7 @@ diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs diff -uNr 02_runtime_init/src/panic_wait.rs 03_hacky_hello_world/src/panic_wait.rs --- 02_runtime_init/src/panic_wait.rs +++ 03_hacky_hello_world/src/panic_wait.rs -@@ -4,10 +4,16 @@ +@@ -4,14 +4,52 @@ //! A panic handler that infinitely waits. @@ -246,9 +246,45 @@ diff -uNr 02_runtime_init/src/panic_wait.rs 03_hacky_hello_world/src/panic_wait. +use crate::{cpu, println}; use core::panic::PanicInfo; + //-------------------------------------------------------------------------------------------------- + // Private Code + //-------------------------------------------------------------------------------------------------- + ++/// Stop immediately if called a second time. ++/// ++/// # Note ++/// ++/// Using atomics here relieves us from needing to use `unsafe` for the static variable. ++/// ++/// On `AArch64`, which is the only implemented architecture at the time of writing this, ++/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store ++/// instructions. They are therefore safe to use even with MMU + caching deactivated. ++/// ++/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load ++/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store ++fn panic_prevent_reenter() { ++ use core::sync::atomic::{AtomicBool, Ordering}; ++ ++ #[cfg(not(target_arch = "aarch64"))] ++ compile_error!("Add the target_arch to above's check if the following code is safe to use"); ++ ++ static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); ++ ++ if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { ++ PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); ++ ++ return; ++ } ++ ++ cpu::wait_forever() ++} ++ #[panic_handler] -fn panic(_info: &PanicInfo) -> ! { +fn panic(info: &PanicInfo) -> ! { ++ // Protect against panic infinite loops if any of the following code panics itself. ++ panic_prevent_reenter(); ++ + if let Some(args) = info.message() { + println!("\nKernel panic: {}", args); + } else { diff --git a/03_hacky_hello_world/src/panic_wait.rs b/03_hacky_hello_world/src/panic_wait.rs index 3c1ca85b..e37724a4 100644 --- a/03_hacky_hello_world/src/panic_wait.rs +++ b/03_hacky_hello_world/src/panic_wait.rs @@ -7,8 +7,44 @@ use crate::{cpu, println}; use core::panic::PanicInfo; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + if let Some(args) = info.message() { println!("\nKernel panic: {}", args); } else { diff --git a/04_safe_globals/src/panic_wait.rs b/04_safe_globals/src/panic_wait.rs index 3c1ca85b..e37724a4 100644 --- a/04_safe_globals/src/panic_wait.rs +++ b/04_safe_globals/src/panic_wait.rs @@ -7,8 +7,44 @@ use crate::{cpu, println}; use core::panic::PanicInfo; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + if let Some(args) = info.message() { println!("\nKernel panic: {}", args); } else { diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index d54fa722..44e5aadf 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -1414,7 +1414,7 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs diff -uNr 04_safe_globals/src/panic_wait.rs 05_drivers_gpio_uart/src/panic_wait.rs --- 04_safe_globals/src/panic_wait.rs +++ 05_drivers_gpio_uart/src/panic_wait.rs -@@ -4,15 +4,35 @@ +@@ -4,13 +4,29 @@ //! A panic handler that infinitely waits. @@ -1422,11 +1422,11 @@ diff -uNr 04_safe_globals/src/panic_wait.rs 05_drivers_gpio_uart/src/panic_wait. -use core::panic::PanicInfo; +use crate::{bsp, cpu}; +use core::{fmt, panic::PanicInfo}; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Code -+//-------------------------------------------------------------------------------------------------- -+ + + //-------------------------------------------------------------------------------------------------- + // Private Code + //-------------------------------------------------------------------------------------------------- + +fn _panic_print(args: fmt::Arguments) { + use fmt::Write; + @@ -1442,9 +1442,13 @@ diff -uNr 04_safe_globals/src/panic_wait.rs 05_drivers_gpio_uart/src/panic_wait. + _panic_print(format_args_nl!($($arg)*)); + }) +} ++ + /// Stop immediately if called a second time. + /// + /// # Note +@@ -46,9 +62,9 @@ + panic_prevent_reenter(); - #[panic_handler] - fn panic(info: &PanicInfo) -> ! { if let Some(args) = info.message() { - println!("\nKernel panic: {}", args); + panic_println!("\nKernel panic: {}", args); diff --git a/05_drivers_gpio_uart/src/panic_wait.rs b/05_drivers_gpio_uart/src/panic_wait.rs index 946041b3..e879b5b3 100644 --- a/05_drivers_gpio_uart/src/panic_wait.rs +++ b/05_drivers_gpio_uart/src/panic_wait.rs @@ -27,8 +27,40 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + if let Some(args) = info.message() { panic_println!("\nKernel panic: {}", args); } else { diff --git a/06_uart_chainloader/demo_payload_rpi3.img b/06_uart_chainloader/demo_payload_rpi3.img index 800ae213..b95058e4 100755 Binary files a/06_uart_chainloader/demo_payload_rpi3.img and b/06_uart_chainloader/demo_payload_rpi3.img differ diff --git a/06_uart_chainloader/demo_payload_rpi4.img b/06_uart_chainloader/demo_payload_rpi4.img index 03c84dda..33debd90 100755 Binary files a/06_uart_chainloader/demo_payload_rpi4.img and b/06_uart_chainloader/demo_payload_rpi4.img differ diff --git a/06_uart_chainloader/src/panic_wait.rs b/06_uart_chainloader/src/panic_wait.rs index 946041b3..e879b5b3 100644 --- a/06_uart_chainloader/src/panic_wait.rs +++ b/06_uart_chainloader/src/panic_wait.rs @@ -27,8 +27,40 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + if let Some(args) = info.message() { panic_println!("\nKernel panic: {}", args); } else { diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 762e3cb3..bfd2ee14 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -635,12 +635,15 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs --- 06_uart_chainloader/src/panic_wait.rs +++ 07_timestamps/src/panic_wait.rs -@@ -29,10 +29,23 @@ +@@ -58,13 +58,26 @@ #[panic_handler] fn panic(info: &PanicInfo) -> ! { + use crate::time::interface::TimeManager; + + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + + let timestamp = crate::time::time_manager().uptime(); + if let Some(args) = info.message() { diff --git a/07_timestamps/src/panic_wait.rs b/07_timestamps/src/panic_wait.rs index 923db329..3c57f562 100644 --- a/07_timestamps/src/panic_wait.rs +++ b/07_timestamps/src/panic_wait.rs @@ -27,10 +27,42 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/08_hw_debug_JTAG/src/panic_wait.rs b/08_hw_debug_JTAG/src/panic_wait.rs index 923db329..3c57f562 100644 --- a/08_hw_debug_JTAG/src/panic_wait.rs +++ b/08_hw_debug_JTAG/src/panic_wait.rs @@ -27,10 +27,42 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/09_privilege_level/src/panic_wait.rs b/09_privilege_level/src/panic_wait.rs index 923db329..3c57f562 100644 --- a/09_privilege_level/src/panic_wait.rs +++ b/09_privilege_level/src/panic_wait.rs @@ -27,10 +27,42 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs index 923db329..3c57f562 100644 --- a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs +++ b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs @@ -27,10 +27,42 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/11_exceptions_part1_groundwork/src/panic_wait.rs b/11_exceptions_part1_groundwork/src/panic_wait.rs index 923db329..3c57f562 100644 --- a/11_exceptions_part1_groundwork/src/panic_wait.rs +++ b/11_exceptions_part1_groundwork/src/panic_wait.rs @@ -27,10 +27,42 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index b5649cd0..5de7c0ef 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -1744,7 +1744,16 @@ diff -uNr 11_exceptions_part1_groundwork/src/panic_wait.rs 12_integrated_testing /// Prints with a newline - only use from the panic handler. /// /// Carbon copy from -@@ -48,5 +65,5 @@ +@@ -53,7 +70,7 @@ + return; + } + +- cpu::wait_forever() ++ _panic_exit() + } + + #[panic_handler] +@@ -80,5 +97,5 @@ ); } diff --git a/12_integrated_testing/src/panic_wait.rs b/12_integrated_testing/src/panic_wait.rs index 2e56f1ce..a1b090d7 100644 --- a/12_integrated_testing/src/panic_wait.rs +++ b/12_integrated_testing/src/panic_wait.rs @@ -44,10 +44,42 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 72b3fa5e..d89093df 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -2511,15 +2511,15 @@ diff -uNr 12_integrated_testing/src/panic_wait.rs 13_exceptions_part2_peripheral use core::{fmt, panic::PanicInfo}; //-------------------------------------------------------------------------------------------------- -@@ -48,6 +48,8 @@ +@@ -77,6 +77,8 @@ fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; + unsafe { exception::asynchronous::local_irq_mask() }; + - let timestamp = crate::time::time_manager().uptime(); + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); - if let Some(args) = info.message() { diff -uNr 12_integrated_testing/src/state.rs 13_exceptions_part2_peripheral_IRQs/src/state.rs --- 12_integrated_testing/src/state.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/panic_wait.rs b/13_exceptions_part2_peripheral_IRQs/src/panic_wait.rs index da7106c9..787bc7dc 100644 --- a/13_exceptions_part2_peripheral_IRQs/src/panic_wait.rs +++ b/13_exceptions_part2_peripheral_IRQs/src/panic_wait.rs @@ -44,12 +44,44 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; unsafe { exception::asynchronous::local_irq_mask() }; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/14_virtual_mem_part2_mmio_remap/src/panic_wait.rs b/14_virtual_mem_part2_mmio_remap/src/panic_wait.rs index da7106c9..787bc7dc 100644 --- a/14_virtual_mem_part2_mmio_remap/src/panic_wait.rs +++ b/14_virtual_mem_part2_mmio_remap/src/panic_wait.rs @@ -44,12 +44,44 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; unsafe { exception::asynchronous::local_irq_mask() }; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/15_virtual_mem_part3_precomputed_tables/src/panic_wait.rs b/15_virtual_mem_part3_precomputed_tables/src/panic_wait.rs index da7106c9..787bc7dc 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/panic_wait.rs +++ b/15_virtual_mem_part3_precomputed_tables/src/panic_wait.rs @@ -44,12 +44,44 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; unsafe { exception::asynchronous::local_irq_mask() }; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/16_virtual_mem_part4_higher_half_kernel/src/panic_wait.rs b/16_virtual_mem_part4_higher_half_kernel/src/panic_wait.rs index da7106c9..787bc7dc 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/panic_wait.rs +++ b/16_virtual_mem_part4_higher_half_kernel/src/panic_wait.rs @@ -44,12 +44,44 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; unsafe { exception::asynchronous::local_irq_mask() }; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() { diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index 64189d65..9fcd693e 100755 Binary files a/X1_JTAG_boot/jtag_boot_rpi3.img and b/X1_JTAG_boot/jtag_boot_rpi3.img differ diff --git a/X1_JTAG_boot/jtag_boot_rpi4.img b/X1_JTAG_boot/jtag_boot_rpi4.img index 6c029255..fb16a02b 100755 Binary files a/X1_JTAG_boot/jtag_boot_rpi4.img and b/X1_JTAG_boot/jtag_boot_rpi4.img differ diff --git a/X1_JTAG_boot/src/panic_wait.rs b/X1_JTAG_boot/src/panic_wait.rs index 923db329..3c57f562 100644 --- a/X1_JTAG_boot/src/panic_wait.rs +++ b/X1_JTAG_boot/src/panic_wait.rs @@ -27,10 +27,42 @@ macro_rules! panic_println { }) } +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + cpu::wait_forever() +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + let timestamp = crate::time::time_manager().uptime(); if let Some(args) = info.message() {