Skip to content

Commit 87ae7db

Browse files
hoshinolinajannau
authored andcommitted
Rust: io: Add memcpy_fromio wrapper
Adapted from *RFL import: kernel::io_mem Commit reference: 3dfc5eb Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 6de1dbb commit 87ae7db

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

rust/helpers/io.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ void rust_helper_iounmap(void __iomem *addr)
1818
iounmap(addr);
1919
}
2020

21+
void rust_helper_memcpy_fromio(void *to, const void __iomem *from, long count)
22+
{
23+
memcpy_fromio(to, from, count);
24+
}
25+
2126
u8 rust_helper_readb(const void __iomem *addr)
2227
{
2328
return readb(addr);

rust/kernel/io.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ impl<const SIZE: usize> Io<SIZE> {
205205
}
206206
}
207207

208+
#[inline]
209+
const fn length_valid(offset: usize, length: usize, size: usize) -> bool {
210+
if let Some(end) = offset.checked_add(length) {
211+
end <= size
212+
} else {
213+
false
214+
}
215+
}
216+
208217
#[inline]
209218
fn io_addr<U>(&self, offset: usize) -> Result<usize> {
210219
if !Self::offset_valid::<U>(offset, self.maxsize()) {
@@ -223,6 +232,46 @@ impl<const SIZE: usize> Io<SIZE> {
223232
self.addr() + offset
224233
}
225234

235+
/// Copy memory block from an i/o memory by filling the specified buffer with it.
236+
///
237+
/// # Examples
238+
/// ```
239+
/// use kernel::io::mem::IoMem;
240+
/// use kernel::io::mem::Resource;
241+
///
242+
/// fn test(device: &Device, res: Resource) -> Result {
243+
/// // Create an i/o memory block of at least 100 bytes.
244+
/// let devres_mem = IoMem::<100>::new(res, device)?;
245+
/// // aquire access to memory block
246+
/// let mem = devres_mem.try_access()?;
247+
///
248+
/// let mut buffer: [u8; 32] = [0; 32];
249+
///
250+
/// // Memcpy 16 bytes from an offset 10 of i/o memory block into the buffer.
251+
/// mem.try_memcpy_fromio(&mut buffer[..16], 10)?;
252+
///
253+
/// Ok(())
254+
/// }
255+
/// ```
256+
pub fn try_memcpy_fromio(&self, buffer: &mut [u8], offset: usize) -> Result {
257+
if buffer.len() == 0 || !Self::length_valid(offset, buffer.len(), self.maxsize()) {
258+
return Err(EINVAL);
259+
}
260+
let addr = self.io_addr::<crate::ffi::c_char>(offset)?;
261+
262+
// SAFETY:
263+
// - The type invariants guarantee that `adr` is a valid pointer.
264+
// - The bounds of `buffer` are checked with a call to `length_valid`.
265+
unsafe {
266+
bindings::memcpy_fromio(
267+
buffer.as_mut_ptr() as *mut _,
268+
addr as *const _,
269+
buffer.len() as _,
270+
)
271+
};
272+
Ok(())
273+
}
274+
226275
define_read!(read8, try_read8, readb -> u8);
227276
define_read!(read16, try_read16, readw -> u16);
228277
define_read!(read32, try_read32, readl -> u32);

0 commit comments

Comments
 (0)