use std::slice;
use super::raw::bindings::{
ConstBufferView, GuestAddress, MemoryBuffer, MemoryBufferWithRanges,
MemoryRange,
};
#[derive(Debug)]
pub struct QueriedMemoryRange<'a> {
address: GuestAddress,
memory: &'a [u8],
sequence: super::raw::bindings::SequenceId,
}
impl<'a> QueriedMemoryRange<'a> {
pub(crate) unsafe fn from_ttd_owned(result: MemoryRange) -> Self {
let memory = if result.Memory.Size == 0 {
&[]
} else {
assert!(
!result.Memory.BaseAddress.is_null(),
"TTD returned a null memory-range pointer with a non-zero size"
);
assert!(
result.Memory.Size <= isize::MAX as usize,
"TTD returned a memory range too large for a Rust slice"
);
unsafe {
slice::from_raw_parts(
result.Memory.BaseAddress.cast::<u8>(),
result.Memory.Size,
)
}
};
Self {
address: result.Address,
memory,
sequence: result.Sequence,
}
}
#[inline]
pub fn address(&self) -> GuestAddress { self.address }
#[inline]
pub fn memory(&self) -> &'a [u8] { self.memory }
#[inline]
pub fn sequence(&self) -> super::raw::bindings::SequenceId { self.sequence }
}
#[derive(Debug)]
pub struct QueriedMemory<'a> {
address: GuestAddress,
memory: &'a [u8],
}
impl<'a> QueriedMemory<'a> {
#[inline]
pub(crate) fn from_raw(buffer: &'a [u8], result: MemoryBuffer) -> Self {
Self {
address: result.Address,
memory: validated_memory_slice(buffer, result.Memory),
}
}
#[inline]
pub fn address(&self) -> GuestAddress { self.address }
#[inline]
pub fn memory(&self) -> &'a [u8] { self.memory }
}
#[derive(Debug)]
pub struct QueriedMemoryWithRanges<'a, 'r> {
address: GuestAddress,
memory: &'a [u8],
ranges: &'r [MemoryRange],
}
impl<'a, 'r> QueriedMemoryWithRanges<'a, 'r> {
#[inline]
pub(crate) fn from_raw(
buffer: &'a [u8],
ranges: &'r [MemoryRange],
result: MemoryBufferWithRanges,
) -> Self {
assert!(
result.RangeCount <= ranges.len(),
"TTD returned more memory ranges than the supplied range buffer"
);
Self {
address: result.Address,
memory: validated_memory_slice(buffer, result.Memory),
ranges: &ranges[..result.RangeCount],
}
}
#[inline]
pub fn address(&self) -> GuestAddress { self.address }
#[inline]
pub fn memory(&self) -> &'a [u8] { self.memory }
#[inline]
pub fn ranges(&self) -> &'r [MemoryRange] { self.ranges }
}
fn validated_memory_slice(buffer: &[u8], memory: ConstBufferView) -> &[u8] {
if memory.Size == 0 {
return &buffer[..0];
}
assert!(
!memory.BaseAddress.is_null(),
"TTD returned a null memory pointer with a non-zero size"
);
let buffer_start = buffer.as_ptr() as usize;
let buffer_end = buffer_start
.checked_add(buffer.len())
.expect("host buffer address overflow");
let memory_start = memory.BaseAddress as usize;
let memory_end = memory_start
.checked_add(memory.Size)
.expect("TTD memory view address overflow");
assert!(
memory_start >= buffer_start && memory_end <= buffer_end,
"TTD returned a memory view outside the supplied buffer"
);
unsafe {
slice::from_raw_parts(memory.BaseAddress.cast::<u8>(), memory.Size)
}
}