Skip to content

Commit

Permalink
sys: Fix halt! and crash! message handling
Browse files Browse the repository at this point in the history
Due to the way we called `__furi_crash_implementation` the value of the
`r12` register would often get clobbered, corrupting the message.

This is fixed by directly jumping to the crash handler from inline assembly.

Only messages stored on flash memory can be shown at reboot, so strings
stored in RAM (including string constants in external apps)
will be replaced by a generic "check serial logs" message.

This also allows calling `halt!` and `crash!` in their no-argument form.
  • Loading branch information
dcoles committed Jan 7, 2025
1 parent ba4391f commit f9c3215
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Added

- `flipperzero_sys::furi::FuriBox` for low-level heap allocations
- `flipperzero_sys::halt!` macro

### Changed

- Fixed passing of crash message `__furi_crash_implementation`
- Allow no argument calls to `flipperzero_sys::crash!` and `flipperzero_sys::halt!` macros
- `flipperzero_sys::furi::UnsafeRecord::open` now takes a `&'static CStr`

### Removed
Expand Down
105 changes: 94 additions & 11 deletions crates/sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ mod bindings;

/// Crash the system.
///
/// The only argument is a message with which the system should crash
/// which should contain no NULs. The following will not compile:
/// May be provided with an optional message which should not contain NULs.
/// The following will not compile:
///
/// ```compile_fail
/// flipperzero_sys::crash!("Has a \0 NUL");
Expand All @@ -48,26 +48,109 @@ mod bindings;
/// ```
/// flipperzero_sys::crash!("Hello world!");
/// ```
///
/// Crash the system with default *"Fatal Error"* message:
///
/// ```
/// flipperzero_sys::crash!();
/// ```
#[macro_export]
macro_rules! crash {
() => {
$crate::__crash_implementation!(::core::ptr::null());
};
($msg:expr $(,)?) => {{
const MESSAGE: *const ::core::primitive::i8 =
match ::core::ffi::CStr::from_bytes_with_nul(
::core::concat!($msg, "\0").as_bytes(),
) {
Ok(cstr) => cstr.as_ptr(),
Err(error) => panic!("message contains NULs"),
};
let message = const {
match ::core::ffi::CStr::from_bytes_with_nul(::core::concat!($msg, "\0").as_bytes()) {
Err(_) => c"nul in crash message",
Ok(m) => m,
}
};

$crate::__crash_implementation!(message.as_ptr());
}};
}

/// Crash the system.
///
/// This is an internal implementation detail.
#[doc(hidden)]
#[macro_export]
macro_rules! __crash_implementation {
($ptr:expr) => {
unsafe {
// Crash message is passed via r12
::core::arch::asm!("", in("r12") MESSAGE, options(nomem, nostack));
::core::arch::asm!(
"ldr pc,=__furi_crash_implementation",
in("r12") ($ptr),
options(nomem, nostack),
);

$crate::__furi_crash_implementation();
::core::hint::unreachable_unchecked();
}
};
}

/// Halt the system.
///
/// May be provided with an optional message which should not contain NULs.
/// The following will not compile:
///
/// ```compile_fail
/// flipperzero_sys::halt!("Has a \0 NUL");
/// ```
///
/// # Examples
///
/// Halt the system with a *"Hello world!"* message:
///
/// ```
/// flipperzero_sys::crash!("Hello world!");
/// ```
///
/// Halt the system with default *"System halt requested."* message:
///
/// ```
/// flipperzero_sys::crash!();
/// ```
#[macro_export]
macro_rules! halt {
() => {
$crate::__halt_implementation!(::core::ptr::null());
};
($msg:expr $(,)?) => {{
// Optional message
let message = const {
match ::core::ffi::CStr::from_bytes_with_nul(::core::concat!($msg, "\0").as_bytes()) {
Err(_) => c"nul in halt message",
Ok(m) => m,
}
};

$crate::__halt_implementation!(message.as_ptr());
}};
}

/// Halt the system.
///
/// This is an internal implementation detail.
#[doc(hidden)]
#[macro_export]
macro_rules! __halt_implementation {
($ptr:expr) => {
unsafe {
// Halt message is passed via r12
::core::arch::asm!(
"ldr pc,=__furi_halt_implementation",
in("r12") ($ptr),
options(nomem, nostack))
;

::core::hint::unreachable_unchecked();
}
};
}

// Re-export bindings
pub use bindings::*;

Expand Down

0 comments on commit f9c3215

Please sign in to comment.