diff --git a/framework/aster-frame/src/vm/io.rs b/framework/aster-frame/src/vm/io.rs index e4da7972e..f687b54e3 100644 --- a/framework/aster-frame/src/vm/io.rs +++ b/framework/aster-frame/src/vm/io.rs @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 +use align_ext::AlignExt; use inherit_methods_macro::inherit_methods; use pod::Pod; @@ -65,6 +66,67 @@ pub trait VmIo: Send + Sync { let buf = unsafe { core::mem::transmute(slice) }; 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>( + &self, + offset: usize, + iter: I, + align: usize, + ) -> Result { + let mut nr_written = 0; + + let (mut offset, item_size) = if (align >> 1) == 0 { + // align is 0 or 1 + (offset, core::mem::size_of::()) + } else { + // align is more than 2 + ( + offset.align_up(align), + core::mem::size_of::().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 { diff --git a/kernel/comps/virtio/src/device/input/device.rs b/kernel/comps/virtio/src/device/input/device.rs index ca560f00e..1ebd7a143 100644 --- a/kernel/comps/virtio/src/device/input/device.rs +++ b/kernel/comps/virtio/src/device/input/device.rs @@ -6,7 +6,7 @@ use alloc::{ sync::Arc, vec::Vec, }; -use core::{fmt::Debug, mem}; +use core::{fmt::Debug, iter, mem}; use aster_frame::{ io_mem::IoMem, @@ -244,10 +244,9 @@ impl EventTable { let vm_segment = VmAllocOptions::new(1).alloc_contiguous().unwrap(); let default_event = VirtioInputEvent::default(); - for idx in 0..num_events { - let offset = idx * EVENT_SIZE; - vm_segment.write_val(offset, &default_event).unwrap(); - } + let iter = iter::repeat(&default_event); + let nr_written = vm_segment.write_vals(0, iter, 0).unwrap(); + assert_eq!(nr_written, EVENT_SIZE); let stream = DmaStream::map(vm_segment, DmaDirection::FromDevice, false).unwrap(); Self { stream, num_events }