stm32/dma: fix packing/unpacking not working.

This commit is contained in:
Dario Nieuwenhuis 2025-06-30 00:18:44 +02:00
parent 00b2567fbf
commit 84cc949df6
7 changed files with 57 additions and 45 deletions

View File

@ -2,7 +2,6 @@
#[cfg(any(cryp_v2, cryp_v3, cryp_v4))] #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
use core::cmp::min; use core::cmp::min;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::ptr;
use embassy_hal_internal::{Peri, PeripheralType}; use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
@ -1814,14 +1813,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
assert_eq!(blocks.len() % block_size, 0); assert_eq!(blocks.len() % block_size, 0);
// Configure DMA to transfer input to crypto core. // Configure DMA to transfer input to crypto core.
let dst_ptr: *mut u32 = T::regs().din().as_ptr(); let dst_ptr: *mut u32 = T::regs().din().as_ptr();
let num_words = blocks.len() / 4;
let src_ptr: *const [u8] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words);
let options = TransferOptions { let options = TransferOptions {
#[cfg(not(gpdma))] #[cfg(not(gpdma))]
priority: crate::dma::Priority::High, priority: crate::dma::Priority::High,
..Default::default() ..Default::default()
}; };
let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) }; let dma_transfer = unsafe { dma.write_raw(blocks, dst_ptr, options) };
T::regs().dmacr().modify(|w| w.set_dien(true)); T::regs().dmacr().modify(|w| w.set_dien(true));
// Wait for the transfer to complete. // Wait for the transfer to complete.
dma_transfer.await; dma_transfer.await;
@ -1836,14 +1833,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
assert_eq!((blocks.len() * 4) % block_size, 0); assert_eq!((blocks.len() * 4) % block_size, 0);
// Configure DMA to transfer input to crypto core. // Configure DMA to transfer input to crypto core.
let dst_ptr: *mut u32 = T::regs().din().as_ptr(); let dst_ptr: *mut u32 = T::regs().din().as_ptr();
let num_words = blocks.len();
let src_ptr: *const [u32] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words);
let options = TransferOptions { let options = TransferOptions {
#[cfg(not(gpdma))] #[cfg(not(gpdma))]
priority: crate::dma::Priority::High, priority: crate::dma::Priority::High,
..Default::default() ..Default::default()
}; };
let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) }; let dma_transfer = unsafe { dma.write_raw(blocks, dst_ptr, options) };
T::regs().dmacr().modify(|w| w.set_dien(true)); T::regs().dmacr().modify(|w| w.set_dien(true));
// Wait for the transfer to complete. // Wait for the transfer to complete.
dma_transfer.await; dma_transfer.await;
@ -1857,14 +1852,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
assert_eq!(blocks.len() % block_size, 0); assert_eq!(blocks.len() % block_size, 0);
// Configure DMA to get output from crypto core. // Configure DMA to get output from crypto core.
let src_ptr = T::regs().dout().as_ptr(); let src_ptr = T::regs().dout().as_ptr();
let num_words = blocks.len() / 4;
let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words);
let options = TransferOptions { let options = TransferOptions {
#[cfg(not(gpdma))] #[cfg(not(gpdma))]
priority: crate::dma::Priority::VeryHigh, priority: crate::dma::Priority::VeryHigh,
..Default::default() ..Default::default()
}; };
let dma_transfer = unsafe { dma.read_raw(src_ptr, dst_ptr, options) }; let dma_transfer = unsafe { dma.read_raw(src_ptr, blocks, options) };
T::regs().dmacr().modify(|w| w.set_doen(true)); T::regs().dmacr().modify(|w| w.set_doen(true));
// Wait for the transfer to complete. // Wait for the transfer to complete.
dma_transfer.await; dma_transfer.await;

View File

