Skip to content

Commit 8784790

Browse files
James Munnshannobraun
authored andcommitted
Consistently check slices to prevent odd EasyDMA errors
1 parent ee6d95c commit 8784790

File tree

4 files changed

+41
-22
lines changed

4 files changed

+41
-22
lines changed

nrf52-hal-common/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ pub(crate) fn slice_in_ram(slice: &[u8]) -> bool {
6262
ptr >= target_constants::SRAM_LOWER && (ptr + slice.len()) < target_constants::SRAM_UPPER
6363
}
6464

65+
/// Return an error if slice is not in RAM
66+
pub(crate) fn slice_in_ram_or<T>(slice: &[u8], err: T) -> Result<(), T> {
67+
if slice_in_ram(slice) {
68+
Ok(())
69+
} else {
70+
Err(err)
71+
}
72+
}
73+
74+
6575
/// A handy structure for converting rust slices into ptr and len pairs
6676
/// for use with EasyDMA. Care must be taken to make sure mutability
6777
/// guarantees are respected

nrf52-hal-common/src/spim.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::target::{SPIM1, SPIM2};
2020

2121
use crate::gpio::{Floating, Input, Output, Pin, PushPull};
2222
use crate::target_constants::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
23-
use crate::{slice_in_ram, DmaSlice};
23+
use crate::{slice_in_ram, slice_in_ram_or, DmaSlice};
2424
use embedded_hal::digital::v2::OutputPin;
2525

2626
/// Interface to a SPIM instance
@@ -39,7 +39,7 @@ where
3939

