mango_rt/
panic_wait.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//
3// Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
4
5//! A panic handler that infinitely waits.
6
7use core::panic::PanicInfo;
8use mango_core::println;
9
10//--------------------------------------------------------------------------------------------------
11// Private Code
12//--------------------------------------------------------------------------------------------------
13
14/// The point of exit for `libkernel`.
15///
16/// It is linked weakly, so that the integration tests can overload its standard behavior.
17fn _panic_exit(system: &spin::Mutex<impl mango_hal::devices::System>) -> !
18{
19  #[cfg(not(feature = "test_build"))]
20  {
21    system.lock().wait_forever()
22  }
23
24  #[cfg(feature = "test_build")]
25  {
26    mango_core::qemu::exit_qemu(mango_core::qemu::QemuExitCode::Failed);
27  }
28}
29
30/// Stop immediately if called a second time.
31///
32/// # Note
33///
34/// Using atomics here relieves us from needing to use `unsafe` for the static variable.
35///
36/// On `AArch64`, which is the only implemented architecture at the time of writing this,
37/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store
38/// instructions. They are therefore safe to use even with MMU + caching deactivated.
39///
40/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load
41/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store
42fn panic_prevent_reenter(system: &spin::Mutex<impl mango_hal::devices::System>)
43{
44  use core::sync::atomic::{AtomicBool, Ordering};
45
46  #[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
47  compile_error!("Add the target_arch to above's check if the following code is safe to use");
48
49  static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false);
50
51  if !PANIC_IN_PROGRESS.load(Ordering::Relaxed)
52  {
53    PANIC_IN_PROGRESS.store(true, Ordering::Relaxed);
54
55    return;
56  }
57
58  _panic_exit(system)
59}
60
61/// panic handlers for kernels.
62pub fn panic_handler(info: &PanicInfo, system: &spin::Mutex<impl mango_hal::devices::System>) -> !
63{
64  system.lock().disable_interruptions();
65  // Protect against panic infinite loops if any of the following code panics itself.
66  panic_prevent_reenter(system);
67
68  let timestamp = mango_core::TIME.lock().get_uptime_or(0);
69  let (location, line, column) = match info.location()
70  {
71    Some(loc) => (loc.file(), loc.line(), loc.column()),
72    _ => ("???", 0, 0),
73  };
74
75  println!(
76    "[  {:>3}.{:06}] Kernel panic!\n\n\
77        Panic location:\n      File '{}', line {}, column {}\n\n\
78        {}",
79    timestamp.as_secs(),
80    timestamp.subsec_micros(),
81    location,
82    line,
83    column,
84    info.message(),
85  );
86
87  _panic_exit(system)
88}