Add assembly memset for fast filling zeros

This commit is contained in:
Shaowei Song
2024-08-28 09:38:43 +00:00
committed by Tate, Hongliang Tian
parent a72c7dadf3
commit aae9fdb331
6 changed files with 80 additions and 9 deletions

View File

@ -48,7 +48,7 @@ use const_assert::{Assert, IsTrue};
use inherit_methods_macro::inherit_methods;
use crate::{
arch::mm::__memcpy_fallible,
arch::mm::{__memcpy_fallible, __memset_fallible},
mm::{
kspace::{KERNEL_BASE_VADDR, KERNEL_END_VADDR},
MAX_USERSPACE_VADDR,
@ -326,6 +326,21 @@ unsafe fn memcpy_fallible(dst: *mut u8, src: *const u8, len: usize) -> usize {
len - failed_bytes
}
/// Fills `len` bytes of memory at `dst` with the specified `value`.
/// This function will early stop filling if encountering an unresolvable page fault.
///
/// Returns the number of successfully set bytes.
///
/// # Safety
///
/// - `dst` must either be [valid] for writes of `len` bytes or be in user space for `len` bytes.
///
/// [valid]: crate::mm::io#safety
unsafe fn memset_fallible(dst: *mut u8, value: u8, len: usize) -> usize {
let failed_bytes = __memset_fallible(dst, value, len);
len - failed_bytes
}
/// Fallible memory read from a `VmWriter`.
pub trait FallibleVmRead<F> {
/// Reads all data into the writer until one of the three conditions is met:
@ -825,6 +840,34 @@ impl<'a> VmWriter<'a, Fallible> {
})?;
Ok(())
}
/// Writes `len` zeros to the target memory.
///
/// This method attempts to fill up to `len` bytes with zeros. If the available
/// memory from the current cursor position is less than `len`, it will only fill
/// the available space.
///
/// If the memory write failed due to an unresolvable page fault, this method
/// will return `Err` with the length set so far.
pub fn fill_zeros(&mut self, len: usize) -> core::result::Result<usize, (Error, usize)> {
let len_to_set = self.avail().min(len);
if len_to_set == 0 {
return Ok(0);
}
// SAFETY: The destination is a subset of the memory range specified by
// the current writer, so it is either valid for writing or in user space.
let set_len = unsafe {
let set_len = memset_fallible(self.cursor, 0u8, len_to_set);
self.cursor = self.cursor.add(set_len);
set_len
};
if set_len < len_to_set {
Err((Error::PageFault, set_len))
} else {
Ok(len_to_set)
}
}
}
impl<'a, Fallibility> VmWriter<'a, Fallibility> {