Add write_vals for VmIo

This commit is contained in:
Jianfeng Jiang
2024-04-28 08:58:19 +00:00
committed by Tate, Hongliang Tian
parent abb377b695
commit 345ab8f838
2 changed files with 66 additions and 5 deletions

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use align_ext::AlignExt;
use inherit_methods_macro::inherit_methods; use inherit_methods_macro::inherit_methods;
use pod::Pod; use pod::Pod;
@ -65,6 +66,67 @@ pub trait VmIo: Send + Sync {
let buf = unsafe { core::mem::transmute(slice) }; let buf = unsafe { core::mem::transmute(slice) };
self.write_bytes(offset, buf) self.write_bytes(offset, buf)
} }
/// Write a sequence of values given by an iterator (`iter`) from the specified offset (`offset`).
///
/// The write process stops until the VM object does not have enough remaining space
/// or the iterator returns `None`. If any value is written, the function returns `Ok(nr_written)`,
/// where `nr_written` is the number of the written values.
///
/// The offset of every value written by this method is aligned to the `align`-byte boundary.
/// Naturally, when `align` equals to `0` or `1`, then the argument takes no effect:
/// the values will be written in the most compact way.
///
/// # Example
///
/// Initializing an VM object with the same value can be done easily with `write_values`.
///
/// ```
/// use core::iter::self;
///
/// let _nr_values = vm_obj.write_values(0, iter::repeat(0_u32), 0).unwrap();
/// ```
///
/// # Panic
///
/// This method panics if `align` is greater than two,
/// but not a power of two, in release mode.
fn write_vals<'a, T: Pod + 'a, I: Iterator<Item = &'a T>>(
&self,
offset: usize,
iter: I,
align: usize,
) -> Result<usize> {
let mut nr_written = 0;
let (mut offset, item_size) = if (align >> 1) == 0 {
// align is 0 or 1
(offset, core::mem::size_of::<T>())
} else {
// align is more than 2
(
offset.align_up(align),
core::mem::size_of::<T>().align_up(align),
)
};
for item in iter {
match self.write_val(offset, item) {
Ok(_) => {
offset += item_size;
nr_written += 1;
}
Err(e) => {
if nr_written > 0 {
return Ok(nr_written);
}
return Err(e);
}
}
}
Ok(nr_written)
}
} }
macro_rules! impl_vmio_pointer { macro_rules! impl_vmio_pointer {

View File

@ -6,7 +6,7 @@ use alloc::{
sync::Arc, sync::Arc,
vec::Vec, vec::Vec,
}; };
use core::{fmt::Debug, mem}; use core::{fmt::Debug, iter, mem};
use aster_frame::{ use aster_frame::{
io_mem::IoMem, io_mem::IoMem,
@ -244,10 +244,9 @@ impl EventTable {
let vm_segment = VmAllocOptions::new(1).alloc_contiguous().unwrap(); let vm_segment = VmAllocOptions::new(1).alloc_contiguous().unwrap();
let default_event = VirtioInputEvent::default(); let default_event = VirtioInputEvent::default();
for idx in 0..num_events { let iter = iter::repeat(&default_event);
let offset = idx * EVENT_SIZE; let nr_written = vm_segment.write_vals(0, iter, 0).unwrap();
vm_segment.write_val(offset, &default_event).unwrap(); assert_eq!(nr_written, EVENT_SIZE);
}
let stream = DmaStream::map(vm_segment, DmaDirection::FromDevice, false).unwrap(); let stream = DmaStream::map(vm_segment, DmaDirection::FromDevice, false).unwrap();
Self { stream, num_events } Self { stream, num_events }