Skip to content

Commit 0c351d7

Browse files
author
Maciej Falkowski
committed
rust: iomem: add try_memcpy_fromio method for IoMem<T>
This patch adds only runtime-checked bindings version of `memcpy_fromio()` function prefixed with `try_` similarly to read/write methods of `IoMem<T>` that is `readx` and `try_readx`. Signed-off-by: Maciej Falkowski <[email protected]>
1 parent 2ef2e88 commit 0c351d7

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

rust/helpers.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ void rust_helper_writeq_relaxed(u64 value, volatile void __iomem *addr)
181181
}
182182
EXPORT_SYMBOL_GPL(rust_helper_writeq_relaxed);
183183
#endif
184+
185+
void rust_helper_memcpy_fromio(void *to, const volatile void __iomem *from, long count)
186+
{
187+
memcpy_fromio(to, from, count);
188+
}
189+
EXPORT_SYMBOL_GPL(rust_helper_memcpy_fromio);
190+
184191
void rust_helper___spin_lock_init(spinlock_t *lock, const char *name,
185192
struct lock_class_key *key)
186193
{

rust/kernel/io_mem.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,47 @@ impl<const SIZE: usize> IoMem<SIZE> {
177177
crate::build_assert!(Self::offset_ok::<T>(offset), "IoMem offset overflow");
178178
}
179179

180+
/// Copy memory block from an i/o memory into a buffer.
181+
///
182+
/// # Examples
183+
/// ```
184+
/// # use kernel::prelude::*;
185+
/// use kernel::io_mem::{self, IoMem, Resource};
186+
///
187+
/// fn test(res: Resource) -> Result {
188+
/// // Create an i/o memory block of at least 100 bytes.
189+
/// let mem = unsafe { IoMem::<100>::try_new(res) }?;
190+
///
191+
/// let mut buffer: [i8; 32] = [0; 32];
192+
///
193+
/// // Memcpy 16 bytes from offset 10 of i/o memory block into the buffer.
194+
/// mem.try_memcpy_fromio(&mut buffer, 10, 16)?;
195+
///
196+
/// Ok(())
197+
/// }
198+
/// ```
199+
pub fn try_memcpy_fromio(&self, from: &mut [i8], offset: usize, count: usize) -> Result {
200+
if !IoMem::<SIZE>::offset_ok::<u8>(offset) {
201+
return Err(Error::EINVAL);
202+
}
203+
204+
// Check if memory block can be copied from i/o region
205+
// and also whether it will fit into data buffer.
206+
if count > from.len() || count > SIZE - offset {
207+
return Err(Error::EINVAL);
208+
}
209+
210+
let ptr = self.ptr.wrapping_add(offset);
211+
212+
// SAFETY:
213+
// - The type invariants guarantee that `ptr` is a valid pointer.
214+
// - The `offset_ok` check returns an error if `offset` would make the write
215+
// go out of bounds (including the type size).
216+
// - the sizes of from/to bufferso are asserted whether they match `count` above.
217+
unsafe { bindings::memcpy_fromio(from.as_mut_ptr() as _, ptr as _, count as _) };
218+
Ok(())
219+
}
220+
180221
define_read!(readb, try_readb, u8);
181222
define_read!(readw, try_readw, u16);
182223
define_read!(readl, try_readl, u32);

0 commit comments

Comments
 (0)