pub struct GuestMemWriter {
ptr: *mut u8,
len: usize,
gpa_base: usize,
}
unsafe impl Send for GuestMemWriter {}
unsafe impl Sync for GuestMemWriter {}
impl GuestMemWriter {
pub unsafe fn new(ptr: *mut u8, len: usize, gpa_base: usize) -> Self {
Self { ptr, len, gpa_base }
}
pub fn gpa_to_offset(&self, gpa: usize, access_len: usize) -> Option<usize> {
let off = gpa.checked_sub(self.gpa_base)?;
let end = off.checked_add(access_len)?;
if end > self.len {
return None;
}
Some(off)
}
#[allow(clippy::mut_from_ref)] pub unsafe fn slice_mut(&self, gpa: usize, len: usize) -> Option<&mut [u8]> {
let off = self.gpa_to_offset(gpa, len)?;
unsafe { Some(std::slice::from_raw_parts_mut(self.ptr.add(off), len)) }
}
pub fn slice(&self, gpa: usize, len: usize) -> Option<&[u8]> {
let off = self.gpa_to_offset(gpa, len)?;
unsafe { Some(std::slice::from_raw_parts(self.ptr.add(off), len)) }
}
pub fn read_u16(&self, gpa: usize) -> u16 {
let Some(off) = self.gpa_to_offset(gpa, 2) else {
return 0;
};
unsafe {
let p = self.ptr.add(off);
u16::from_le_bytes([*p, *p.add(1)])
}
}
pub fn read_u32(&self, gpa: usize) -> u32 {
match self.slice(gpa, 4) {
Some(b) => u32::from_le_bytes([b[0], b[1], b[2], b[3]]),
None => 0,
}
}
pub fn read_u64(&self, gpa: usize) -> u64 {
match self.slice(gpa, 8) {
Some(b) => u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]),
None => 0,
}
}
pub fn write_u16(&self, gpa: usize, val: u16) {
let Some(off) = self.gpa_to_offset(gpa, 2) else {
return;
};
let bytes = val.to_le_bytes();
unsafe {
let p = self.ptr.add(off);
*p = bytes[0];
*p.add(1) = bytes[1];
}
}
pub fn write_u32(&self, gpa: usize, val: u32) {
let Some(off) = self.gpa_to_offset(gpa, 4) else {
return;
};
let bytes = val.to_le_bytes();
unsafe {
let p = self.ptr.add(off);
*p = bytes[0];
*p.add(1) = bytes[1];
*p.add(2) = bytes[2];
*p.add(3) = bytes[3];
}
}
pub fn write_byte(&self, gpa: usize, val: u8) {
let Some(off) = self.gpa_to_offset(gpa, 1) else {
return;
};
unsafe { *self.ptr.add(off) = val };
}
pub fn ptr(&self) -> *mut u8 {
self.ptr
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn gpa_base(&self) -> usize {
self.gpa_base
}
}