use arrayvec::ArrayVec;
use serde::{Deserialize, Serialize};
pub const MEMORY_REGION_IDENTIFIER: u8 = 0x01;
#[cfg(feature = "std")]
pub trait MemoryRegion {
fn range(&self) -> std::ops::Range<u64>;
fn read(
&self,
address_range: core::ops::Range<u64>,
) -> Result<Option<Vec<u8>>, crate::device_memory::MemoryReadError>;
fn read_u8(&self, address: u64) -> Result<Option<u8>, crate::device_memory::MemoryReadError> {
Ok(self.read(address..address + 1)?.map(|b| b[0]))
}
fn read_u32(
&self,
address: u64,
endianness: gimli::RunTimeEndian,
) -> Result<Option<u32>, crate::device_memory::MemoryReadError> {
if let Some(slice) = self
.read(address..address + 4)?
.map(|slice| slice[..].try_into().unwrap())
{
if gimli::Endianity::is_little_endian(endianness) {
Ok(Some(u32::from_le_bytes(slice)))
} else {
Ok(Some(u32::from_be_bytes(slice)))
}
} else {
Ok(None)
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
pub struct ArrayMemoryRegion<const SIZE: usize> {
start_address: u64,
data: ArrayVec<u8, SIZE>,
}
impl<const SIZE: usize> ArrayMemoryRegion<SIZE> {
pub fn new(start_address: u64, data: ArrayVec<u8, SIZE>) -> Self {
Self {
start_address,
data,
}
}
pub fn bytes(&self) -> MemoryRegionIterator<'_> {
MemoryRegionIterator::new(self.start_address, &self.data)
}
pub unsafe fn copy_from_memory(&mut self, data_ptr: *const u8, data_len: usize) {
self.start_address = data_ptr as u64;
self.data.clear();
assert!(data_len <= self.data.capacity());
self.data.set_len(data_len);
self.data.as_mut_ptr().copy_from(data_ptr, data_len);
}
}
#[cfg(feature = "std")]
impl<const SIZE: usize> MemoryRegion for ArrayMemoryRegion<SIZE> {
fn range(&self) -> std::ops::Range<u64> {
self.start_address..self.start_address + self.data.len() as u64
}
fn read(
&self,
index: core::ops::Range<u64>,
) -> Result<Option<Vec<u8>>, crate::device_memory::MemoryReadError> {
let start = match index.start.checked_sub(self.start_address) {
Some(start) => start,
None => return Ok(None),
};
let end = match index.end.checked_sub(self.start_address) {
Some(end) => end,
None => return Ok(None),
};
Ok(self
.data
.get(start as usize..end as usize)
.map(|slice| slice.to_vec()))
}
}
impl<'a, const SIZE: usize> FromIterator<&'a u8> for ArrayMemoryRegion<SIZE> {
fn from_iter<T: IntoIterator<Item = &'a u8>>(iter: T) -> Self {
Self::from_iter(iter.into_iter().copied())
}
}
impl<const SIZE: usize> FromIterator<u8> for ArrayMemoryRegion<SIZE> {
fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
let mut iter = iter.into_iter();
assert_eq!(
iter.next().unwrap(),
MEMORY_REGION_IDENTIFIER,
"The given iterator is not for a memory region"
);
let start_address = u64::from_le_bytes([
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
]);
let length = u64::from_le_bytes([
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
]);
let data = ArrayVec::from_iter(iter.take(length as usize));
Self {
start_address,
data,
}
}
}
#[cfg(feature = "std")]
#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
pub struct VecMemoryRegion {
start_address: u64,
data: Vec<u8>,
}
#[cfg(feature = "std")]
impl VecMemoryRegion {
pub fn new(start_address: u64, data: Vec<u8>) -> Self {
Self {
start_address,
data,
}
}
pub fn bytes(&self) -> MemoryRegionIterator<'_> {
MemoryRegionIterator::new(self.start_address, &self.data)
}
pub unsafe fn copy_from_memory(&mut self, data_ptr: *const u8, data_len: usize) {
self.start_address = data_ptr as u64;
self.data.clear();
self.data.resize(data_len, 0);
self.data.as_mut_ptr().copy_from(data_ptr, data_len);
}
}
#[cfg(feature = "std")]
impl MemoryRegion for VecMemoryRegion {
fn range(&self) -> std::ops::Range<u64> {
self.start_address..self.start_address + self.data.len() as u64
}
fn read(
&self,
index: core::ops::Range<u64>,
) -> Result<Option<Vec<u8>>, crate::device_memory::MemoryReadError> {
let start = match index.start.checked_sub(self.start_address) {
Some(start) => start,
None => return Ok(None),
};
let end = match index.end.checked_sub(self.start_address) {
Some(end) => end,
None => return Ok(None),
};
Ok(self
.data
.get(start as usize..end as usize)
.map(|slice| slice.to_vec()))
}
}
#[cfg(feature = "std")]
impl<'a> FromIterator<&'a u8> for VecMemoryRegion {
fn from_iter<T: IntoIterator<Item = &'a u8>>(iter: T) -> Self {
Self::from_iter(iter.into_iter().copied())
}
}
#[cfg(feature = "std")]
impl FromIterator<u8> for VecMemoryRegion {
fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
let mut iter = iter.into_iter();
assert_eq!(
iter.next().unwrap(),
MEMORY_REGION_IDENTIFIER,
"The given iterator is not for a memory region"
);
let start_address = u64::from_le_bytes([
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
]);
let length = u64::from_le_bytes([
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
]);
let data = Vec::from_iter(iter.take(length as usize));
Self {
start_address,
data,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
pub struct SliceMemoryRegion<'a> {
data: &'a [u8],
}
impl<'a> SliceMemoryRegion<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data }
}
pub fn bytes(&self) -> MemoryRegionIterator<'_> {
let start_address = self.data.as_ptr() as u64;
MemoryRegionIterator::new(start_address, self.data)
}
pub unsafe fn copy_from_memory(&mut self, data_ptr: *const u8, data_len: usize) {
self.data = core::slice::from_raw_parts(data_ptr, data_len);
}
}
#[cfg(feature = "std")]
impl<'a> MemoryRegion for SliceMemoryRegion<'a> {
fn range(&self) -> std::ops::Range<u64> {
let range = self.data.as_ptr_range();
range.start as u64..range.end as u64
}
fn read(
&self,
index: core::ops::Range<u64>,
) -> Result<Option<Vec<u8>>, crate::device_memory::MemoryReadError> {
let start_address = self.data.as_ptr() as u64;
let start = match index.start.checked_sub(start_address) {
Some(start) => start,
None => return Ok(None),
};
let end = match index.end.checked_sub(start_address) {
Some(end) => end,
None => return Ok(None),
};
Ok(self
.data
.get(start as usize..end as usize)
.map(|slice| slice.to_vec()))
}
}
pub struct MemoryRegionIterator<'a> {
start_address: u64,
data: &'a [u8],
index: usize,
}
impl<'a> MemoryRegionIterator<'a> {
fn new(start_address: u64, data: &'a [u8]) -> Self {
Self {
start_address,
data,
index: 0,
}
}
}
impl<'a> Iterator for MemoryRegionIterator<'a> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
match self.index {
0 => {
self.index += 1;
Some(MEMORY_REGION_IDENTIFIER)
}
index @ 1..=8 => {
self.index += 1;
Some(self.start_address.to_le_bytes()[index - 1])
}
index @ 9..=16 => {
self.index += 1;
Some((self.data.len() as u64).to_le_bytes()[index - 9])
}
index => {
self.index += 1;
self.data.get(index - 17).copied()
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining_length = 17 + self.data.len() - self.index;
(remaining_length, Some(remaining_length))
}
}
impl<'a> ExactSizeIterator for MemoryRegionIterator<'a> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn iterator() {
let region = VecMemoryRegion::new(0x2000_0000, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
let copied_region = VecMemoryRegion::from_iter(region.bytes());
assert_eq!(region, copied_region);
}
#[test]
fn iterator_len() {
let region = VecMemoryRegion::new(0x2000_0000, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
let iter = region.bytes();
assert_eq!(iter.len(), iter.count());
let mut iter = region.bytes();
iter.nth(10).unwrap();
assert_eq!(iter.len(), iter.count());
}
}