Add map_mmio to rust bindings

This commit is contained in:
Sven Bartscher
2021-11-17 18:35:30 +01:00
parent 78e0ddbc4d
commit 20d97a0c00
3 changed files with 242 additions and 0 deletions

View File

@ -81,6 +81,8 @@ pub struct UnicornInner<'a, D> {
pub arch: Arch,
/// to keep ownership over the hook for this uc instance's lifetime
pub hooks: Vec<(ffi::uc_hook, Box<dyn ffi::IsUcHook<'a> + 'a>)>,
/// To keep ownership over the mmio callbacks for this uc instance's lifetime
pub mmio_callbacks: Vec<(Option<Box<dyn ffi::IsUcHook<'a> + 'a>>, Option<Box<dyn ffi::IsUcHook<'a> + 'a>>)>,
pub data: D,
}
@ -123,6 +125,7 @@ where
arch,
data,
hooks: vec![],
mmio_callbacks: vec![],
})),
})
} else {
@ -262,6 +265,99 @@ impl<'a, D> Unicorn<'a, D> {
}
}
/// Map in am MMIO region backed by callbacks.
///
/// `address` must be aligned to 4kb or this will return `Error::ARG`.
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
pub fn mmio_map<R: 'a, W: 'a>(
&mut self,
address: u64,
size: libc::size_t,
read_callback: Option<R>,
write_callback: Option<W>,
) -> Result<(), uc_error>
where
R: FnMut(&mut Unicorn<D>, u64, usize) -> u64,
W: FnMut(&mut Unicorn<D>, u64, usize, u64),
{
let mut read_data = read_callback.map( |c| {
Box::new(ffi::UcHook {
callback: c,
uc: Unicorn {
inner: self.inner.clone(),
},
})
});
let mut write_data = write_callback.map( |c| {
Box::new(ffi::UcHook {
callback: c,
uc: Unicorn {
inner: self.inner.clone(),
},
})
});
let err = unsafe {
ffi::uc_mmio_map(
self.inner().uc,
address,
size,
ffi::mmio_read_callback_proxy::<D, R> as _,
match read_data {
Some(ref mut d) => d.as_mut() as *mut _ as _,
None => ptr::null_mut(),
},
ffi::mmio_write_callback_proxy::<D, W> as _,
match write_data {
Some(ref mut d) => d.as_mut() as *mut _ as _,
None => ptr::null_mut(),
},
)
};
if err == uc_error::OK {
let rd = read_data.map( |c| c as Box<dyn ffi::IsUcHook> );
let wd = write_data.map( |c| c as Box<dyn ffi::IsUcHook> );
self.inner_mut().mmio_callbacks.push((rd, wd));
Ok(())
} else {
Err(err)
}
}
/// Map in a read-only MMIO region backed by a callback.
///
/// `address` must be aligned to 4kb or this will return `Error::ARG`.
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
pub fn mmio_map_ro<F: 'a>(
&mut self,
address: u64,
size: libc::size_t,
callback: F,
) -> Result<(), uc_error>
where
F: FnMut(&mut Unicorn<D>, u64, usize) -> u64,
{
self.mmio_map(address, size, Some(callback), None::<fn(&mut Unicorn<D>, u64, usize, u64)>)
}
/// Map in a write-only MMIO region backed by a callback.
///
/// `address` must be aligned to 4kb or this will return `Error::ARG`.
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
pub fn mmio_map_wo<F: 'a>(
&mut self,
address: u64,
size: libc::size_t,
callback: F,
) -> Result<(), uc_error>
where
F: FnMut(&mut Unicorn<D>, u64, usize, u64),
{
self.mmio_map(address, size, None::<fn(&mut Unicorn<D>, u64, usize) -> u64>, Some(callback))
}
/// Unmap a memory region.
///
/// `address` must be aligned to 4kb or this will return `Error::ARG`.