From 0aa93dc1d6502e633ba7add91daac9c5cf0660f0 Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Sun, 18 Aug 2024 14:01:31 +0200 Subject: [PATCH 1/9] Remove aliasing &mut references --- Cargo.toml | 1 + src/audio.rs | 61 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6cb26e9..fd3e6cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ cortex-m-log = { version = "~0.8", features = ["itm", "semihosting", "log-integr panic-itm = { version = "~0.4.2", optional = true } panic-semihosting = { version = "0.6.0", optional = true } cortex-m-semihosting = { version = "0.5.0", optional = true } +stable_deref_trait = { version = "1.2.0", default-features = false } [features] default = [] diff --git a/src/audio.rs b/src/audio.rs index ac639b5..4a19b34 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -1,16 +1,15 @@ //! Audio module. Handles audio startup and I/O. //! As well as converting between the S24 input and f32 for processing. +use core::ops::{Deref, DerefMut}; + use log::info; use stm32h7xx_hal::{ dma, gpio::{gpioe, Analog}, - pac, rcc, - rcc::rec, - sai, - sai::*, - stm32, - stm32::rcc::d2ccip1r::SAI1SEL_A, + pac::{self}, rcc::{self, rec}, + sai::{self, *}, + stm32::{self, rcc::d2ccip1r::SAI1SEL_A}, traits::i2s::FullDuplex, }; @@ -41,11 +40,37 @@ pub const MAX_TRANSFER_SIZE: usize = BLOCK_SIZE_MAX * 2; pub type AudioBuffer = [(f32, f32); BLOCK_SIZE_MAX]; +/// Raw pointer backed reference to the DMA buffers. It exists to avoid storing multiple aliasing +/// `&mut` references to `TX_BUFFER` and `RX_BUFFER`, which is UB. +/// # Safety +/// References are created whenever the underlying buffer is accessed, but since the access is single +/// threaded and the references are short lived this should be fine. +/// This wrapper is only, and may only be, pointing to memory with a 'static lifetime. +struct DmaBufferRawRef { + ptr: *mut DmaBuffer, +} +impl Deref for DmaBufferRawRef { + type Target = DmaBuffer; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr } + } +} +impl DerefMut for DmaBufferRawRef { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.ptr } + + } +} +unsafe impl stable_deref_trait::StableDeref for DmaBufferRawRef {} +// Required for using the buffer in practice. No more dangerous than sending a `&mut DmaBuffer` +unsafe impl Send for DmaBufferRawRef {} + type DmaInputStream = dma::Transfer< dma::dma::Stream1, stm32::SAI1, dma::PeripheralToMemory, - &'static mut [u32; DMA_BUFFER_SIZE], + DmaBufferRawRef, dma::DBTransfer, >; @@ -53,7 +78,7 @@ type DmaOutputStream = dma::Transfer< dma::dma::Stream0, stm32::SAI1, dma::MemoryToPeripheral, - &'static mut [u32; DMA_BUFFER_SIZE], + DmaBufferRawRef, dma::DBTransfer, >; @@ -138,7 +163,9 @@ impl Audio { let dma1_streams = dma::dma::StreamsTuple::new(dma1_d, dma1_p); // dma1 stream 0 - let tx_buffer: &'static mut [u32; DMA_BUFFER_SIZE] = unsafe { &mut TX_BUFFER }; + let tx_buffer = DmaBufferRawRef { + ptr: unsafe { core::ptr::addr_of_mut!(TX_BUFFER)} + }; let dma_config = dma::dma::DmaConfig::default() .priority(dma::config::Priority::High) .memory_increment(true) @@ -155,7 +182,9 @@ impl Audio { ); // dma1 stream 1 - let rx_buffer: &'static mut [u32; DMA_BUFFER_SIZE] = unsafe { &mut RX_BUFFER }; + let rx_buffer = DmaBufferRawRef { + ptr: unsafe { core::ptr::addr_of_mut!(RX_BUFFER)} + }; let dma_config = dma_config .transfer_complete_interrupt(true) .half_transfer_interrupt(true); @@ -207,8 +236,8 @@ impl Audio { sai.enable(); sai.try_send(0, 0).unwrap(); }); - let input = Input::new(unsafe { &mut RX_BUFFER }); - let output = Output::new(unsafe { &mut TX_BUFFER }); + let input = Input::new(DmaBufferRawRef { ptr: unsafe { core::ptr::addr_of_mut!(RX_BUFFER) }}); + let output = Output::new(DmaBufferRawRef { ptr: unsafe { core::ptr::addr_of_mut!(TX_BUFFER) }}); info!( "{:?}, {:?}", &input.buffer[0] as *const u32, &output.buffer[0] as *const u32 @@ -289,12 +318,12 @@ impl Audio { struct Input { index: usize, - buffer: &'static DmaBuffer, + buffer: DmaBufferRawRef, } impl Input { /// Create a new Input from a DmaBuffer - fn new(buffer: &'static DmaBuffer) -> Self { + fn new(buffer: DmaBufferRawRef) -> Self { Self { index: 0, buffer } } @@ -310,12 +339,12 @@ impl Input { struct Output { index: usize, - buffer: &'static mut DmaBuffer, + buffer: DmaBufferRawRef, } impl Output { /// Create a new Input from a DmaBuffer - fn new(buffer: &'static mut DmaBuffer) -> Self { + fn new(buffer: DmaBufferRawRef) -> Self { Self { index: 0, buffer } } From fe90b9c5dbdb6d5bf42d1211508736c5a853d026 Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Sun, 18 Aug 2024 14:01:59 +0200 Subject: [PATCH 2/9] Fix Cargo.toml section name format --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fd3e6cc..d691bc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ debug = true # symbols are nice and they don't increase the size in flash lto = true # better optimizations opt-level = "s" # optimize for binary size -[dev_dependencies] +[dev-dependencies] embedded-sdmmc = "0.5.0" usbd-midi = { git = "https://github.com/btrepp/usbd-midi/" } num_enum = { version = "0.7.3", default-features = false } From 9e5f05f8dd7ee8c9a26faecf34bf1910b7a37718 Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Thu, 19 Dec 2024 14:39:00 +0100 Subject: [PATCH 3/9] New &raw mut syntax for pointer to static --- src/audio.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/audio.rs b/src/audio.rs index 4a19b34..04f315e 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -164,7 +164,7 @@ impl Audio { // dma1 stream 0 let tx_buffer = DmaBufferRawRef { - ptr: unsafe { core::ptr::addr_of_mut!(TX_BUFFER)} + ptr: &raw mut TX_BUFFER, }; let dma_config = dma::dma::DmaConfig::default() .priority(dma::config::Priority::High) @@ -183,7 +183,7 @@ impl Audio { // dma1 stream 1 let rx_buffer = DmaBufferRawRef { - ptr: unsafe { core::ptr::addr_of_mut!(RX_BUFFER)} + ptr: &raw mut RX_BUFFER, }; let dma_config = dma_config .transfer_complete_interrupt(true) @@ -236,8 +236,12 @@ impl Audio { sai.enable(); sai.try_send(0, 0).unwrap(); }); - let input = Input::new(DmaBufferRawRef { ptr: unsafe { core::ptr::addr_of_mut!(RX_BUFFER) }}); - let output = Output::new(DmaBufferRawRef { ptr: unsafe { core::ptr::addr_of_mut!(TX_BUFFER) }}); + let input = Input::new(DmaBufferRawRef { + ptr: &raw mut RX_BUFFER, + }); + let output = Output::new(DmaBufferRawRef { + ptr: &raw mut TX_BUFFER, + }); info!( "{:?}, {:?}", &input.buffer[0] as *const u32, &output.buffer[0] as *const u32 From bc195ab491c07195e4824945a6b4b42ea41c32be Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Thu, 19 Dec 2024 14:48:11 +0100 Subject: [PATCH 4/9] Document &'static mut and suppress warning UsbBus::new requires a &'static mut so &raw mut cannot be used. Therefore, I wrote a warning not to reference EP_MEMORY again. --- examples/usb_midi.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/usb_midi.rs b/examples/usb_midi.rs index eb8b9b5..1772d7b 100644 --- a/examples/usb_midi.rs +++ b/examples/usb_midi.rs @@ -34,6 +34,8 @@ mod app { midi_device::MidiClass, }; + // Warning: EP_MEMORY may only be used for the UsbBusAllocator. Any + // additional references are UB. static mut EP_MEMORY: [u32; 1024] = [0; 1024]; #[shared] @@ -127,6 +129,7 @@ mod app { &ccdr.clocks, ); + #[allow(static_mut_refs)] let usb_bus = cortex_m::singleton!( : usb_device::class_prelude::UsbBusAllocator> = UsbBus::new(usb, unsafe { &mut EP_MEMORY }) From fda8ba60e0f8c0d0c90d6b4611f66f7991c83e40 Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Thu, 19 Dec 2024 14:49:56 +0100 Subject: [PATCH 5/9] Warning and formatting --- examples/usb_midi.rs | 5 +++-- src/audio.rs | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/usb_midi.rs b/examples/usb_midi.rs index 1772d7b..4edf757 100644 --- a/examples/usb_midi.rs +++ b/examples/usb_midi.rs @@ -70,7 +70,7 @@ mod app { let mut timer2 = device.TIM2.timer( MilliSeconds::from_ticks(200).into_rate(), ccdr.peripheral.TIM2, - &mut ccdr.clocks, + &ccdr.clocks, ); timer2.listen(Event::TimeOut); @@ -139,7 +139,8 @@ mod app { let midi = MidiClass::new(usb_bus, 1, 1).unwrap(); let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x16c0, 0x5e4)) - .strings(&[StringDescriptors::default().product("daisy midi")]).unwrap() + .strings(&[StringDescriptors::default().product("daisy midi")]) + .unwrap() .device_class(USB_CLASS_NONE) .build(); diff --git a/src/audio.rs b/src/audio.rs index 04f315e..9773832 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -7,7 +7,8 @@ use log::info; use stm32h7xx_hal::{ dma, gpio::{gpioe, Analog}, - pac::{self}, rcc::{self, rec}, + pac::{self}, + rcc::{self, rec}, sai::{self, *}, stm32::{self, rcc::d2ccip1r::SAI1SEL_A}, traits::i2s::FullDuplex, @@ -40,10 +41,10 @@ pub const MAX_TRANSFER_SIZE: usize = BLOCK_SIZE_MAX * 2; pub type AudioBuffer = [(f32, f32); BLOCK_SIZE_MAX]; -/// Raw pointer backed reference to the DMA buffers. It exists to avoid storing multiple aliasing -/// `&mut` references to `TX_BUFFER` and `RX_BUFFER`, which is UB. +/// Raw pointer backed reference to the DMA buffers. It exists to avoid storing multiple aliasing +/// `&mut` references to `TX_BUFFER` and `RX_BUFFER`, which is UB. /// # Safety -/// References are created whenever the underlying buffer is accessed, but since the access is single +/// References are created whenever the underlying buffer is accessed, but since the access is single /// threaded and the references are short lived this should be fine. /// This wrapper is only, and may only be, pointing to memory with a 'static lifetime. struct DmaBufferRawRef { @@ -59,7 +60,6 @@ impl Deref for DmaBufferRawRef { impl DerefMut for DmaBufferRawRef { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *self.ptr } - } } unsafe impl stable_deref_trait::StableDeref for DmaBufferRawRef {} From 1011de75c26f81a45a57dac48f09ac5b3c3770f2 Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Thu, 19 Dec 2024 14:51:01 +0100 Subject: [PATCH 6/9] Rename .cargo/config to remove deprecation warning --- .cargo/{config => config.toml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .cargo/{config => config.toml} (100%) diff --git a/.cargo/config b/.cargo/config.toml similarity index 100% rename from .cargo/config rename to .cargo/config.toml From 0bc12339a79f09a1feeb4a37f657b8ff8cb3aa78 Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Thu, 19 Dec 2024 15:00:08 +0100 Subject: [PATCH 7/9] Fix log-semihosting import --- src/logger.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logger.rs b/src/logger.rs index 38d752d..90cf392 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -71,10 +71,10 @@ cfg_if::cfg_if! { use cortex_m_log::printer::semihosting; use cortex_m_log::printer::semihosting::Semihosting; use cortex_m_log::modes::InterruptOk; - use cortex_m_semihosting::hio::HStdout; + use cortex_m_semihosting::hio::HostStream; lazy_static! { - static ref LOGGER: Logger> = Logger { + static ref LOGGER: Logger> = Logger { level: LevelFilter::Info, inner: semihosting::InterruptOk::<_>::stdout().expect("Get Semihosting stdout"), }; From 826761043079a05a66452d18bba5fece7757e378 Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Thu, 19 Dec 2024 15:02:06 +0100 Subject: [PATCH 8/9] rustfmt --- examples/sdmmc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/sdmmc.rs b/examples/sdmmc.rs index 462de33..0a67ea8 100644 --- a/examples/sdmmc.rs +++ b/examples/sdmmc.rs @@ -9,7 +9,7 @@ mod app { use log::info; - use embedded_sdmmc::{VolumeManager, TimeSource, Timestamp, VolumeIdx}; + use embedded_sdmmc::{TimeSource, Timestamp, VolumeIdx, VolumeManager}; use libdaisy::{ gpio, // Includes a panic handler and optional logging facilities From 6dbe6a554eac896df66a8e8de76f4c2bdd2abfea Mon Sep 17 00:00:00 2001 From: Erik Natanael Gustafsson Date: Thu, 23 Jan 2025 18:08:29 +0100 Subject: [PATCH 9/9] MSRV to 1.82.0 --- .github/bors.toml | 6 +++--- .github/workflows/ci.yml | 2 +- README.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/bors.toml b/.github/bors.toml index e63e697..7650ddc 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -2,9 +2,9 @@ block_labels = ["wip"] delete_merged_branches = true status = [ "Rustfmt", - "ci (1.68.2, log-rtt)", - "ci (1.68.2, log-itm)", - "ci (1.68.2, log-semihosting)", + "ci (1.82.0, log-rtt)", + "ci (1.82.0, log-itm)", + "ci (1.82.0, log-semihosting)", "ci (stable, log-rtt)", "ci (stable, log-itm))", "ci (stable, log-semihosting)", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab46398..71c606f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: # All permutations of {rust, mcu} rust: - - 1.70.0 # MSRV + - 1.82.0 # MSRV - stable logger: - log-rtt diff --git a/README.md b/README.md index 8e1783d..eb9d37c 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ cargo objcopy --example passthru --release -- -O binary passthru.bin [cargo-binutils-url]: https://github.com/rust-embedded/cargo-binutils # Minimum supported Rust version -The Minimum Supported Rust Version (MSRV) at the moment is 1.70.0 +The Minimum Supported Rust Version (MSRV) at the moment is 1.82.0 # Demos [Looper](https://github.com/mtthw-meyer/daisy-looper) - Basic one button looper.