diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs index 5aaca57c9..5e1158182 100644 --- a/embassy-stm32/src/dma/util.rs +++ b/embassy-stm32/src/dma/util.rs @@ -39,10 +39,10 @@ impl<'d> ChannelAndRequest<'d> { Transfer::new_write(&mut self.channel, self.request, buf, peri_addr, options) } - pub unsafe fn write_raw<'a, W: Word>( + pub unsafe fn write_raw<'a, MW: Word, PW: Word>( &'a mut self, - buf: *const [W], - peri_addr: *mut W, + buf: *const [MW], + peri_addr: *mut PW, options: TransferOptions, ) -> Transfer<'a> { Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options) diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 3c2125498..3951e9d63 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -12,10 +12,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use stm32_metapac::hash::regs::*; -use crate::dma::NoDma; #[cfg(hash_v2)] -use crate::dma::Transfer; +use crate::dma::ChannelAndRequest; use crate::interrupt::typelevel::Interrupt; +#[cfg(hash_v2)] +use crate::mode::Async; +use crate::mode::{Blocking, Mode}; use crate::peripherals::HASH; use crate::{interrupt, pac, peripherals, rcc, Peripheral}; @@ -116,24 +118,26 @@ pub struct Context<'c> { type HmacKey<'k> = Option<&'k [u8]>; /// HASH driver. -pub struct Hash<'d, T: Instance, D = NoDma> { +pub struct Hash<'d, T: Instance, M: Mode> { _peripheral: PeripheralRef<'d, T>, - #[allow(dead_code)] - dma: PeripheralRef<'d, D>, + _phantom: PhantomData, + #[cfg(hash_v2)] + dma: Option>, } -impl<'d, T: Instance, D> Hash<'d, T, D> { +impl<'d, T: Instance> Hash<'d, T, Blocking> { /// Instantiates, resets, and enables the HASH peripheral. - pub fn new( + pub fn new_blocking( peripheral: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peripheral, dma); + into_ref!(peripheral); let instance = Self { _peripheral: peripheral, - dma: dma, + _phantom: PhantomData, + #[cfg(hash_v2)] + dma: None, }; T::Interrupt::unpend(); @@ -141,7 +145,9 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { instance } +} +impl<'d, T: Instance, M: Mode> Hash<'d, T, M> { /// Starts computation of a new hash and returns the saved peripheral state. pub fn start<'c>(&mut self, algorithm: Algorithm, format: DataType, key: HmacKey<'c>) -> Context<'c> { // Define a context for this new computation. @@ -282,14 +288,136 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { self.store_context(ctx); } + /// Computes a digest for the given context. + /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. + /// The largest returned digest size is 128 bytes for SHA-512. + /// Panics if the supplied digest buffer is too short. + pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { + // Restore the peripheral state. + self.load_context(&ctx); + + // Hash the leftover bytes, if any. + self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]); + ctx.buflen = 0; + + //Start the digest calculation. + T::regs().str().write(|w| w.set_dcal(true)); + + // Load the HMAC key if provided. + if let Some(key) = ctx.key { + while !T::regs().sr().read().dinis() {} + self.accumulate_blocking(key); + T::regs().str().write(|w| w.set_dcal(true)); + } + + // Block until digest computation is complete. + while !T::regs().sr().read().dcis() {} + + // Return the digest. + let digest_words = match ctx.algo { + Algorithm::SHA1 => 5, + #[cfg(any(hash_v1, hash_v2, hash_v4))] + Algorithm::MD5 => 4, + Algorithm::SHA224 => 7, + Algorithm::SHA256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA384 => 12, + #[cfg(hash_v3)] + Algorithm::SHA512_224 => 7, + #[cfg(hash_v3)] + Algorithm::SHA512_256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA512 => 16, + }; + + let digest_len_bytes = digest_words * 4; + // Panics if the supplied digest buffer is too short. + if digest.len() < digest_len_bytes { + panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); + } + + let mut i = 0; + while i < digest_words { + let word = T::regs().hr(i).read(); + digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); + i += 1; + } + digest_len_bytes + } + + /// Push data into the hash core. + fn accumulate_blocking(&mut self, input: &[u8]) { + // Set the number of valid bits. + let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; + T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); + + let mut i = 0; + while i < input.len() { + let mut word: [u8; 4] = [0; 4]; + let copy_idx = min(i + 4, input.len()); + word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); + T::regs().din().write_value(u32::from_ne_bytes(word)); + i += 4; + } + } + + /// Save the peripheral state to a context. + fn store_context<'c>(&mut self, ctx: &mut Context<'c>) { + // Block waiting for data in ready. + while !T::regs().sr().read().dinis() {} + + // Store peripheral context. + ctx.imr = T::regs().imr().read().0; + ctx.str = T::regs().str().read().0; + ctx.cr = T::regs().cr().read().0; + let mut i = 0; + while i < NUM_CONTEXT_REGS { + ctx.csr[i] = T::regs().csr(i).read(); + i += 1; + } + } + + /// Restore the peripheral state from a context. + fn load_context(&mut self, ctx: &Context) { + // Restore the peripheral state from the context. + T::regs().imr().write_value(Imr { 0: ctx.imr }); + T::regs().str().write_value(Str { 0: ctx.str }); + T::regs().cr().write_value(Cr { 0: ctx.cr }); + T::regs().cr().modify(|w| w.set_init(true)); + let mut i = 0; + while i < NUM_CONTEXT_REGS { + T::regs().csr(i).write_value(ctx.csr[i]); + i += 1; + } + } +} + +#[cfg(hash_v2)] +impl<'d, T: Instance> Hash<'d, T, Async> { + /// Instantiates, resets, and enables the HASH peripheral. + pub fn new( + peripheral: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + rcc::enable_and_reset::(); + into_ref!(peripheral, dma); + let instance = Self { + _peripheral: peripheral, + _phantom: PhantomData, + dma: new_dma!(dma), + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + instance + } + /// Restores the peripheral state using the given context, /// then updates the state with the provided data. /// Peripheral state is saved upon return. - #[cfg(hash_v2)] - pub async fn update<'c>(&mut self, ctx: &mut Context<'c>, input: &[u8]) - where - D: crate::hash::Dma, - { + pub async fn update(&mut self, ctx: &mut Context<'_>, input: &[u8]) { // Restore the peripheral state. self.load_context(&ctx); @@ -353,68 +481,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. /// The largest returned digest size is 128 bytes for SHA-512. /// Panics if the supplied digest buffer is too short. - pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { - // Restore the peripheral state. - self.load_context(&ctx); - - // Hash the leftover bytes, if any. - self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]); - ctx.buflen = 0; - - //Start the digest calculation. - T::regs().str().write(|w| w.set_dcal(true)); - - // Load the HMAC key if provided. - if let Some(key) = ctx.key { - while !T::regs().sr().read().dinis() {} - self.accumulate_blocking(key); - T::regs().str().write(|w| w.set_dcal(true)); - } - - // Block until digest computation is complete. - while !T::regs().sr().read().dcis() {} - - // Return the digest. - let digest_words = match ctx.algo { - Algorithm::SHA1 => 5, - #[cfg(any(hash_v1, hash_v2, hash_v4))] - Algorithm::MD5 => 4, - Algorithm::SHA224 => 7, - Algorithm::SHA256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA384 => 12, - #[cfg(hash_v3)] - Algorithm::SHA512_224 => 7, - #[cfg(hash_v3)] - Algorithm::SHA512_256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA512 => 16, - }; - - let digest_len_bytes = digest_words * 4; - // Panics if the supplied digest buffer is too short. - if digest.len() < digest_len_bytes { - panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); - } - - let mut i = 0; - while i < digest_words { - let word = T::regs().hr(i).read(); - digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); - i += 1; - } - digest_len_bytes - } - - /// Computes a digest for the given context. - /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. - /// The largest returned digest size is 128 bytes for SHA-512. - /// Panics if the supplied digest buffer is too short. - #[cfg(hash_v2)] - pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize - where - D: crate::hash::Dma, - { + pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { // Restore the peripheral state. self.load_context(&ctx); @@ -483,27 +550,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { } /// Push data into the hash core. - fn accumulate_blocking(&mut self, input: &[u8]) { - // Set the number of valid bits. - let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; - T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); - - let mut i = 0; - while i < input.len() { - let mut word: [u8; 4] = [0; 4]; - let copy_idx = min(i + 4, input.len()); - word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); - T::regs().din().write_value(u32::from_ne_bytes(word)); - i += 4; - } - } - - /// Push data into the hash core. - #[cfg(hash_v2)] - async fn accumulate(&mut self, input: &[u8]) - where - D: crate::hash::Dma, - { + async fn accumulate(&mut self, input: &[u8]) { // Ignore an input length of 0. if input.len() == 0 { return; @@ -514,57 +561,20 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); // Configure DMA to transfer input to hash core. - let dma_request = self.dma.request(); let dst_ptr: *mut u32 = T::regs().din().as_ptr(); let mut num_words = input.len() / 4; if input.len() % 4 > 0 { num_words += 1; } let src_ptr: *const [u8] = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); - let dma_transfer = unsafe { - Transfer::new_write_raw( - &mut self.dma, - dma_request, - src_ptr, - dst_ptr as *mut u32, - Default::default(), - ) - }; + + let dma = self.dma.as_mut().unwrap(); + let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr as *mut u32, Default::default()) }; T::regs().cr().modify(|w| w.set_dmae(true)); // Wait for the transfer to complete. dma_transfer.await; } - - /// Save the peripheral state to a context. - fn store_context<'c>(&mut self, ctx: &mut Context<'c>) { - // Block waiting for data in ready. - while !T::regs().sr().read().dinis() {} - - // Store peripheral context. - ctx.imr = T::regs().imr().read().0; - ctx.str = T::regs().str().read().0; - ctx.cr = T::regs().cr().read().0; - let mut i = 0; - while i < NUM_CONTEXT_REGS { - ctx.csr[i] = T::regs().csr(i).read(); - i += 1; - } - } - - /// Restore the peripheral state from a context. - fn load_context(&mut self, ctx: &Context) { - // Restore the peripheral state from the context. - T::regs().imr().write_value(Imr { 0: ctx.imr }); - T::regs().str().write_value(Str { 0: ctx.str }); - T::regs().cr().write_value(Cr { 0: ctx.cr }); - T::regs().cr().modify(|w| w.set_init(true)); - let mut i = 0; - while i < NUM_CONTEXT_REGS { - T::regs().csr(i).write_value(ctx.csr[i]); - i += 1; - } - } } trait SealedInstance { diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 44dda6a9e..a43da1b5a 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -839,7 +839,7 @@ impl<'d> Spi<'d, Async> { let rx_src = self.info.regs.rx_ptr(); let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; - let tx_dst = self.info.regs.tx_ptr(); + let tx_dst: *mut W = self.info.regs.tx_ptr(); let tx_f = unsafe { self.tx_dma .as_mut() diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index bdb3c9a69..52b84a499 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -6,7 +6,6 @@ mod common; use common::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::hash::*; use embassy_stm32::{bind_interrupts, hash, peripherals}; use hmac::{Hmac, Mac}; @@ -36,7 +35,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let p: embassy_stm32::Peripherals = init(); - let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs); + let mut hw_hasher = Hash::new_blocking(p.HASH, Irqs); let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr";