cortexm/
dma_fence.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2026.
4
5//! Cortex-M synchronization implementation for Rust when using DMA.
6
7use kernel::platform::dma_fence::DmaFence;
8
9#[derive(Debug, Copy, Clone)]
10pub struct CortexMDmaFence {
11    _private: (),
12}
13
14/// An implementation of [DmaFence] for ARM Cortex-M systems.
15///
16/// The provided `release` and `acquire` methods use opaque assembly
17/// blocks and the THUMB `DMB` instructions to make prior writes to
18/// shared buffers visible to DMA devices, and DMA writes visible
19/// subsequent memory reads, as specified in the ARM Cortex-M
20/// Programming Guide to Memory Barrier Instructions [1].
21///
22/// [1]: https://developer.arm.com/documentation/dai0321/a/
23impl CortexMDmaFence {
24    /// Construct a new [CortexMDmaFence].
25    ///
26    /// # Safety
27    ///
28    /// Users of this function guarantee that this fence is an appropriate
29    /// implementation of [`DmaFence`] for the platform on which this code is
30    /// running. In practice, this means that users must assert to be running on
31    /// an ARM Cortex-M (ARM-v6m / ARM-v7m) CPU.
32    pub unsafe fn new() -> Self {
33        Self { _private: () }
34    }
35}
36
37#[cfg(all(target_arch = "arm", target_os = "none"))]
38unsafe impl DmaFence for CortexMDmaFence {
39    fn release<T>(self, slice_ptr: *mut [T]) {
40        let slice_start_ptr: *mut T = slice_ptr.cast();
41        unsafe {
42            core::arch::asm!(
43                "
44    // This block is opaque to the compiler; the compiler must assume
45    // that the block could read to the entire buffer from which the
46    // pointer stored in {dma_buffer_ptr_reg} was derived.
47    //
48    // Do not reorder prior memory reads or writes over subsequent
49    // I/O reads or writes.
50    dmb
51                ",
52                dma_buffer_ptr_reg = in(reg) slice_start_ptr,
53            );
54        }
55    }
56
57    fn acquire<T>(self, slice_ptr: *mut [T]) {
58        let slice_start_ptr: *mut T = slice_ptr.cast();
59        unsafe {
60            core::arch::asm!(
61                "
62    // This block is opaque to the compiler; the compiler must assume
63    // that the block could write to the entire buffer from which the
64    // pointer stored in {dma_buffer_ptr_reg} was derived.
65    //
66    // Do not reorder prior I/O reads or writes over subsequent
67    // memory reads or writes.
68    dmb
69                ",
70                dma_buffer_ptr_reg = in(reg) slice_start_ptr,
71            );
72        }
73    }
74}
75
76#[cfg(not(all(target_arch = "arm", target_os = "none")))]
77unsafe impl DmaFence for CortexMDmaFence {
78    fn release<T>(self, _buf: *mut [T]) {
79        // When building for another architecture, such as for tests or CI:
80        unimplemented!("CortexMDmaFence can only be used on cortex-m targets");
81    }
82
83    fn acquire<T>(self, _buf: *mut [T]) {
84        // When building for another architecture, such as for tests or CI:
85        unimplemented!("CortexMDmaFence can only be used on cortex-m targets");
86    }
87}