Revise usage of mutexes

This commit is contained in:
Jakub Hlusička 2026-02-26 20:32:14 +01:00
parent 3b291669ca
commit 6f42bf7a7b
8 changed files with 85 additions and 42 deletions

View file

@ -18,11 +18,11 @@ impl embedded_io::ErrorType for Writer {
impl embedded_io::Write for Writer { impl embedded_io::Write for Writer {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
with_uart_tx(|_, uart| uart.write(buf)) with_uart_tx(|uart| uart.write(buf))
} }
fn flush(&mut self) -> Result<(), Self::Error> { fn flush(&mut self) -> Result<(), Self::Error> {
with_uart_tx(|_, uart| uart.flush()) with_uart_tx(|uart| uart.flush())
} }
} }

View file

@ -3,7 +3,6 @@ use core::{
ffi::{c_char, c_int, c_size_t, c_uchar, c_ulonglong}, ffi::{c_char, c_int, c_size_t, c_uchar, c_ulonglong},
}; };
use critical_section::Mutex;
use embassy_sync::blocking_mutex::{self, raw::CriticalSectionRawMutex}; use embassy_sync::blocking_mutex::{self, raw::CriticalSectionRawMutex};
use hmac::digest::{FixedOutput, KeyInit, Update}; use hmac::digest::{FixedOutput, KeyInit, Update};
use password_hash::Key; use password_hash::Key;
@ -39,7 +38,8 @@ unsafe extern "C" fn __spre_crypto_hash_sha256(
/// This is the encrypted user key currently being used in the key derivation function of spectre. /// This is the encrypted user key currently being used in the key derivation function of spectre.
/// It decrypts using the user's password into the key that would be derived with the original password hashing function. /// It decrypts using the user's password into the key that would be derived with the original password hashing function.
pub static ACTIVE_ENCRYPTED_USER_KEY: Mutex<Cell<Key>> = Mutex::new(Cell::new([0; _])); pub static ACTIVE_ENCRYPTED_USER_KEY: blocking_mutex::Mutex<CriticalSectionRawMutex, Cell<Key>> =
blocking_mutex::Mutex::new(Cell::new([0; _]));
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
#[must_use] #[must_use]
@ -65,7 +65,7 @@ unsafe extern "C" fn __spre_crypto_pwhash_scryptsalsa208sha256_ll(
}; };
let output: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(output, output_len) }; let output: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(output, output_len) };
let mut user_key = critical_section::with(|cs| ACTIVE_ENCRYPTED_USER_KEY.borrow(cs).get()); let mut user_key = ACTIVE_ENCRYPTED_USER_KEY.lock(|user_key| user_key.get());
password_hash::decrypt_with(&mut user_key, &encryption_key); password_hash::decrypt_with(&mut user_key, &encryption_key);
output.copy_from_slice(&user_key); output.copy_from_slice(&user_key);

View file

