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))]
use core::cmp::min;
use core::marker::PhantomData;
use core::ptr;
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
@ -1814,14 +1813,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
assert_eq!(blocks.len() % block_size, 0);
// Configure DMA to transfer input to crypto core.
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 {
#[cfg(not(gpdma))]
priority: crate::dma::Priority::High,
..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));
// Wait for the transfer to complete.
dma_transfer.await;
@ -1836,14 +1833,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
assert_eq!((blocks.len() * 4) % block_size, 0);
// Configure DMA to transfer input to crypto core.
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 {
#[cfg(not(gpdma))]
priority: crate::dma::Priority::High,
..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));
// Wait for the transfer to complete.
dma_transfer.await;
@ -1857,14 +1852,12 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
assert_eq!(blocks.len() % block_size, 0);
// Configure DMA to get output from crypto core.
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 {
#[cfg(not(gpdma))]
priority: crate::dma::Priority::VeryHigh,
..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));
// Wait for the transfer to complete.
dma_transfer.await;

View File

@ -341,7 +341,7 @@ impl AnyChannel {
mem_len: usize,
incr_mem: bool,
mem_size: WordSize,
peripheral_size: WordSize,
peri_size: WordSize,
options: TransferOptions,
) {
// "Preceding reads and writes cannot be moved past subsequent writes."
@ -357,8 +357,6 @@ impl AnyChannel {
#[cfg(dmamux)]
super::dmamux::configure_dmamux(&info.dmamux, _request);
assert!(mem_len > 0 && mem_len <= 0xFFFF);
match self.info().dma {
#[cfg(dma)]
DmaInfo::Dma(r) => {
@ -368,14 +366,39 @@ impl AnyChannel {
state.complete_count.store(0, Ordering::Release);
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.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| {
if let Some(fth) = options.fifo_threshold {
// FIFO mode
w.set_dmdis(pac::dma::vals::Dmdis::DISABLED);
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 {
// Direct mode
w.set_dmdis(pac::dma::vals::Dmdis::ENABLED);
@ -384,7 +407,7 @@ impl AnyChannel {
ch.cr().write(|w| {
w.set_dir(dir.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_minc(incr_mem);
w.set_pinc(false);
@ -404,6 +427,8 @@ impl AnyChannel {
}
#[cfg(bdma)]
DmaInfo::Bdma(r) => {
assert!(mem_len > 0 && mem_len <= 0xFFFF);
#[cfg(bdma_v2)]
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.ndtr().write(|w| w.set_ndt(mem_len as u16));
ch.cr().write(|w| {
w.set_psize(peripheral_size.into());
w.set_psize(peri_size.into());
w.set_msize(mem_size.into());
w.set_minc(incr_mem);
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.
pub unsafe fn new_read_raw<W: Word>(
pub unsafe fn new_read_raw<MW: Word, PW: Word>(
channel: Peri<'a, impl Channel>,
request: Request,
peri_addr: *mut W,
buf: *mut [W],
peri_addr: *mut PW,
buf: *mut [MW],
options: TransferOptions,
) -> Self {
Self::new_inner(
@ -599,11 +624,11 @@ impl<'a> Transfer<'a> {
request,
Dir::PeripheralToMemory,
peri_addr as *const u32,
buf as *mut W as *mut u32,
buf as *mut MW as *mut u32,
buf.len(),
true,
W::size(),
W::size(),
MW::size(),
PW::size(),
options,
)
}
@ -672,22 +697,14 @@ impl<'a> Transfer<'a> {
mem_addr: *mut u32,
mem_len: usize,
incr_mem: bool,
data_size: WordSize,
peripheral_size: WordSize,
mem_size: WordSize,
peri_size: WordSize,
options: TransferOptions,
) -> Self {
assert!(mem_len > 0 && mem_len <= 0xFFFF);
channel.configure(
_request,
dir,
peri_addr,
mem_addr,
mem_len,
incr_mem,
data_size,
peripheral_size,
options,
_request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options,
);
channel.start();
Self { channel }

View File

@ -125,11 +125,11 @@ impl<'a> Transfer<'a> {
}
/// 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>,
request: Request,
peri_addr: *mut W,
buf: *mut [W],
peri_addr: *mut PW,
buf: *mut [MW],
options: TransferOptions,
) -> Self {
Self::new_inner(
@ -137,11 +137,11 @@ impl<'a> Transfer<'a> {
request,
Dir::PeripheralToMemory,
peri_addr as *const u32,
buf as *mut W as *mut u32,
buf as *mut MW as *mut u32,
buf.len(),
true,
W::size(),
W::size(),
PW::size(),
MW::size(),
options,
)
}

View File

@ -20,10 +20,10 @@ impl<'d> ChannelAndRequest<'d> {
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,
peri_addr: *mut W,
buf: *mut [W],
peri_addr: *mut PW,
buf: *mut [MW],
options: TransferOptions,
) -> Transfer<'a> {
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);
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 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
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_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()]);
// 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");
cortex_m::asm::bkpt();