From f30b298b0e412c5f14859b419cf01d47a5ea1e01 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 12 May 2024 23:31:42 +0200
Subject: [PATCH 1/6] Update stable Rust.

---
 rust-toolchain.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 2f5d17069..57185e217 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,5 +1,5 @@
 [toolchain]
-channel = "1.77"
+channel = "1.78"
 components = [ "rust-src", "rustfmt", "llvm-tools" ]
 targets = [
     "thumbv7em-none-eabi",

From 43d51884e24f937864e292400fc272855aa1c481 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 12 May 2024 23:40:32 +0200
Subject: [PATCH 2/6] hal-internal: fix failing test due to not initializing
 ringbuf.

---
 embassy-hal-internal/src/atomic_ring_buffer.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs
index 34ceac852..40ad9dc7a 100644
--- a/embassy-hal-internal/src/atomic_ring_buffer.rs
+++ b/embassy-hal-internal/src/atomic_ring_buffer.rs
@@ -478,8 +478,12 @@ mod tests {
 
     #[test]
     fn zero_len() {
+        let mut b = [0; 0];
+
         let rb = RingBuffer::new();
         unsafe {
+            rb.init(b.as_mut_ptr(), b.len());
+
             assert_eq!(rb.is_empty(), true);
             assert_eq!(rb.is_full(), true);
 

From 623d3ec3069c20e9e1f19232094068fbf398ee97 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 12 May 2024 23:41:46 +0200
Subject: [PATCH 3/6] stm32/ospi: remove unused trait.

---
 embassy-stm32/src/ospi/mod.rs | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index 398c3298f..c25ac4d24 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -969,17 +969,6 @@ fn finish_dma(regs: Regs) {
     });
 }
 
-trait RegsExt {
-    fn dr_ptr<W>(&self) -> *mut W;
-}
-
-impl RegsExt for Regs {
-    fn dr_ptr<W>(&self) -> *mut W {
-        let dr = self.dr();
-        dr.as_ptr() as *mut W
-    }
-}
-
 pub(crate) trait SealedInstance {
     const REGS: Regs;
 }

From a14319f51e0a99d725c9c96f01fc09282cf35bb6 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 13 May 2024 00:00:36 +0200
Subject: [PATCH 4/6] stm32: allow some unused.

---
 embassy-stm32/src/adc/mod.rs    | 1 +
 embassy-stm32/src/cordic/mod.rs | 1 +
 2 files changed, 2 insertions(+)

diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 8ef68490b..c753d046c 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -52,6 +52,7 @@ trait SealedInstance {
     #[allow(unused)]
     fn regs() -> crate::pac::adc::Adc;
     #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
+    #[allow(unused)]
     fn common_regs() -> crate::pac::adccommon::AdcCommon;
     #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
     fn state() -> &'static State;
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index 9ac10e714..29b11735e 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -47,6 +47,7 @@ trait SealedInstance {
     }
 
     /// Enable global interrupt
+    #[allow(unused)]
     fn enable_irq(&self) {
         Self::regs().csr().modify(|v| v.set_ien(true))
     }

From a8f578751ff3050edbd49cbeb7bbdddf0f3af6a5 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 13 May 2024 00:16:24 +0200
Subject: [PATCH 5/6] tests/riscv32: workaround linking bug, update deps.

https://github.com/rust-embedded/riscv/issues/196
---
 tests/riscv32/Cargo.toml |   4 +-
 tests/riscv32/link.x     | 214 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 216 insertions(+), 2 deletions(-)
 create mode 100644 tests/riscv32/link.x

diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml
index 38fb2deec..94eda3c09 100644
--- a/tests/riscv32/Cargo.toml
+++ b/tests/riscv32/Cargo.toml
@@ -11,8 +11,8 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature
 embassy-time = { version = "0.3.0", path = "../../embassy-time" }
 embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
 
-riscv-rt = "0.11"
-riscv = { version = "0.10", features = ["critical-section-single-hart"] }
+riscv-rt = "0.12.2"
+riscv = { version = "0.11.1", features = ["critical-section-single-hart"] }
 
 
 [profile.dev]
diff --git a/tests/riscv32/link.x b/tests/riscv32/link.x
new file mode 100644
index 000000000..4076b0c68
--- /dev/null
+++ b/tests/riscv32/link.x
@@ -0,0 +1,214 @@
+/* # EMBASSY notes
+  This file is a workaround for https://github.com/rust-embedded/riscv/issues/196
+  Remove when fixed upstream.
+*/
+/* # Developer notes
+
+- Symbols that start with a double underscore (__) are considered "private"
+
+- Symbols that start with a single underscore (_) are considered "semi-public"; they can be
+  overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" {
+  static mut _heap_size }`).
+
+- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a
+  symbol if not dropped if it appears in or near the front of the linker arguments and "it's not
+  needed" by any of the preceding objects (linker arguments)
+
+- `PROVIDE` is used to provide default values that can be overridden by a user linker script
+
+- In this linker script, you may find symbols that look like `${...}` (e.g., `4`).
+  These are wildcards used by the `build.rs` script to adapt to different target particularities.
+  Check `build.rs` for more details about these symbols.
+
+- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and*
+  the LMA of .data are all `4`-byte aligned. These alignments are assumed by the RAM
+  initialization routine. There's also a second benefit: `4`-byte aligned boundaries
+  means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`.
+*/
+
+PROVIDE(_stext = ORIGIN(REGION_TEXT));
+PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
+PROVIDE(_max_hart_id = 0);
+PROVIDE(_hart_stack_size = 2K);
+PROVIDE(_heap_size = 0);
+
+PROVIDE(InstructionMisaligned = ExceptionHandler);
+PROVIDE(InstructionFault = ExceptionHandler);
+PROVIDE(IllegalInstruction = ExceptionHandler);
+PROVIDE(Breakpoint = ExceptionHandler);
+PROVIDE(LoadMisaligned = ExceptionHandler);
+PROVIDE(LoadFault = ExceptionHandler);
+PROVIDE(StoreMisaligned = ExceptionHandler);
+PROVIDE(StoreFault = ExceptionHandler);;
+PROVIDE(UserEnvCall = ExceptionHandler);
+PROVIDE(SupervisorEnvCall = ExceptionHandler);
+PROVIDE(MachineEnvCall = ExceptionHandler);
+PROVIDE(InstructionPageFault = ExceptionHandler);
+PROVIDE(LoadPageFault = ExceptionHandler);
+PROVIDE(StorePageFault = ExceptionHandler);
+
+PROVIDE(SupervisorSoft = DefaultHandler);
+PROVIDE(MachineSoft = DefaultHandler);
+PROVIDE(SupervisorTimer = DefaultHandler);
+PROVIDE(MachineTimer = DefaultHandler);
+PROVIDE(SupervisorExternal = DefaultHandler);
+PROVIDE(MachineExternal = DefaultHandler);
+
+PROVIDE(DefaultHandler = DefaultInterruptHandler);
+PROVIDE(ExceptionHandler = DefaultExceptionHandler);
+
+/* # Pre-initialization function */
+/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,
+   then the function this points to will be called before the RAM is initialized. */
+PROVIDE(__pre_init = default_pre_init);
+
+/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */
+PROVIDE(_setup_interrupts = default_setup_interrupts);
+
+/* # Multi-processing hook function
+   fn _mp_hook() -> bool;
+
+   This function is called from all the harts and must return true only for one hart,
+   which will perform memory initialization. For other harts it must return false
+   and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
+*/
+PROVIDE(_mp_hook = default_mp_hook);
+
+/* # Start trap function override
+  By default uses the riscv crates default trap handler
+  but by providing the `_start_trap` symbol external crates can override.
+*/
+PROVIDE(_start_trap = default_start_trap);
+
+SECTIONS
+{
+  .text.dummy (NOLOAD) :
+  {
+    /* This section is intended to make _stext address work */
+    . = ABSOLUTE(_stext);
+  } > REGION_TEXT
+
+  .text _stext :
+  {
+    /* Put reset handler first in .text section so it ends up as the entry */
+    /* point of the program. */
+    KEEP(*(.init));
+    KEEP(*(.init.rust));
+    . = ALIGN(4);
+    *(.trap);
+    *(.trap.rust);
+    *(.text.abort);
+    *(.text .text.*);
+  } > REGION_TEXT
+
+  .eh_frame : { KEEP(*(.eh_frame)) } > REGION_TEXT
+  .eh_frame_hdr : { *(.eh_frame_hdr) } > REGION_TEXT
+
+  .rodata : ALIGN(4)
+  {
+    *(.srodata .srodata.*);
+    *(.rodata .rodata.*);
+
+    /* 4-byte align the end (VMA) of this section.
+       This is required by LLD to ensure the LMA of the following .data
+       section will have the correct alignment. */
+    . = ALIGN(4);
+  } > REGION_RODATA
+
+  .data : ALIGN(4)
+  {
+    _sidata = LOADADDR(.data);
+    _sdata = .;
+    /* Must be called __global_pointer$ for linker relaxations to work. */
+    PROVIDE(__global_pointer$ = . + 0x800);
+    *(.sdata .sdata.* .sdata2 .sdata2.*);
+    *(.data .data.*);
+    . = ALIGN(4);
+    _edata = .;
+  } > REGION_DATA AT > REGION_RODATA
+
+  .bss (NOLOAD) : ALIGN(4)
+  {
+    _sbss = .;
+    *(.sbss .sbss.* .bss .bss.*);
+    . = ALIGN(4);
+    _ebss = .;
+  } > REGION_BSS
+
+  /* fictitious region that represents the memory available for the heap */
+  .heap (NOLOAD) :
+  {
+    _sheap = .;
+    . += _heap_size;
+    . = ALIGN(4);
+    _eheap = .;
+  } > REGION_HEAP
+
+  /* fictitious region that represents the memory available for the stack */
+  .stack (NOLOAD) :
+  {
+    _estack = .;
+    . = ABSOLUTE(_stack_start);
+    _sstack = .;
+  } > REGION_STACK
+
+  /* fake output .got section */
+  /* Dynamic relocations are unsupported. This section is only used to detect
+     relocatable code in the input files and raise an error if relocatable code
+     is found */
+  .got (INFO) :
+  {
+    KEEP(*(.got .got.*));
+  }
+}
+
+/* Do not exceed this mark in the error messages above                                    | */
+ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
+ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
+
+ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, "
+ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");
+
+ASSERT(ORIGIN(REGION_DATA) % 4 == 0, "
+ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned");
+
+ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, "
+ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");
+
+ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
+ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
+
+ASSERT(ORIGIN(REGION_STACK) % 4 == 0, "
+ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");
+
+ASSERT(_stext % 4 == 0, "
+ERROR(riscv-rt): `_stext` must be 4-byte aligned");
+
+ASSERT(_sdata % 4 == 0 && _edata % 4 == 0, "
+BUG(riscv-rt): .data is not 4-byte aligned");
+
+ASSERT(_sidata % 4 == 0, "
+BUG(riscv-rt): the LMA of .data is not 4-byte aligned");
+
+ASSERT(_sbss % 4 == 0 && _ebss % 4 == 0, "
+BUG(riscv-rt): .bss is not 4-byte aligned");
+
+ASSERT(_sheap % 4 == 0, "
+BUG(riscv-rt): start of .heap is not 4-byte aligned");
+
+ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "
+ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
+Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'");
+
+ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
+ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
+Consider changing `_max_hart_id` or `_hart_stack_size`.");
+
+ASSERT(SIZEOF(.got) == 0, "
+.got section detected in the input files. Dynamic relocations are not
+supported. If you are linking to C code compiled using the `gcc` crate
+then modify your build script to compile the C code _without_ the
+-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
+details.");
+
+/* Do not exceed this mark in the error messages above                                    | */

From 1c9bb7c2e1ff7d68bfa709745f935040c8b415e1 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 13 May 2024 00:35:46 +0200
Subject: [PATCH 6/6] time/generic-queue: fix ub in tests.

---
 embassy-time/src/queue_generic.rs | 120 +++++++++++++-----------------
 1 file changed, 53 insertions(+), 67 deletions(-)

diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs
index cf7a986d5..4882afd3e 100644
--- a/embassy-time/src/queue_generic.rs
+++ b/embassy-time/src/queue_generic.rs
@@ -177,9 +177,10 @@ embassy_time_queue_driver::timer_queue_impl!(static QUEUE: Queue = Queue::new())
 #[cfg(test)]
 #[cfg(feature = "mock-driver")]
 mod tests {
-    use core::cell::Cell;
-    use core::task::{RawWaker, RawWakerVTable, Waker};
-    use std::rc::Rc;
+    use core::sync::atomic::{AtomicBool, Ordering};
+    use core::task::Waker;
+    use std::sync::Arc;
+    use std::task::Wake;
 
     use serial_test::serial;
 
@@ -188,42 +189,26 @@ mod tests {
     use crate::{Duration, Instant};
 
     struct TestWaker {
-        pub awoken: Rc<Cell<bool>>,
-        pub waker: Waker,
+        pub awoken: AtomicBool,
     }
 
-    impl TestWaker {
-        fn new() -> Self {
-            let flag = Rc::new(Cell::new(false));
-
-            const VTABLE: RawWakerVTable = RawWakerVTable::new(
-                |data: *const ()| {
-                    unsafe {
-                        Rc::increment_strong_count(data as *const Cell<bool>);
-                    }
-
-                    RawWaker::new(data as _, &VTABLE)
-                },
-                |data: *const ()| unsafe {
-                    let data = data as *const Cell<bool>;
-                    data.as_ref().unwrap().set(true);
-                    Rc::decrement_strong_count(data);
-                },
-                |data: *const ()| unsafe {
-                    (data as *const Cell<bool>).as_ref().unwrap().set(true);
-                },
-                |data: *const ()| unsafe {
-                    Rc::decrement_strong_count(data);
-                },
-            );
-
-            let raw = RawWaker::new(Rc::into_raw(flag.clone()) as _, &VTABLE);
-
-            Self {
-                awoken: flag.clone(),
-                waker: unsafe { Waker::from_raw(raw) },
-            }
+    impl Wake for TestWaker {
+        fn wake(self: Arc<Self>) {
+            self.awoken.store(true, Ordering::Relaxed);
         }
+
+        fn wake_by_ref(self: &Arc<Self>) {
+            self.awoken.store(true, Ordering::Relaxed);
+        }
+    }
+
+    fn test_waker() -> (Arc<TestWaker>, Waker) {
+        let arc = Arc::new(TestWaker {
+            awoken: AtomicBool::new(false),
+        });
+        let waker = Waker::from(arc.clone());
+
+        (arc, waker)
     }
 
     fn setup() {
@@ -249,11 +234,11 @@ mod tests {
 
         assert_eq!(queue_len(), 0);
 
-        let waker = TestWaker::new();
+        let (flag, waker) = test_waker();
 
-        QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker);
+        QUEUE.schedule_wake(Instant::from_secs(1), &waker);
 
-        assert!(!waker.awoken.get());
+        assert!(!flag.awoken.load(Ordering::Relaxed));
         assert_eq!(queue_len(), 1);
     }
 
@@ -262,23 +247,23 @@ mod tests {
     fn test_schedule_same() {
         setup();
 
-        let waker = TestWaker::new();
+        let (_flag, waker) = test_waker();
 
-        QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker);
+        QUEUE.schedule_wake(Instant::from_secs(1), &waker);
 
         assert_eq!(queue_len(), 1);
 
-        QUEUE.schedule_wake(Instant::from_secs(1), &waker.waker);
+        QUEUE.schedule_wake(Instant::from_secs(1), &waker);
 
         assert_eq!(queue_len(), 1);
 
-        QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker);
+        QUEUE.schedule_wake(Instant::from_secs(100), &waker);
 
         assert_eq!(queue_len(), 1);
 
-        let waker2 = TestWaker::new();
+        let (_flag2, waker2) = test_waker();
 
-        QUEUE.schedule_wake(Instant::from_secs(100), &waker2.waker);
+        QUEUE.schedule_wake(Instant::from_secs(100), &waker2);
 
         assert_eq!(queue_len(), 2);
     }
@@ -288,21 +273,21 @@ mod tests {
     fn test_trigger() {
         setup();
 
-        let waker = TestWaker::new();
+        let (flag, waker) = test_waker();
 
-        QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker);
+        QUEUE.schedule_wake(Instant::from_secs(100), &waker);
 
-        assert!(!waker.awoken.get());
+        assert!(!flag.awoken.load(Ordering::Relaxed));
 
         MockDriver::get().advance(Duration::from_secs(99));
 
-        assert!(!waker.awoken.get());
+        assert!(!flag.awoken.load(Ordering::Relaxed));
 
         assert_eq!(queue_len(), 1);
 
         MockDriver::get().advance(Duration::from_secs(1));
 
-        assert!(waker.awoken.get());
+        assert!(flag.awoken.load(Ordering::Relaxed));
 
         assert_eq!(queue_len(), 0);
     }
@@ -312,18 +297,18 @@ mod tests {
     fn test_immediate_trigger() {
         setup();
 
-        let waker = TestWaker::new();
+        let (flag, waker) = test_waker();
 
-        QUEUE.schedule_wake(Instant::from_secs(100), &waker.waker);
+        QUEUE.schedule_wake(Instant::from_secs(100), &waker);
 
         MockDriver::get().advance(Duration::from_secs(50));
 
-        let waker2 = TestWaker::new();
+        let (flag2, waker2) = test_waker();
 
-        QUEUE.schedule_wake(Instant::from_secs(40), &waker2.waker);
+        QUEUE.schedule_wake(Instant::from_secs(40), &waker2);
 
-        assert!(!waker.awoken.get());
-        assert!(waker2.awoken.get());
+        assert!(!flag.awoken.load(Ordering::Relaxed));
+        assert!(flag2.awoken.load(Ordering::Relaxed));
         assert_eq!(queue_len(), 1);
     }
 
@@ -333,30 +318,31 @@ mod tests {
         setup();
 
         for i in 1..super::QUEUE_SIZE {
-            let waker = TestWaker::new();
+            let (flag, waker) = test_waker();
 
-            QUEUE.schedule_wake(Instant::from_secs(310), &waker.waker);
+            QUEUE.schedule_wake(Instant::from_secs(310), &waker);
 
             assert_eq!(queue_len(), i);
-            assert!(!waker.awoken.get());
+            assert!(!flag.awoken.load(Ordering::Relaxed));
         }
 
-        let first_waker = TestWaker::new();
+        let (flag, waker) = test_waker();
 
-        QUEUE.schedule_wake(Instant::from_secs(300), &first_waker.waker);
+        QUEUE.schedule_wake(Instant::from_secs(300), &waker);
 
         assert_eq!(queue_len(), super::QUEUE_SIZE);
-        assert!(!first_waker.awoken.get());
+        assert!(!flag.awoken.load(Ordering::Relaxed));
 
-        let second_waker = TestWaker::new();
+        let (flag2, waker2) = test_waker();
 
-        QUEUE.schedule_wake(Instant::from_secs(305), &second_waker.waker);
+        QUEUE.schedule_wake(Instant::from_secs(305), &waker2);
 
         assert_eq!(queue_len(), super::QUEUE_SIZE);
-        assert!(first_waker.awoken.get());
+        assert!(flag.awoken.load(Ordering::Relaxed));
 
-        QUEUE.schedule_wake(Instant::from_secs(320), &TestWaker::new().waker);
+        let (_flag3, waker3) = test_waker();
+        QUEUE.schedule_wake(Instant::from_secs(320), &waker3);
         assert_eq!(queue_len(), super::QUEUE_SIZE);
-        assert!(second_waker.awoken.get());
+        assert!(flag2.awoken.load(Ordering::Relaxed));
     }
 }