4040
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Error> {
4141
// If the slice isn't in RAM, we can't write back to it at all
42-
ram_slice_check(words)?;
42+
slice_in_ram_or(words, Error::DMABufferNotInDataMemory)?;
4343

4444
words.chunks(EASY_DMA_SIZE).try_for_each(|chunk| {
4545
self.do_spi_dma_transfer(DmaSlice::from_slice(chunk), DmaSlice::from_slice(chunk))
@@ -242,7 +242,7 @@ where
242242
chip_select: &mut Pin<Output<PushPull>>,
243243
buffer: &mut [u8],
244244
) -> Result<(), Error> {
245-
ram_slice_check(buffer)?;
245+
slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?;
246246

247247
chip_select.set_low().unwrap();
248248

@@ -273,8 +273,9 @@ where
273273
tx_buffer: &[u8],
274274
rx_buffer: &mut [u8],
275275
) -> Result<(), Error> {
276-
ram_slice_check(tx_buffer)?;
277-
ram_slice_check(rx_buffer)?;
276+
// NOTE: RAM slice check for `rx_buffer` is not necessary, as a mutable
277+
// slice can only be built from data located in RAM
278+
slice_in_ram_or(tx_buffer, Error::DMABufferNotInDataMemory)?;
278279

279280
let txi = tx_buffer.chunks(EASY_DMA_SIZE);
280281
let rxi = rx_buffer.chunks_mut(EASY_DMA_SIZE);
@@ -310,8 +311,10 @@ where
310311
tx_buffer: &[u8],
311312
rx_buffer: &mut [u8],
312313
) -> Result<(), Error> {
313-
ram_slice_check(tx_buffer)?;
314-
ram_slice_check(rx_buffer)?;
314+
// NOTE: RAM slice check for `rx_buffer` is not necessary, as a mutable
315+
// slice can only be built from data located in RAM
316+
slice_in_ram_or(tx_buffer, Error::DMABufferNotInDataMemory)?;
317+
315318
// For the tx and rx, we want to return Some(chunk)
316319
// as long as there is data to send. We then chain a repeat to
317320
// the end so once all chunks have been exhausted, we will keep
@@ -362,7 +365,7 @@ where
362365
chip_select: &mut Pin<Output<PushPull>>,
363366
tx_buffer: &[u8],
364367
) -> Result<(), Error> {
365-
ram_slice_check(tx_buffer)?;
368+
slice_in_ram_or(tx_buffer, Error::DMABufferNotInDataMemory)?;
366369
self.transfer_split_uneven(chip_select, tx_buffer, &mut [0u8; 0])
367370
}
368371

@@ -396,14 +399,6 @@ pub enum Error {
396399
Receive,
397400
}
398401

399-
fn ram_slice_check(slice: &[u8]) -> Result<(), Error> {
400-
if slice_in_ram(slice) {
401-
Ok(())
402-
} else {
403-
Err(Error::DMABufferNotInDataMemory)
404-
}
405-
}
406-
407402
/// Implemented by all SPIM instances
408403
pub trait Instance: Deref<Target = spim0::RegisterBlock> {}
409404

nrf52-hal-common/src/twim.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ use crate::target::{twim0, P0, TWIM0};
1616
#[cfg(any(feature = "52832", feature = "52840"))]
1717
use crate::target::TWIM1;
1818

19-
use crate::gpio::{Floating, Input, Pin};
20-
21-
use crate::target_constants::EASY_DMA_SIZE;
19+
use crate::{
20+
gpio::{Floating, Input, Pin},
21+
target_constants::EASY_DMA_SIZE,
22+
slice_in_ram_or,
23+
};
2224

2325
pub use twim0::frequency::FREQUENCYW as Frequency;
2426

@@ -89,6 +91,8 @@ where
8991
/// The buffer must have a length of at most 255 bytes on the nRF52832
9092
/// and at most 65535 bytes on the nRF52840.
9193
pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
94+
slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?;
95+
9296
if buffer.len() > EASY_DMA_SIZE {
9397
return Err(Error::TxBufferTooLong);
9498
}
@@ -155,6 +159,9 @@ where
155159
/// The buffer must have a length of at most 255 bytes on the nRF52832
156160
/// and at most 65535 bytes on the nRF52840.
157161
pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
162+
// NOTE: RAM slice check is not necessary, as a mutable slice can only be
163+
// built from data located in RAM
164+
158165
if buffer.len() > EASY_DMA_SIZE {
159166
return Err(Error::RxBufferTooLong);
160167
}
@@ -229,6 +236,10 @@ where
229236
wr_buffer: &[u8],
230237
rd_buffer: &mut [u8],
231238
) -> Result<(), Error> {
239+
// NOTE: RAM slice check for `rd_buffer` is not necessary, as a mutable
240+
// slice can only be built from data located in RAM
241+
slice_in_ram_or(wr_buffer, Error::DMABufferNotInDataMemory)?;
242+
232243
if wr_buffer.len() > EASY_DMA_SIZE {
233244
return Err(Error::TxBufferTooLong);
234245
}
@@ -385,6 +396,7 @@ pub enum Error {
385396
RxBufferTooLong,
386397
Transmit,
387398
Receive,
399+
DMABufferNotInDataMemory,
388400
}
389401

390402
/// Implemented by all TWIM instances

nrf52-hal-common/src/uarte.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::gpio::{Floating, Input, Output, Pin, PushPull};
2323
use crate::prelude::*;
2424
use crate::target_constants::EASY_DMA_SIZE;
2525
use crate::timer::{self, Timer};
26+
use crate::slice_in_ram_or;
2627

2728
// Re-export SVD variants to allow user to directly set values
2829
pub use uarte0::{baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity};
@@ -107,9 +108,7 @@ where
107108
}
108109

109110
// We can only DMA out of RAM
110-
if !crate::slice_in_ram(tx_buffer) {
111-
return Err(Error::BufferNotInRAM);
112-
}
111+
slice_in_ram_or(tx_buffer, Error::BufferNotInRAM)?;
113112

114113
// Conservative compiler fence to prevent optimizations that do not
115114
// take in to account actions by DMA. The fence has been placed here,
@@ -264,6 +263,9 @@ where
264263
return Err(Error::TxBufferTooLong);
265264
}
266265

266+
// NOTE: RAM slice check is not necessary, as a mutable slice can only be
267+
// built from data located in RAM
268+
267269
// Conservative compiler fence to prevent optimizations that do not
268270
// take in to account actions by DMA. The fence has been placed here,
269271
// before any DMA action has started

0 commit comments

Comments
 (0)