Skip to content

Commit 68823a3

Browse files
author
Maciej Falkowski
committed
rust: iomem: add memcpy_fromio function bindings
Signed-off-by: Maciej Falkowski <[email protected]>
1 parent 6625ab8 commit 68823a3

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

rust/helpers.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ void rust_helper_writeq_relaxed(u64 value, volatile void __iomem *addr)
176176
}
177177
EXPORT_SYMBOL_GPL(rust_helper_writeq_relaxed);
178178
#endif
179+
180+
void rust_helper_memcpy_fromio(void *to, const volatile void __iomem *from, long count)
181+
{
182+
memcpy_fromio(to, from, count);
183+
}
184+
179185
void rust_helper___spin_lock_init(spinlock_t *lock, const char *name,
180186
struct lock_class_key *key)
181187
{

rust/kernel/io_mem.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,50 @@ impl<const SIZE: usize> IoMem<SIZE> {
266266
);
267267
}
268268

269+
/// Copy memory block from IO memory into buffer.
270+
///
271+
/// # Examples
272+
/// ```
273+
/// use kernel::io_mem::{self, IoMem, Resource};
274+
///
275+
/// fn test(res: Resource) -> Result {
276+
/// // Create an io mem block of at least 100 bytes.
277+
/// let mem = unsafe { IoMem::<100>::try_new(res) }?;
278+
///
279+
/// let buffer: [i8; 32] = [0; 32];
280+
///
281+
/// // Memcpy 16 bytes from offset 10 of io mem block into the buffer.
282+
/// io_mem::try_memcpy_fromio(mem, buffer, 10, 16)?;
283+
///
284+
/// Ok(())
285+
/// ```
286+
pub fn try_memcpy_fromio<const SIZE: usize>(
287+
iomem: &IoMem<SIZE>,
288+
data: &mut [i8],
289+
offset: usize,
290+
count: usize,
291+
) -> Result {
292+
if !IoMem::<SIZE>::offset_ok::<u8>(offset) {
293+
return Err(Error::EINVAL);
294+
}
295+
296+
// Check if memory block can be copied from io region
297+
// and also whether it will fit into data buffer.
298+
if count > data.len() || count > SIZE - offset {
299+
return Err(Error::EINVAL);
300+
}
301+
302+
let ptr = iomem.ptr.wrapping_add(offset);
303+
304+
// SAFETY:
305+
// - The type invariants guarantee that `ptr` is a valid pointer.
306+
// - The `offset_ok` check returns an error if `offset` would make the write
307+
// go out of bounds (including the type size).
308+
// - the sizes of from/to buffers are asserted whether they match `count` above.
309+
unsafe { bindings::memcpy_fromio(data.as_mut_ptr() as _, ptr as _, count.try_into()?) };
310+
Ok(())
311+
}
312+
269313
impl<const SIZE: usize> Drop for IoMem<SIZE> {
270314
fn drop(&mut self) {
271315
// SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful

0 commit comments

Comments
 (0)