Skip to content

Commit 2cbcfb9

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 8b84b12 commit 2cbcfb9

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
@@ -206,6 +206,15 @@ impl<const SIZE: usize> Io<SIZE> {
206206
}
207207
}
208208

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

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

0 commit comments

Comments
 (0)