Skip to content

Commit b40a3e8

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 63fcaa9 commit b40a3e8

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
@@ -203,6 +203,15 @@ impl<const SIZE: usize> Io<SIZE> {
203203
}
204204
}
205205

206+
#[inline]
207+
const fn length_valid(offset: usize, length: usize, size: usize) -> bool {
208+
if let Some(end) = offset.checked_add(length) {
209+
end <= size
210+
} else {
211+
false
212+
}
213+
}
214+
206215
#[inline]
207216
fn io_addr<U>(&self, offset: usize) -> Result<usize> {
208217
if !Self::offset_valid::<U>(offset, self.maxsize()) {
@@ -221,6 +230,46 @@ impl<const SIZE: usize> Io<SIZE> {
221230
self.addr() + offset
222231
}
223232

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

0 commit comments

Comments
 (0)