@ -69,28 +69,29 @@ pub mod usb {
#[cfg(feature = "alt-log")] #[cfg(feature = "alt-log")]
#[macro_use] #[macro_use]
pub mod uart { pub mod uart {
use crate::util::MutexExt;
use super::*; use super::*;
use core::{cell::RefCell, fmt::Write}; use core::{cell::RefCell, fmt::Write};
use critical_section::{CriticalSection, Mutex}; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
use esp_hal::{ use esp_hal::{Blocking, uart::UartTx};
Blocking,
uart::UartTx,
};
use log::{Log, info}; use log::{Log, info};
static ALT_LOGGER_UART: Mutex<RefCell<Option<UartTx<'static, Blocking>>>> = static ALT_LOGGER_UART: Mutex<
Mutex::new(RefCell::new(None)); CriticalSectionRawMutex,
RefCell<Option<UartTx<'static, Blocking>>>,
> = Mutex::new(RefCell::new(None));
pub fn with_uart_tx<R>( pub fn with_uart_tx<R>(f: impl FnOnce(&'_ mut UartTx<'static, Blocking>) -> R) -> R {
f: impl FnOnce(CriticalSection<'_>, &'_ mut UartTx<'static, Blocking>) -> R, // Safety:
) -> R { // * The guard is not held across yield points.
critical_section::with(|cs| { // * **CARE MUST BE TAKEN NOT TO INVOKE THIS FUNCTION FROM AN INTERRUPT HANDLER.**
let mut uart = ALT_LOGGER_UART.borrow(cs).borrow_mut(); let uart = unsafe { ALT_LOGGER_UART.lock_blocking() };
let uart = uart.as_mut().unwrap(); let mut uart = uart.borrow_mut();
let uart = uart.as_mut().unwrap();
(f)(cs, uart) (f)(uart)
})
} }
#[allow(unused)] #[allow(unused)]
@ -106,7 +107,7 @@ pub mod uart {
#[allow(unused)] #[allow(unused)]
fn do_print(args: core::fmt::Arguments<'_>) { fn do_print(args: core::fmt::Arguments<'_>) {
with_uart_tx(|_, uart| { with_uart_tx(|uart| {
uart.write_fmt(format_args!("{}\n", args)).unwrap(); uart.write_fmt(format_args!("{}\n", args)).unwrap();
uart.flush().unwrap(); uart.flush().unwrap();
}) })
@ -123,7 +124,7 @@ pub mod uart {
#[allow(unused)] #[allow(unused)]
fn log(&self, record: &log::Record) { fn log(&self, record: &log::Record) {
with_uart_tx(|cs, uart| { with_uart_tx(|uart| {
with_formatted_log_record(record, |args| uart.write_fmt(args)).unwrap(); with_formatted_log_record(record, |args| uart.write_fmt(args)).unwrap();
uart.flush().unwrap(); uart.flush().unwrap();
}) })
@ -154,9 +155,13 @@ pub mod uart {
} }
pub fn setup_logging(uart_tx: UartTx<'static, Blocking>) { pub fn setup_logging(uart_tx: UartTx<'static, Blocking>) {
critical_section::with(|cs| { {
*ALT_LOGGER_UART.borrow(cs).borrow_mut() = Some(uart_tx); // Safety:
}); // * The guard is not held across yield points.
// * This function is not invoked from an interrupt handler.
let uart = unsafe { ALT_LOGGER_UART.lock_blocking() };
*uart.borrow_mut() = Some(uart_tx);
}
unsafe { unsafe {
log::set_logger_racy(&UartLogger).unwrap(); log::set_logger_racy(&UartLogger).unwrap();

View file

@ -30,6 +30,7 @@ use alloc::vec::Vec;
use embassy_embedded_hal::adapter::BlockingAsync; use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_embedded_hal::flash::partition::Partition; use embassy_embedded_hal::flash::partition::Partition;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_sync::blocking_mutex;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel; use embassy_sync::channel::Channel;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
@ -753,7 +754,7 @@ async fn main_task(peripherals: MainPeripherals) {
window: RefCell::new(None), window: RefCell::new(None),
swapchain: RefCell::new(swapchain_writer), swapchain: RefCell::new(swapchain_writer),
quit_event_loop: Default::default(), quit_event_loop: Default::default(),
events: Arc::new(critical_section::Mutex::new(RefCell::new(VecDeque::new()))), events: Arc::new(blocking_mutex::Mutex::new(RefCell::new(VecDeque::new()))),
}; };
spawner.must_spawn(ui::run_renderer_task(slint_backend, flash_part_acid)); spawner.must_spawn(ui::run_renderer_task(slint_backend, flash_part_acid));
}); });

View file

@ -1276,7 +1276,7 @@ where
// //
// Adafruit would use 11 MHz. // Adafruit would use 11 MHz.
// I had lowered the frequency, so that `DmaBounce` could keep up. // I had lowered the frequency, so that `DmaBounce` could keep up.
.with_frequency(Rate::from_mhz(5)) // From Adafruit .with_frequency(Rate::from_mhz(6)) // From Adafruit
.with_clock_mode(ClockMode { .with_clock_mode(ClockMode {
polarity: Polarity::IdleLow, // From Adafruit polarity: Polarity::IdleLow, // From Adafruit
phase: Phase::ShiftHigh, // From Adafruit phase: Phase::ShiftHigh, // From Adafruit

View file

@ -7,7 +7,7 @@ use core::{
use alloc::{ use alloc::{
boxed::Box, collections::vec_deque::VecDeque, rc::Rc, string::ToString, sync::Arc, vec::Vec, boxed::Box, collections::vec_deque::VecDeque, rc::Rc, string::ToString, sync::Arc, vec::Vec,
}; };
use critical_section::Mutex; use embassy_sync::blocking_mutex::{self, raw::CriticalSectionRawMutex};
use esp_hal::time::Instant; use esp_hal::time::Instant;
use esp_hal_bounce_buffers::SwapchainWriter; use esp_hal_bounce_buffers::SwapchainWriter;
use log::{debug, info}; use log::{debug, info};
@ -29,7 +29,9 @@ pub struct SlintBackend {
pub window: RefCell<Option<Rc<SoftwareWindowAdapter>>>, pub window: RefCell<Option<Rc<SoftwareWindowAdapter>>>,
pub swapchain: RefCell<SwapchainWriter>, pub swapchain: RefCell<SwapchainWriter>,
pub quit_event_loop: Arc<AtomicBool>, pub quit_event_loop: Arc<AtomicBool>,
pub events: Arc<Mutex<RefCell<VecDeque<Box<dyn FnOnce() + Send>>>>>, pub events: Arc<
blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<VecDeque<Box<dyn FnOnce() + Send>>>>,
>,
} }
impl slint::platform::Platform for SlintBackend { impl slint::platform::Platform for SlintBackend {
@ -66,13 +68,9 @@ impl slint::platform::Platform for SlintBackend {
/* loop */ /* loop */
{ {
let drained_events = critical_section::with(|cs| { let drained_events = self
self.events .events
.borrow(cs) .lock(|events| events.borrow_mut().drain(..).collect::<Vec<_>>());
.borrow_mut()
.drain(..)
.collect::<Vec<_>>()
});
for event in drained_events { for event in drained_events {
(event)(); (event)();
@ -146,7 +144,9 @@ impl slint::platform::Platform for SlintBackend {
struct AcidEventLoopProxy { struct AcidEventLoopProxy {
pub quit_event_loop: Arc<AtomicBool>, pub quit_event_loop: Arc<AtomicBool>,
pub events: Arc<Mutex<RefCell<VecDeque<Box<dyn FnOnce() + Send>>>>>, pub events: Arc<
blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<VecDeque<Box<dyn FnOnce() + Send>>>>,
>,
} }
impl EventLoopProxy for AcidEventLoopProxy { impl EventLoopProxy for AcidEventLoopProxy {
@ -159,8 +159,8 @@ impl EventLoopProxy for AcidEventLoopProxy {
&self, &self,
event: Box<dyn FnOnce() + Send>, event: Box<dyn FnOnce() + Send>,
) -> Result<(), EventLoopError> { ) -> Result<(), EventLoopError> {
critical_section::with(|cs| { self.events.lock(|events| {
self.events.borrow(cs).borrow_mut().push_back(event); events.borrow_mut().push_back(event);
}); });
Ok(()) Ok(())
} }

View file

@ -61,8 +61,8 @@ fn spectre_derive_user_key(
encrypted_key: Option<Key>, encrypted_key: Option<Key>,
) -> SpectreUserKey { ) -> SpectreUserKey {
if let Some(encrypted_key) = encrypted_key { if let Some(encrypted_key) = encrypted_key {
critical_section::with(|cs| { ACTIVE_ENCRYPTED_USER_KEY.lock(|user_key| {
ACTIVE_ENCRYPTED_USER_KEY.borrow(cs).set(encrypted_key); user_key.set(encrypted_key);
}); });
} }

View file

@ -1,5 +1,9 @@
use core::fmt::Display; use core::fmt::Display;
use embassy_sync::{
blocking_mutex::raw::RawMutex,
mutex::{Mutex, MutexGuard, TryLockError},
};
use embassy_time::Duration; use embassy_time::Duration;
pub struct FormattedDuration<'a>(&'a Duration); pub struct FormattedDuration<'a>(&'a Duration);
@ -46,3 +50,36 @@ pub const fn get_file_name(path: &str) -> &str {
Err(_) => panic!("Failed to extract the file name from a path."), Err(_) => panic!("Failed to extract the file name from a path."),
} }
} }
pub trait MutexExt<M, T> {
type Guard<'a>
where
M: 'a,
T: 'a,
Self: 'a;
/// Locks the mutex, while entering a critical section only during locking and unlocking.
///
/// # Safety:
/// * The guard must not be kept across async `yield` points.
/// * This must not be called from within interrupt handlers.
/// Otherwise, a deadlock might occur.
unsafe fn lock_blocking(&self) -> Self::Guard<'_>;
}
impl<M: RawMutex, T> MutexExt<M, T> for Mutex<M, T> {
type Guard<'a>
= MutexGuard<'a, M, T>
where
M: 'a,
T: 'a,
Self: 'a;
unsafe fn lock_blocking(&self) -> Self::Guard<'_> {
loop {
if let Ok(guard) = self.try_lock() {
return guard;
}
}
}
}