@ -341,7 +341,7 @@ impl AnyChannel {
mem_len: usize, mem_len: usize,
incr_mem: bool, incr_mem: bool,
mem_size: WordSize, mem_size: WordSize,
peripheral_size: WordSize, peri_size: WordSize,
options: TransferOptions, options: TransferOptions,
) { ) {
// "Preceding reads and writes cannot be moved past subsequent writes." // "Preceding reads and writes cannot be moved past subsequent writes."
@ -357,8 +357,6 @@ impl AnyChannel {
#[cfg(dmamux)] #[cfg(dmamux)]
super::dmamux::configure_dmamux(&info.dmamux, _request); super::dmamux::configure_dmamux(&info.dmamux, _request);
assert!(mem_len > 0 && mem_len <= 0xFFFF);
match self.info().dma { match self.info().dma {
#[cfg(dma)] #[cfg(dma)]
DmaInfo::Dma(r) => { DmaInfo::Dma(r) => {
@ -368,14 +366,39 @@ impl AnyChannel {
state.complete_count.store(0, Ordering::Release); state.complete_count.store(0, Ordering::Release);
self.clear_irqs(); self.clear_irqs();
// NDTR is the number of transfers in the *peripheral* word size.
// ex: if mem_size=1, peri_size=4 and ndtr=3 it'll do 12 mem transfers, 3 peri transfers.
let ndtr = match (mem_size, peri_size) {
(WordSize::FourBytes, WordSize::OneByte) => mem_len * 4,
(WordSize::FourBytes, WordSize::TwoBytes) | (WordSize::TwoBytes, WordSize::OneByte) => mem_len * 2,
(WordSize::FourBytes, WordSize::FourBytes)
| (WordSize::TwoBytes, WordSize::TwoBytes)
| (WordSize::OneByte, WordSize::OneByte) => mem_len,
(WordSize::TwoBytes, WordSize::FourBytes) | (WordSize::OneByte, WordSize::TwoBytes) => {
assert!(mem_len % 2 == 0);
mem_len / 2
}
(WordSize::OneByte, WordSize::FourBytes) => {
assert!(mem_len % 4 == 0);
mem_len / 4
}
};
assert!(ndtr > 0 && ndtr <= 0xFFFF);
ch.par().write_value(peri_addr as u32); ch.par().write_value(peri_addr as u32);
ch.m0ar().write_value(mem_addr as u32); ch.m0ar().write_value(mem_addr as u32);
ch.ndtr().write_value(pac::dma::regs::Ndtr(mem_len as _)); ch.ndtr().write_value(pac::dma::regs::Ndtr(ndtr as _));
ch.fcr().write(|w| { ch.fcr().write(|w| {
if let Some(fth) = options.fifo_threshold { if let Some(fth) = options.fifo_threshold {
// FIFO mode // FIFO mode
w.set_dmdis(pac::dma::vals::Dmdis::DISABLED); w.set_dmdis(pac::dma::vals::Dmdis::DISABLED);
w.set_fth(fth.into()); w.set_fth(fth.into());
} else if mem_size != peri_size {
// force FIFO mode if msize != psize
// packing/unpacking doesn't work in direct mode.
w.set_dmdis(pac::dma::vals::Dmdis::DISABLED);
w.set_fth(FifoThreshold::Half.into());
} else { } else {
// Direct mode // Direct mode
w.set_dmdis(pac::dma::vals::Dmdis::ENABLED); w.set_dmdis(pac::dma::vals::Dmdis::ENABLED);
@ -384,7 +407,7 @@ impl AnyChannel {
ch.cr().write(|w| { ch.cr().write(|w| {
w.set_dir(dir.into()); w.set_dir(dir.into());
w.set_msize(mem_size.into()); w.set_msize(mem_size.into());
w.set_psize(peripheral_size.into()); w.set_psize(peri_size.into());
w.set_pl(options.priority.into()); w.set_pl(options.priority.into());
w.set_minc(incr_mem); w.set_minc(incr_mem);
w.set_pinc(false); w.set_pinc(false);
@ -404,6 +427,8 @@ impl AnyChannel {
} }
#[cfg(bdma)] #[cfg(bdma)]
DmaInfo::Bdma(r) => { DmaInfo::Bdma(r) => {
assert!(mem_len > 0 && mem_len <= 0xFFFF);
#[cfg(bdma_v2)] #[cfg(bdma_v2)]
critical_section::with(|_| r.cselr().modify(|w| w.set_cs(info.num, _request))); critical_section::with(|_| r.cselr().modify(|w| w.set_cs(info.num, _request)));
@ -417,7 +442,7 @@ impl AnyChannel {
ch.mar().write_value(mem_addr as u32); ch.mar().write_value(mem_addr as u32);
ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); ch.ndtr().write(|w| w.set_ndt(mem_len as u16));
ch.cr().write(|w| { ch.cr().write(|w| {
w.set_psize(peripheral_size.into()); w.set_psize(peri_size.into());
w.set_msize(mem_size.into()); w.set_msize(mem_size.into());
w.set_minc(incr_mem); w.set_minc(incr_mem);
w.set_dir(dir.into()); w.set_dir(dir.into());
@ -587,11 +612,11 @@ impl<'a> Transfer<'a> {
} }
/// Create a new read DMA transfer (peripheral to memory), using raw pointers. /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
pub unsafe fn new_read_raw<W: Word>( pub unsafe fn new_read_raw<MW: Word, PW: Word>(
channel: Peri<'a, impl Channel>, channel: Peri<'a, impl Channel>,
request: Request, request: Request,
peri_addr: *mut W, peri_addr: *mut PW,
buf: *mut [W], buf: *mut [MW],
options: TransferOptions, options: TransferOptions,
) -> Self { ) -> Self {
Self::new_inner( Self::new_inner(
@ -599,11 +624,11 @@ impl<'a> Transfer<'a> {
request, request,
Dir::PeripheralToMemory, Dir::PeripheralToMemory,
peri_addr as *const u32, peri_addr as *const u32,
buf as *mut W as *mut u32, buf as *mut MW as *mut u32,
buf.len(), buf.len(),
true, true,
W::size(), MW::size(),
W::size(), PW::size(),
options, options,
) )
} }
@ -672,22 +697,14 @@ impl<'a> Transfer<'a> {
mem_addr: *mut u32, mem_addr: *mut u32,
mem_len: usize, mem_len: usize,
incr_mem: bool, incr_mem: bool,
data_size: WordSize, mem_size: WordSize,
peripheral_size: WordSize, peri_size: WordSize,
options: TransferOptions, options: TransferOptions,
) -> Self { ) -> Self {
assert!(mem_len > 0 && mem_len <= 0xFFFF); assert!(mem_len > 0 && mem_len <= 0xFFFF);
channel.configure( channel.configure(
_request, _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options,
dir,
peri_addr,
mem_addr,
mem_len,
incr_mem,
data_size,
peripheral_size,
options,
); );
channel.start(); channel.start();
Self { channel } Self { channel }

View File

@ -125,11 +125,11 @@ impl<'a> Transfer<'a> {
} }
/// Create a new read DMA transfer (peripheral to memory), using raw pointers. /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
pub unsafe fn new_read_raw<W: Word>( pub unsafe fn new_read_raw<MW: Word, PW: Word>(
channel: Peri<'a, impl Channel>, channel: Peri<'a, impl Channel>,
request: Request, request: Request,
peri_addr: *mut W, peri_addr: *mut PW,
buf: *mut [W], buf: *mut [MW],
options: TransferOptions, options: TransferOptions,
) -> Self { ) -> Self {
Self::new_inner( Self::new_inner(
@ -137,11 +137,11 @@ impl<'a> Transfer<'a> {
request, request,
Dir::PeripheralToMemory, Dir::PeripheralToMemory,
peri_addr as *const u32, peri_addr as *const u32,
buf as *mut W as *mut u32, buf as *mut MW as *mut u32,
buf.len(), buf.len(),
true, true,
W::size(), PW::size(),
W::size(), MW::size(),
options, options,
) )
} }

View File

@ -20,10 +20,10 @@ impl<'d> ChannelAndRequest<'d> {
Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options) Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options)
} }
pub unsafe fn read_raw<'a, W: Word>( pub unsafe fn read_raw<'a, MW: Word, PW: Word>(
&'a mut self, &'a mut self,
peri_addr: *mut W, peri_addr: *mut PW,
buf: *mut [W], buf: *mut [MW],
options: TransferOptions, options: TransferOptions,
) -> Transfer<'a> { ) -> Transfer<'a> {
Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options)

View File

@ -843,7 +843,7 @@ impl<'d> Spi<'d, Async> {
set_rxdmaen(self.info.regs, true); set_rxdmaen(self.info.regs, true);
let rx_src = self.info.regs.rx_ptr(); let rx_src = self.info.regs.rx_ptr::<W>();
let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) };
let tx_dst: *mut W = self.info.regs.tx_ptr(); let tx_dst: *mut W = self.info.regs.tx_ptr();

View File

@ -68,7 +68,9 @@ async fn main(_spawner: Spawner) -> ! {
); );
// Decrypt in software using AES-GCM 128-bit // Decrypt in software using AES-GCM 128-bit
let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec); cipher
.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec)
.unwrap();
let sw_end_time = Instant::now(); let sw_end_time = Instant::now();
let sw_execution_time = sw_end_time - sw_start_time; let sw_execution_time = sw_end_time - sw_start_time;

View File

@ -72,7 +72,7 @@ async fn main(_spawner: Spawner) {
defmt::assert!(encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]); defmt::assert!(encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]);
// Decrypt in software using AES-GCM 128-bit // Decrypt in software using AES-GCM 128-bit
let _ = cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec); cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec).unwrap();
info!("Test OK"); info!("Test OK");
cortex_m::asm::bkpt(); cortex_m::asm::bkpt();