From 65aa87b4c0beed251ea2bbb03cfb666fcc5ce639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 22 May 2026 10:26:14 +0200 Subject: [PATCH 1/5] Prevent ESP32 SHA powering down mid-operation --- esp-hal/src/sha.rs | 21 ++++++++++++++------- hil-test/src/bin/crypto/sha.rs | 3 +++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index 2b517f9125d..3e8e6c1c06a 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -1105,6 +1105,15 @@ impl<'t, 'd> ShaWorkQueueDriver<'t, 'd> { } } +// ESP32 can't save (or rather, restore) the hash context, so we need to fall back to software +// if a context already uses the hardware. Also we must not power down the hardware when a +// context uses it, as it corrupts state. +#[cfg(esp32)] +enum Esp32Hasher { + Hardware(GenericPeripheralGuard<{ crate::system::Peripheral::Sha as u8 }>), + Software(SoftwareHasher), +} + #[cfg(esp32)] enum SoftwareHasher { Sha1(sha1::Sha1), @@ -1122,10 +1131,8 @@ struct ShaContext { #[cfg(not(esp32))] // Saved H_MEM registers state: [u32; 16], - // ESP32 can't save (or rather, restore) the hash context, so we need to fall back to software - // if a context already uses the hardware. #[cfg(esp32)] - use_software: Option, + use_software: Esp32Hasher, } // ESP32 can't save the context, so it can't support interleaved operation. To support the digest @@ -1150,9 +1157,9 @@ impl ShaContext SoftwareHasher::Sha384(sha2::Sha384::new()), ShaAlgorithmKind::Sha512 => SoftwareHasher::Sha512(sha2::Sha512::new()), }; - Some(hasher) + Esp32Hasher::Software(hasher) } else { - None + Esp32Hasher::Hardware(GenericPeripheralGuard::new()) }; Self { @@ -1181,7 +1188,7 @@ impl ShaContext ShaContext Date: Fri, 22 May 2026 10:46:58 +0200 Subject: [PATCH 2/5] Only clear HW accelerator flag if the hardware-using context is dropped --- esp-hal/src/sha.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index 3e8e6c1c06a..3a8463ef9aa 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -1297,7 +1297,9 @@ impl Drop for ShaContext { fn drop(&mut self) { - ACCELERATOR_IN_USE.store(false, Ordering::Release); + if matches!(self.use_software, Esp32Hasher::Hardware(_)) { + ACCELERATOR_IN_USE.store(false, Ordering::Release); + } } } From c7a4f593f73fda54d5a7100e886f496347b40863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 22 May 2026 10:47:41 +0200 Subject: [PATCH 3/5] Rename field --- esp-hal/src/sha.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index 3a8463ef9aa..70a51310253 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -1132,7 +1132,7 @@ struct ShaContext { state: [u32; 16], #[cfg(esp32)] - use_software: Esp32Hasher, + hasher: Esp32Hasher, } // ESP32 can't save the context, so it can't support interleaved operation. To support the digest @@ -1150,7 +1150,7 @@ static ACCELERATOR_IN_USE: AtomicBool = AtomicBool::new(false); impl ShaContext { fn new(algorithm: ShaAlgorithmKind) -> Self { #[cfg(esp32)] - let use_software = if ACCELERATOR_IN_USE.swap(true, Ordering::SeqCst) { + let hasher = if ACCELERATOR_IN_USE.swap(true, Ordering::SeqCst) { let hasher = match algorithm { ShaAlgorithmKind::Sha1 => SoftwareHasher::Sha1(sha1::Sha1::new()), ShaAlgorithmKind::Sha256 => SoftwareHasher::Sha256(sha2::Sha256::new()), @@ -1177,7 +1177,7 @@ impl ShaContext ShaContext ShaContext Drop for ShaContext { fn drop(&mut self) { - if matches!(self.use_software, Esp32Hasher::Hardware(_)) { + if matches!(self.hasher, Esp32Hasher::Hardware(_)) { ACCELERATOR_IN_USE.store(false, Ordering::Release); } } From 28c15e271fd4d823b7fc91d619c486af82fc1ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 22 May 2026 12:49:52 +0200 Subject: [PATCH 4/5] Fix RSA on ESP32 --- esp-hal/src/rsa/mod.rs | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/esp-hal/src/rsa/mod.rs b/esp-hal/src/rsa/mod.rs index 7a45ffcab93..8bc6490fa72 100644 --- a/esp-hal/src/rsa/mod.rs +++ b/esp-hal/src/rsa/mod.rs @@ -31,8 +31,8 @@ use crate::{ asynch::AtomicWaker, interrupt::InterruptHandler, pac, - peripherals::{Interrupt, RSA}, - system::{Cpu, GenericPeripheralGuard, Peripheral as PeripheralEnable}, + peripherals::RSA, + system::{GenericPeripheralGuard, Peripheral as PeripheralEnable}, trm_markdown_link, work_queue::{self, Status, VTable, WorkQueue, WorkQueueDriver, WorkQueueFrontend}, }; @@ -41,9 +41,7 @@ use crate::{ pub struct Rsa<'d, Dm: DriverMode> { rsa: RSA<'d>, phantom: PhantomData, - #[cfg(not(rsa_version = "1"))] - _memory_guard: RsaMemoryPowerGuard, - _guard: GenericPeripheralGuard<{ PeripheralEnable::Rsa as u8 }>, + _guard: RsaGuard, } // There are two distinct peripheral versions: ESP32, and all else. There is a naming split in the @@ -56,12 +54,14 @@ pub struct Rsa<'d, Dm: DriverMode> { /// bits, or 16 words. const WORDS_PER_INCREMENT: u32 = property!("rsa.size_increment") / 32; -#[cfg(not(rsa_version = "1"))] -struct RsaMemoryPowerGuard; +struct RsaGuard { + _guard: GenericPeripheralGuard<{ PeripheralEnable::Rsa as u8 }>, +} -#[cfg(not(rsa_version = "1"))] -impl RsaMemoryPowerGuard { +impl RsaGuard { fn new() -> Self { + let _guard = GenericPeripheralGuard::new(); + #[cfg(not(rsa_version = "1"))] crate::peripherals::SYSTEM::regs() .rsa_pd_ctrl() .modify(|_, w| { @@ -69,12 +69,11 @@ impl RsaMemoryPowerGuard { w.rsa_mem_force_pu().set_bit(); w.rsa_mem_pd().clear_bit() }); - Self + Self { _guard } } } -#[cfg(not(rsa_version = "1"))] -impl Drop for RsaMemoryPowerGuard { +impl Drop for RsaGuard { fn drop(&mut self) { unsafe { // Stopping the peripheral's clock source pends an interrupt. Since the clocks @@ -83,6 +82,7 @@ impl Drop for RsaMemoryPowerGuard { // To prevent this, we disable interrupts manually before stopping the peripheral. crate::peripherals::RSA::steal().disable_peri_interrupt_on_all_cores(); } + #[cfg(not(rsa_version = "1"))] crate::peripherals::SYSTEM::regs() .rsa_pd_ctrl() .modify(|_, w| { @@ -98,14 +98,10 @@ impl<'d> Rsa<'d, Blocking> { /// /// Optionally an interrupt handler can be bound. pub fn new(rsa: RSA<'d>) -> Self { - let guard = GenericPeripheralGuard::new(); - let this = Self { rsa, phantom: PhantomData, - #[cfg(not(rsa_version = "1"))] - _memory_guard: RsaMemoryPowerGuard::new(), - _guard: guard, + _guard: RsaGuard::new(), }; while !this.ready() {} @@ -121,8 +117,6 @@ impl<'d> Rsa<'d, Blocking> { Rsa { rsa: self.rsa, phantom: PhantomData, - #[cfg(not(rsa_version = "1"))] - _memory_guard: self._memory_guard, _guard: self._guard, } } @@ -161,12 +155,9 @@ impl<'d> Rsa<'d, Async> { self.internal_enable_disable_interrupt(false); self.rsa.disable_peri_interrupt_on_all_cores(); - crate::interrupt::disable(Cpu::current(), Interrupt::RSA); Rsa { rsa: self.rsa, phantom: PhantomData, - #[cfg(not(rsa_version = "1"))] - _memory_guard: self._memory_guard, _guard: self._guard, } } @@ -836,9 +827,7 @@ impl<'d> RsaBackend<'d> { let driver = Rsa { rsa: unsafe { self.peri.clone_unchecked() }, phantom: PhantomData, - #[cfg(not(rsa_version = "1"))] - _memory_guard: RsaMemoryPowerGuard::new(), - _guard: GenericPeripheralGuard::new(), + _guard: RsaGuard::new(), }; self.state = RsaBackendState::Initializing(driver); work_queue::Poll::Pending(true) From 5b0a365192a08ece5bd0b6757b9553b9c83cf261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 22 May 2026 13:02:21 +0200 Subject: [PATCH 5/5] Allow large enum variant lint --- esp-hal/src/sha.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index 70a51310253..a20321e729a 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -1109,6 +1109,7 @@ impl<'t, 'd> ShaWorkQueueDriver<'t, 'd> { // if a context already uses the hardware. Also we must not power down the hardware when a // context uses it, as it corrupts state. #[cfg(esp32)] +#[expect(clippy::large_enum_variant)] enum Esp32Hasher { Hardware(GenericPeripheralGuard<{ crate::system::Peripheral::Sha as u8 }>), Software(SoftwareHasher),