From ee21e7d66a2975aa358f9a69185defa9fa5e4e85 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio <jorge@japaric.io> Date: Thu, 11 Jan 2018 15:26:18 +0100 Subject: [PATCH] make `Stim::write_*` methods take `&mut self` instead of `&self` this prevents people from overlapping non-atomic write operations on the same stimulus port when working with generators (cooperative tasks). For example, with this change the following code won't compile ``` rust let stim = &mut ITM.stim[0]; let a = || { loop { // .. for byte in b"Hello, world!".iter() { while !stim.is_fifo_ready() { yield } stim.write_u8(*byte); } // .. } }; let b = || { loop { // .. for byte in b"The quick brown fox jumps over the lazy dog".iter() { while !stim.is_fifo_ready() { yield } stim.write_u8(*byte); } // .. } }; ``` A possible fix for the above code is to use different stimulus ports in each task (generator). --- src/itm.rs | 12 ++++++------ src/peripheral/itm.rs | 6 +++--- src/peripheral/mod.rs | 12 +++++++++--- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/itm.rs b/src/itm.rs index 5a2722d..02ada53 100644 --- a/src/itm.rs +++ b/src/itm.rs @@ -7,7 +7,7 @@ use aligned::Aligned; use peripheral::itm::Stim; // NOTE assumes that `bytes` is 32-bit aligned -unsafe fn write_words(stim: &Stim, bytes: &[u32]) { +unsafe fn write_words(stim: &mut Stim, bytes: &[u32]) { let mut p = bytes.as_ptr(); for _ in 0..bytes.len() { while !stim.is_fifo_ready() {} @@ -16,7 +16,7 @@ unsafe fn write_words(stim: &Stim, bytes: &[u32]) { } } -struct Port<'p>(&'p Stim); +struct Port<'p>(&'p mut Stim); impl<'p> fmt::Write for Port<'p> { fn write_str(&mut self, s: &str) -> fmt::Result { @@ -26,7 +26,7 @@ impl<'p> fmt::Write for Port<'p> { } /// Writes a `buffer` to the ITM `port` -pub fn write_all(port: &Stim, buffer: &[u8]) { +pub fn write_all(port: &mut Stim, buffer: &[u8]) { unsafe { let mut len = buffer.len(); let mut ptr = buffer.as_ptr(); @@ -84,7 +84,7 @@ pub fn write_all(port: &Stim, buffer: &[u8]) { /// // Or equivalently /// itm::write_aligned(&itm.stim[0], &Aligned(*b"Hello, world!\n")); /// ``` -pub fn write_aligned(port: &Stim, buffer: &Aligned<u32, [u8]>) { +pub fn write_aligned(port: &mut Stim, buffer: &Aligned<u32, [u8]>) { unsafe { let len = buffer.len(); @@ -120,13 +120,13 @@ pub fn write_aligned(port: &Stim, buffer: &Aligned<u32, [u8]>) { } /// Writes `fmt::Arguments` to the ITM `port` -pub fn write_fmt(port: &Stim, args: fmt::Arguments) { +pub fn write_fmt(port: &mut Stim, args: fmt::Arguments) { use core::fmt::Write; Port(port).write_fmt(args).ok(); } /// Writes a string to the ITM `port` -pub fn write_str(port: &Stim, string: &str) { +pub fn write_str(port: &mut Stim, string: &str) { write_all(port, string.as_bytes()) } diff --git a/src/peripheral/itm.rs b/src/peripheral/itm.rs index 17cf869..fd4a2fd 100644 --- a/src/peripheral/itm.rs +++ b/src/peripheral/itm.rs @@ -33,17 +33,17 @@ pub struct Stim { impl Stim { /// Writes an `u8` payload into the stimulus port - pub fn write_u8(&self, value: u8) { + pub fn write_u8(&mut self, value: u8) { unsafe { ptr::write_volatile(self.register.get() as *mut u8, value) } } /// Writes an `u16` payload into the stimulus port - pub fn write_u16(&self, value: u16) { + pub fn write_u16(&mut self, value: u16) { unsafe { ptr::write_volatile(self.register.get() as *mut u16, value) } } /// Writes an `u32` payload into the stimulus port - pub fn write_u32(&self, value: u32) { + pub fn write_u32(&mut self, value: u32) { unsafe { ptr::write_volatile(self.register.get(), value) } } diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index d462bdb..bd658a4 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -9,7 +9,7 @@ #![allow(private_no_mangle_statics)] use core::marker::PhantomData; -use core::ops::Deref; +use core::ops::{Deref, DerefMut}; use interrupt; @@ -262,8 +262,8 @@ pub struct ITM { impl ITM { /// Returns a pointer to the register block - pub fn ptr() -> *const itm::RegisterBlock { - 0xE000_0000 as *const _ + pub fn ptr() -> *mut itm::RegisterBlock { + 0xE000_0000 as *mut _ } } @@ -275,6 +275,12 @@ impl Deref for ITM { } } +impl DerefMut for ITM { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *Self::ptr() } + } +} + /// Memory Protection Unit pub struct MPU { _marker: PhantomData<*const ()>, -- GitLab