From e22c5c013347eb09d585710abb9f96e060448dba Mon Sep 17 00:00:00 2001 From: Jan Niehusmann Date: Tue, 23 May 2023 10:35:16 +0000 Subject: [PATCH 1/3] Mark ReadTarget and WriteTarget as unsafe --- rp2040-hal/src/dma/mod.rs | 11 +++++++---- rp2040-hal/src/pio.rs | 8 ++++++-- rp2040-hal/src/spi.rs | 8 ++++++-- rp2040-hal/src/uart/reader.rs | 4 +++- rp2040-hal/src/uart/writer.rs | 4 +++- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/rp2040-hal/src/dma/mod.rs b/rp2040-hal/src/dma/mod.rs index d5e871ba0..91cb56c6b 100644 --- a/rp2040-hal/src/dma/mod.rs +++ b/rp2040-hal/src/dma/mod.rs @@ -149,7 +149,8 @@ impl ChannelRegs for Channel { } /// Trait which is implemented by anything that can be read via DMA. -pub trait ReadTarget { + +pub unsafe trait ReadTarget { /// Type which is transferred in a single DMA transfer. type ReceivedWord; @@ -179,7 +180,8 @@ pub trait ReadTarget { /// two DMA channels. In the case of peripherals, the function can always return the same values. pub trait EndlessReadTarget: ReadTarget {} -impl ReadTarget for B { +/// Safety: ReadBuffer and ReadTarget have the same safety requirements. +unsafe impl ReadTarget for B { type ReceivedWord = ::Word; fn rx_treq() -> Option { @@ -197,7 +199,7 @@ impl ReadTarget for B { } /// Trait which is implemented by anything that can be written via DMA. -pub trait WriteTarget { +pub unsafe trait WriteTarget { /// Type which is transferred in a single DMA transfer. type TransmittedWord; @@ -221,7 +223,8 @@ pub trait WriteTarget { /// two DMA channels. In the case of peripherals, the function can always return the same values. pub trait EndlessWriteTarget: WriteTarget {} -impl WriteTarget for B { +/// Safety: WriteBuffer and WriteTarget have the same safety requirements. +unsafe impl WriteTarget for B { type TransmittedWord = ::Word; fn tx_treq() -> Option { diff --git a/rp2040-hal/src/pio.rs b/rp2040-hal/src/pio.rs index 505c83356..51e97879a 100644 --- a/rp2040-hal/src/pio.rs +++ b/rp2040-hal/src/pio.rs @@ -1394,7 +1394,9 @@ impl Rx { } } -impl ReadTarget for Rx { +// Safety: This only reads from the state machine fifo, so it doesn't +// interact with rust-managed memory. +unsafe impl ReadTarget for Rx { type ReceivedWord = u32; fn rx_treq() -> Option { @@ -1586,7 +1588,9 @@ impl Tx { } } -impl WriteTarget for Tx { +// Safety: This only writes to the state machine fifo, so it doesn't +// interact with rust-managed memory. +unsafe impl WriteTarget for Tx { type TransmittedWord = u32; fn tx_treq() -> Option { diff --git a/rp2040-hal/src/spi.rs b/rp2040-hal/src/spi.rs index c9c816e31..eb1e23be6 100644 --- a/rp2040-hal/src/spi.rs +++ b/rp2040-hal/src/spi.rs @@ -449,7 +449,9 @@ macro_rules! impl_write { } } - impl> ReadTarget for Spi { + // Safety: This only reads from the RX fifo, so it doesn't + // interact with rust-managed memory. + unsafe impl> ReadTarget for Spi { type ReceivedWord = $type; fn rx_treq() -> Option { @@ -470,7 +472,9 @@ macro_rules! impl_write { impl> EndlessReadTarget for Spi {} - impl> WriteTarget for Spi { + // Safety: This only writes to the TX fifo, so it doesn't + // interact with rust-managed memory. + unsafe impl> WriteTarget for Spi { type TransmittedWord = $type; fn tx_treq() -> Option { diff --git a/rp2040-hal/src/uart/reader.rs b/rp2040-hal/src/uart/reader.rs index 7ba882af1..cacb1c593 100644 --- a/rp2040-hal/src/uart/reader.rs +++ b/rp2040-hal/src/uart/reader.rs @@ -236,7 +236,9 @@ impl> Read for Reader { } } -impl> ReadTarget for Reader { +// Safety: This only reads from the RX fifo, so it doesn't +// interact with rust-managed memory. +unsafe impl> ReadTarget for Reader { type ReceivedWord = u8; fn rx_treq() -> Option { diff --git a/rp2040-hal/src/uart/writer.rs b/rp2040-hal/src/uart/writer.rs index 7e9e71e47..fec76bb0c 100644 --- a/rp2040-hal/src/uart/writer.rs +++ b/rp2040-hal/src/uart/writer.rs @@ -184,7 +184,9 @@ impl> Write for Writer { } } -impl> WriteTarget for Writer { +// Safety: This only writes to the TX fifo, so it doesn't +// interact with rust-managed memory. +unsafe impl> WriteTarget for Writer { type TransmittedWord = u8; fn tx_treq() -> Option { From 4976e9300202bb4b7b4571d848d7c065c6aef162 Mon Sep 17 00:00:00 2001 From: Jan Niehusmann Date: Tue, 23 May 2023 18:16:29 +0000 Subject: [PATCH 2/3] Add safety comments --- rp2040-hal/src/dma/mod.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/rp2040-hal/src/dma/mod.rs b/rp2040-hal/src/dma/mod.rs index 91cb56c6b..a053f291f 100644 --- a/rp2040-hal/src/dma/mod.rs +++ b/rp2040-hal/src/dma/mod.rs @@ -149,7 +149,18 @@ impl ChannelRegs for Channel { } /// Trait which is implemented by anything that can be read via DMA. - +/// +/// # Safety +/// +/// The implementing type must be safe to use for DMA reads. This means: +/// +/// - The range returned by rx_address_count must pointer to a valid address, +/// and if rx_increment is true, count must fit into the allocated buffer. +/// - As long as no `&mut self` method is called on the implementing object: +/// - `rx_address_count` must always return the same value, if called multiple +/// times. +/// - The memory specified by the pointer and size returned by `rx_address_count` +/// must not be freed during the transfer it is used in as long as `self` is not dropped. pub unsafe trait ReadTarget { /// Type which is transferred in a single DMA transfer. type ReceivedWord; @@ -199,6 +210,18 @@ unsafe impl ReadTarget for B { } /// Trait which is implemented by anything that can be written via DMA. +/// +/// # Safety +/// +/// The implementing type must be safe to use for DMA writes. This means: +/// +/// - The range returned by tx_address_count must pointer to a valid address, +/// and if tx_increment is true, count must fit into the allocated buffer. +/// - As long as no other `&mut self` method is called on the implementing object: +/// - `tx_address_count` must always return the same value, if called multiple +/// times. +/// - The memory specified by the pointer and size returned by `tx_address_count` +/// must not be freed during the transfer it is used in as long as `self` is not dropped. pub unsafe trait WriteTarget { /// Type which is transferred in a single DMA transfer. type TransmittedWord; From 172b1fab437670fe2bf1341d25373a27eeb315d2 Mon Sep 17 00:00:00 2001 From: Jan Niehusmann Date: Sat, 8 Jul 2023 08:56:25 +0000 Subject: [PATCH 3/3] Fix a typo --- rp2040-hal/src/dma/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/dma/mod.rs b/rp2040-hal/src/dma/mod.rs index a053f291f..bf5cc8bd4 100644 --- a/rp2040-hal/src/dma/mod.rs +++ b/rp2040-hal/src/dma/mod.rs @@ -154,7 +154,7 @@ impl ChannelRegs for Channel { /// /// The implementing type must be safe to use for DMA reads. This means: /// -/// - The range returned by rx_address_count must pointer to a valid address, +/// - The range returned by rx_address_count must point to a valid address, /// and if rx_increment is true, count must fit into the allocated buffer. /// - As long as no `&mut self` method is called on the implementing object: /// - `rx_address_count` must always return the same value, if called multiple @@ -215,7 +215,7 @@ unsafe impl ReadTarget for B { /// /// The implementing type must be safe to use for DMA writes. This means: /// -/// - The range returned by tx_address_count must pointer to a valid address, +/// - The range returned by tx_address_count must point to a valid address, /// and if tx_increment is true, count must fit into the allocated buffer. /// - As long as no other `&mut self` method is called on the implementing object: /// - `tx_address_count` must always return the same value, if called multiple