use bitflags::bitflags;
use libc::{c_int, c_void, MAP_SHARED, _SC_PAGESIZE};
use std::{io, mem::size_of, os::raw::c_ulong, os::unix::io::AsRawFd, ptr::null_mut, result};
use vmm_sys_util::{
fam::{Error as FamError, FamStruct, FamStructWrapper},
generate_fam_struct_impl,
ioctl::{ioctl_expr, _IOC_NONE},
};
#[cfg(not(test))]
use vmm_sys_util::ioctl::ioctl_with_ref;
#[cfg(test)]
use tests::ioctl_with_ref;
use crate::bitmap::{Bitmap, BS};
use crate::guest_memory::{FileOffset, GuestAddress};
use crate::mmap::{check_file_offset, NewBitmap};
use crate::volatile_memory::{self, VolatileMemory, VolatileSlice};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("The specified file offset and length cause overflow when added")]
InvalidOffsetLength,
#[error("The forbidden `MAP_FIXED` flag was specified")]
MapFixed,
#[error("The specified file offset and length is greater then file length")]
MappingPastEof,
#[error("{0}")]
Mmap(io::Error),
#[error("Error seeking the end of the file: {0}")]
SeekEnd(io::Error),
#[error("Error seeking the start of the file: {0}")]
SeekStart(io::Error),
#[error("Invalid file offset")]
InvalidFileOffset,
#[error("Memory mapped in advance")]
MappedInAdvance,
#[error("Invalid Xen Mmap flags: {0:x}")]
MmapFlags(u32),
#[error("Fam error: {0}")]
Fam(FamError),
#[error("Unexpected error")]
UnexpectedError,
}
type Result<T> = result::Result<T, Error>;
#[derive(Clone, Debug)]
pub struct MmapRange {
size: usize,
file_offset: Option<FileOffset>,
prot: Option<i32>,
flags: Option<i32>,
hugetlbfs: Option<bool>,
addr: GuestAddress,
mmap_flags: u32,
mmap_data: u32,
}
impl MmapRange {
pub fn new(
size: usize,
file_offset: Option<FileOffset>,
addr: GuestAddress,
mmap_flags: u32,
mmap_data: u32,
) -> Self {
Self {
size,
file_offset,
prot: None,
flags: None,
hugetlbfs: None,
addr,
mmap_flags,
mmap_data,
}
}
pub fn new_unix(size: usize, file_offset: Option<FileOffset>, addr: GuestAddress) -> Self {
let flags = Some(match file_offset {
Some(_) => libc::MAP_NORESERVE | libc::MAP_SHARED,
None => libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
});
Self {
size,
file_offset,
prot: None,
flags,
hugetlbfs: None,
addr,
mmap_flags: MmapXenFlags::UNIX.bits(),
mmap_data: 0,
}
}
pub fn set_prot(&mut self, prot: i32) {
self.prot = Some(prot)
}
pub fn set_flags(&mut self, flags: i32) {
self.flags = Some(flags)
}
pub fn set_hugetlbfs(&mut self, hugetlbfs: bool) {
self.hugetlbfs = Some(hugetlbfs)
}
}
#[derive(Debug)]
pub struct MmapRegion<B = ()> {
bitmap: B,
size: usize,
prot: i32,
flags: i32,
file_offset: Option<FileOffset>,
hugetlbfs: Option<bool>,
mmap: MmapXen,
}
unsafe impl<B: Send> Send for MmapRegion<B> {}
unsafe impl<B: Sync> Sync for MmapRegion<B> {}
impl<B: NewBitmap> MmapRegion<B> {
pub fn from_range(mut range: MmapRange) -> Result<Self> {
if range.prot.is_none() {
range.prot = Some(libc::PROT_READ | libc::PROT_WRITE);
}
match range.flags {
Some(flags) => {
if flags & libc::MAP_FIXED != 0 {
return Err(Error::MapFixed);
}
}
None => range.flags = Some(libc::MAP_NORESERVE | libc::MAP_SHARED),
}
let mmap = MmapXen::new(&range)?;
Ok(MmapRegion {
bitmap: B::with_len(range.size),
size: range.size,
prot: range.prot.ok_or(Error::UnexpectedError)?,
flags: range.flags.ok_or(Error::UnexpectedError)?,
file_offset: range.file_offset,
hugetlbfs: range.hugetlbfs,
mmap,
})
}
}
impl<B: Bitmap> MmapRegion<B> {
pub fn as_ptr(&self) -> *mut u8 {
self.mmap.addr()
}
pub fn size(&self) -> usize {
self.size
}
pub fn file_offset(&self) -> Option<&FileOffset> {
self.file_offset.as_ref()
}
pub fn prot(&self) -> i32 {
self.prot
}
pub fn flags(&self) -> i32 {
self.flags
}
pub fn fds_overlap<T: Bitmap>(&self, other: &MmapRegion<T>) -> bool {
if let Some(f_off1) = self.file_offset() {
if let Some(f_off2) = other.file_offset() {
if f_off1.file().as_raw_fd() == f_off2.file().as_raw_fd() {
let s1 = f_off1.start();
let s2 = f_off2.start();
let l1 = self.len() as u64;
let l2 = other.len() as u64;
if s1 < s2 {
return s1 + l1 > s2;
} else {
return s2 + l2 > s1;
}
}
}
}
false
}
pub fn set_hugetlbfs(&mut self, hugetlbfs: bool) {
self.hugetlbfs = Some(hugetlbfs)
}
pub fn is_hugetlbfs(&self) -> Option<bool> {
self.hugetlbfs
}
pub fn bitmap(&self) -> &B {
&self.bitmap
}
pub fn xen_mmap_flags(&self) -> u32 {
self.mmap.flags()
}
pub fn xen_mmap_data(&self) -> u32 {
self.mmap.data()
}
}
impl<B: Bitmap> VolatileMemory for MmapRegion<B> {
type B = B;
fn len(&self) -> usize {
self.size
}
fn get_slice(
&self,
offset: usize,
count: usize,
) -> volatile_memory::Result<VolatileSlice<BS<B>>> {
let _ = self.compute_end_offset(offset, count)?;
let mmap_info = if self.mmap.mmap_in_advance() {
None
} else {
Some(&self.mmap)
};
Ok(
unsafe {
VolatileSlice::with_bitmap(
self.as_ptr().add(offset),
count,
self.bitmap.slice_at(offset),
mmap_info,
)
},
)
}
}
#[derive(Clone, Debug, PartialEq)]
struct MmapUnix {
addr: *mut u8,
size: usize,
}
impl MmapUnix {
fn new(size: usize, prot: i32, flags: i32, fd: i32, f_offset: u64) -> Result<Self> {
let addr =
unsafe { libc::mmap(null_mut(), size, prot, flags, fd, f_offset as libc::off_t) };
if addr == libc::MAP_FAILED {
return Err(Error::Mmap(io::Error::last_os_error()));
}
Ok(Self {
addr: addr as *mut u8,
size,
})
}
fn addr(&self) -> *mut u8 {
self.addr
}
}
impl Drop for MmapUnix {
fn drop(&mut self) {
unsafe {
libc::munmap(self.addr as *mut libc::c_void, self.size);
}
}
}
bitflags! {
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MmapXenFlags: u32 {
const UNIX = 0x0;
const FOREIGN = 0x1;
const GRANT = 0x2;
const NO_ADVANCE_MAP = 0x8;
const ALL = Self::FOREIGN.bits() | Self::GRANT.bits();
}
}
impl MmapXenFlags {
pub fn is_valid(&self) -> bool {
if self.is_grant() {
!self.is_foreign()
} else if self.is_foreign() || self.is_unix() {
self.mmap_in_advance()
} else {
false
}
}
pub fn is_unix(&self) -> bool {
self.bits() == Self::UNIX.bits()
}
pub fn is_foreign(&self) -> bool {
self.contains(Self::FOREIGN)
}
pub fn is_grant(&self) -> bool {
self.contains(Self::GRANT)
}
pub fn mmap_in_advance(&self) -> bool {
!self.contains(Self::NO_ADVANCE_MAP)
}
}
fn page_size() -> u64 {
unsafe { libc::sysconf(_SC_PAGESIZE) as u64 }
}
fn pages(size: usize) -> (usize, usize) {
let page_size = page_size() as usize;
let num = size.div_ceil(page_size);
(num, page_size * num)
}
fn validate_file(file_offset: &Option<FileOffset>) -> Result<(i32, u64)> {
let file_offset = match file_offset {
Some(f) => f,
None => return Err(Error::InvalidFileOffset),
};
let fd = file_offset.file().as_raw_fd();
let f_offset = file_offset.start();
if f_offset != 0 {
return Err(Error::InvalidOffsetLength);
}
Ok((fd, f_offset))
}
trait MmapXenTrait: std::fmt::Debug {
fn mmap_slice(&self, addr: *const u8, prot: i32, len: usize) -> Result<MmapXenSlice>;
fn addr(&self) -> *mut u8;
}
#[derive(Clone, Debug, PartialEq)]
struct MmapXenUnix(MmapUnix);
impl MmapXenUnix {
fn new(range: &MmapRange) -> Result<Self> {
let (fd, offset) = if let Some(ref f_off) = range.file_offset {
check_file_offset(f_off, range.size)?;
(f_off.file().as_raw_fd(), f_off.start())
} else {
(-1, 0)
};
Ok(Self(MmapUnix::new(
range.size,
range.prot.ok_or(Error::UnexpectedError)?,
range.flags.ok_or(Error::UnexpectedError)?,
fd,
offset,
)?))
}
}
impl MmapXenTrait for MmapXenUnix {
#[allow(unused_variables)]
fn mmap_slice(&self, addr: *const u8, prot: i32, len: usize) -> Result<MmapXenSlice> {
Err(Error::MappedInAdvance)
}
fn addr(&self) -> *mut u8 {
self.0.addr()
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct PrivCmdMmapBatchV2 {
num: u32,
domid: u16,
addr: *mut c_void,
arr: *const u64,
err: *mut c_int,
}
const XEN_PRIVCMD_TYPE: u32 = 'P' as u32;
fn ioctl_privcmd_mmapbatch_v2() -> c_ulong {
ioctl_expr(
_IOC_NONE,
XEN_PRIVCMD_TYPE,
4,
size_of::<PrivCmdMmapBatchV2>() as u32,
)
}
#[derive(Clone, Debug, PartialEq)]
struct MmapXenForeign {
domid: u32,
guest_base: GuestAddress,
unix_mmap: MmapUnix,
fd: i32,
}
impl AsRawFd for MmapXenForeign {
fn as_raw_fd(&self) -> i32 {
self.fd
}
}
impl MmapXenForeign {
fn new(range: &MmapRange) -> Result<Self> {
let (fd, f_offset) = validate_file(&range.file_offset)?;
let (count, size) = pages(range.size);
let unix_mmap = MmapUnix::new(
size,
range.prot.ok_or(Error::UnexpectedError)?,
range.flags.ok_or(Error::UnexpectedError)? | MAP_SHARED,
fd,
f_offset,
)?;
let foreign = Self {
domid: range.mmap_data,
guest_base: range.addr,
unix_mmap,
fd,
};
foreign.mmap_ioctl(count)?;
Ok(foreign)
}
fn mmap_ioctl(&self, count: usize) -> Result<()> {
let base = self.guest_base.0 / page_size();
let mut pfn = Vec::with_capacity(count);
for i in 0..count {
pfn.push(base + i as u64);
}
let mut err: Vec<c_int> = vec![0; count];
let map = PrivCmdMmapBatchV2 {
num: count as u32,
domid: self.domid as u16,
addr: self.addr() as *mut c_void,
arr: pfn.as_ptr(),
err: err.as_mut_ptr(),
};
let ret = unsafe { ioctl_with_ref(self, ioctl_privcmd_mmapbatch_v2(), &map) };
if ret == 0 {
Ok(())
} else {
Err(Error::Mmap(io::Error::last_os_error()))
}
}
}
impl MmapXenTrait for MmapXenForeign {
#[allow(unused_variables)]
fn mmap_slice(&self, addr: *const u8, prot: i32, len: usize) -> Result<MmapXenSlice> {
Err(Error::MappedInAdvance)
}
fn addr(&self) -> *mut u8 {
self.unix_mmap.addr()
}
}
const XEN_GRANT_ADDR_OFF: u64 = 1 << 63;
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq)]
struct GntDevGrantRef {
domid: u32,
reference: u32,
}
#[repr(C)]
#[derive(Debug, Default, PartialEq, Eq)]
struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
#[inline]
unsafe fn as_ptr(&self) -> *const T {
self as *const __IncompleteArrayField<T> as *const T
}
#[inline]
unsafe fn as_mut_ptr(&mut self) -> *mut T {
self as *mut __IncompleteArrayField<T> as *mut T
}
#[inline]
unsafe fn as_slice(&self, len: usize) -> &[T] {
::std::slice::from_raw_parts(self.as_ptr(), len)
}
#[inline]
unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
}
}
#[repr(C)]
#[derive(Debug, Default)]
struct GntDevMapGrantRef {
count: u32,
pad: u32,
index: u64,
refs: __IncompleteArrayField<GntDevGrantRef>,
}
generate_fam_struct_impl!(
GntDevMapGrantRef,
GntDevGrantRef,
refs,
u32,
count,
usize::MAX
);
type GntDevMapGrantRefWrapper = FamStructWrapper<GntDevMapGrantRef>;
impl GntDevMapGrantRef {
fn new(domid: u32, base: u32, count: usize) -> Result<GntDevMapGrantRefWrapper> {
let mut wrapper = GntDevMapGrantRefWrapper::new(count).map_err(Error::Fam)?;
let refs = wrapper.as_mut_slice();
for (i, r) in refs.iter_mut().enumerate().take(count) {
r.domid = domid;
r.reference = base + i as u32;
}
Ok(wrapper)
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct GntDevUnmapGrantRef {
index: u64,
count: u32,
pad: u32,
}
impl GntDevUnmapGrantRef {
fn new(index: u64, count: u32) -> Self {
Self {
index,
count,
pad: 0,
}
}
}
const XEN_GNTDEV_TYPE: u32 = 'G' as u32;
fn ioctl_gntdev_map_grant_ref() -> c_ulong {
ioctl_expr(
_IOC_NONE,
XEN_GNTDEV_TYPE,
0,
(size_of::<GntDevMapGrantRef>() + size_of::<GntDevGrantRef>()) as u32,
)
}
fn ioctl_gntdev_unmap_grant_ref() -> c_ulong {
ioctl_expr(
_IOC_NONE,
XEN_GNTDEV_TYPE,
1,
size_of::<GntDevUnmapGrantRef>() as u32,
)
}
#[derive(Clone, Debug)]
struct MmapXenGrant {
guest_base: GuestAddress,
unix_mmap: Option<MmapUnix>,
file_offset: FileOffset,
flags: i32,
size: usize,
index: u64,
domid: u32,
}
impl AsRawFd for MmapXenGrant {
fn as_raw_fd(&self) -> i32 {
self.file_offset.file().as_raw_fd()
}
}
impl MmapXenGrant {
fn new(range: &MmapRange, mmap_flags: MmapXenFlags) -> Result<Self> {
validate_file(&range.file_offset)?;
let mut grant = Self {
guest_base: range.addr,
unix_mmap: None,
file_offset: range.file_offset.as_ref().unwrap().clone(),
flags: range.flags.ok_or(Error::UnexpectedError)?,
size: 0,
index: 0,
domid: range.mmap_data,
};
if mmap_flags.mmap_in_advance() {
let (unix_mmap, index) = grant.mmap_range(
range.addr,
range.size,
range.prot.ok_or(Error::UnexpectedError)?,
)?;
grant.unix_mmap = Some(unix_mmap);
grant.index = index;
grant.size = range.size;
}
Ok(grant)
}
fn mmap_range(&self, addr: GuestAddress, size: usize, prot: i32) -> Result<(MmapUnix, u64)> {
let (count, size) = pages(size);
let index = self.mmap_ioctl(addr, count)?;
let unix_mmap = MmapUnix::new(size, prot, self.flags, self.as_raw_fd(), index)?;
Ok((unix_mmap, index))
}
fn unmap_range(&self, unix_mmap: MmapUnix, size: usize, index: u64) {
let (count, _) = pages(size);
drop(unix_mmap);
self.unmap_ioctl(count as u32, index).unwrap();
}
fn mmap_ioctl(&self, addr: GuestAddress, count: usize) -> Result<u64> {
let base = ((addr.0 & !XEN_GRANT_ADDR_OFF) / page_size()) as u32;
let wrapper = GntDevMapGrantRef::new(self.domid, base, count)?;
let reference = wrapper.as_fam_struct_ref();
let ret = unsafe { ioctl_with_ref(self, ioctl_gntdev_map_grant_ref(), reference) };
if ret == 0 {
Ok(reference.index)
} else {
Err(Error::Mmap(io::Error::last_os_error()))
}
}
fn unmap_ioctl(&self, count: u32, index: u64) -> Result<()> {
let unmap = GntDevUnmapGrantRef::new(index, count);
let ret = unsafe { ioctl_with_ref(self, ioctl_gntdev_unmap_grant_ref(), &unmap) };
if ret == 0 {
Ok(())
} else {
Err(Error::Mmap(io::Error::last_os_error()))
}
}
}
impl MmapXenTrait for MmapXenGrant {
fn mmap_slice(&self, addr: *const u8, prot: i32, len: usize) -> Result<MmapXenSlice> {
MmapXenSlice::new_with(self.clone(), addr as usize, prot, len)
}
fn addr(&self) -> *mut u8 {
if let Some(ref unix_mmap) = self.unix_mmap {
unix_mmap.addr()
} else {
null_mut()
}
}
}
impl Drop for MmapXenGrant {
fn drop(&mut self) {
if let Some(unix_mmap) = self.unix_mmap.take() {
self.unmap_range(unix_mmap, self.size, self.index);
}
}
}
#[derive(Debug)]
pub(crate) struct MmapXenSlice {
grant: Option<MmapXenGrant>,
unix_mmap: Option<MmapUnix>,
addr: *mut u8,
size: usize,
index: u64,
}
impl MmapXenSlice {
fn raw(addr: *mut u8) -> Self {
Self {
grant: None,
unix_mmap: None,
addr,
size: 0,
index: 0,
}
}
fn new_with(grant: MmapXenGrant, offset: usize, prot: i32, size: usize) -> Result<Self> {
let page_size = page_size() as usize;
let page_base: usize = (offset / page_size) * page_size;
let offset = offset - page_base;
let size = offset + size;
let addr = grant.guest_base.0 + page_base as u64;
let (unix_mmap, index) = grant.mmap_range(GuestAddress(addr), size, prot)?;
let addr = unsafe { unix_mmap.addr().add(offset) };
Ok(Self {
grant: Some(grant),
unix_mmap: Some(unix_mmap),
addr,
size,
index,
})
}
pub(crate) fn addr(&self) -> *mut u8 {
self.addr
}
}
impl Drop for MmapXenSlice {
fn drop(&mut self) {
if let Some(unix_mmap) = self.unix_mmap.take() {
self.grant
.as_ref()
.unwrap()
.unmap_range(unix_mmap, self.size, self.index);
}
}
}
#[derive(Debug)]
pub struct MmapXen {
xen_flags: MmapXenFlags,
domid: u32,
mmap: Box<dyn MmapXenTrait>,
}
impl MmapXen {
fn new(range: &MmapRange) -> Result<Self> {
let xen_flags = match MmapXenFlags::from_bits(range.mmap_flags) {
Some(flags) => flags,
None => return Err(Error::MmapFlags(range.mmap_flags)),
};
if !xen_flags.is_valid() {
return Err(Error::MmapFlags(xen_flags.bits()));
}
Ok(Self {
xen_flags,
domid: range.mmap_data,
mmap: if xen_flags.is_foreign() {
Box::new(MmapXenForeign::new(range)?)
} else if xen_flags.is_grant() {
Box::new(MmapXenGrant::new(range, xen_flags)?)
} else {
Box::new(MmapXenUnix::new(range)?)
},
})
}
fn addr(&self) -> *mut u8 {
self.mmap.addr()
}
fn flags(&self) -> u32 {
self.xen_flags.bits()
}
fn data(&self) -> u32 {
self.domid
}
fn mmap_in_advance(&self) -> bool {
self.xen_flags.mmap_in_advance()
}
pub(crate) fn mmap(
mmap_xen: Option<&Self>,
addr: *mut u8,
prot: i32,
len: usize,
) -> MmapXenSlice {
match mmap_xen {
Some(mmap_xen) => mmap_xen.mmap.mmap_slice(addr, prot, len).unwrap(),
None => MmapXenSlice::raw(addr),
}
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::undocumented_unsafe_blocks)]
use super::*;
use vmm_sys_util::tempfile::TempFile;
impl Error {
fn raw_os_error(&self) -> i32 {
match self {
Error::Mmap(e) => e.raw_os_error().unwrap(),
_ => i32::MIN,
}
}
}
#[allow(unused_variables)]
pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &T) -> c_int {
0
}
impl MmapRange {
fn initialized(is_file: bool) -> Self {
let file_offset = if is_file {
Some(FileOffset::new(TempFile::new().unwrap().into_file(), 0))
} else {
None
};
let mut range = MmapRange::new_unix(0x1000, file_offset, GuestAddress(0x1000));
range.prot = Some(libc::PROT_READ | libc::PROT_WRITE);
range.mmap_data = 1;
range
}
}
impl MmapRegion {
pub fn new(size: usize) -> Result<Self> {
let range = MmapRange::new_unix(size, None, GuestAddress(0));
Self::from_range(range)
}
}
#[test]
fn test_mmap_xen_failures() {
let mut range = MmapRange::initialized(true);
range.mmap_flags = 16;
let r = MmapXen::new(&range);
assert_eq!(
format!("{:?}", r.unwrap_err()),
format!("MmapFlags({})", range.mmap_flags),
);
range.mmap_flags = MmapXenFlags::FOREIGN.bits() | MmapXenFlags::GRANT.bits();
let r = MmapXen::new(&range);
assert_eq!(
format!("{:?}", r.unwrap_err()),
format!("MmapFlags({:x})", MmapXenFlags::ALL.bits()),
);
range.mmap_flags = MmapXenFlags::FOREIGN.bits() | MmapXenFlags::NO_ADVANCE_MAP.bits();
let r = MmapXen::new(&range);
assert_eq!(
format!("{:?}", r.unwrap_err()),
format!(
"MmapFlags({:x})",
MmapXenFlags::NO_ADVANCE_MAP.bits() | MmapXenFlags::FOREIGN.bits(),
),
);
}
#[test]
fn test_mmap_xen_success() {
let mut range = MmapRange::initialized(true);
range.mmap_flags = MmapXenFlags::FOREIGN.bits();
let r = MmapXen::new(&range).unwrap();
assert_eq!(r.flags(), range.mmap_flags);
assert_eq!(r.data(), range.mmap_data);
assert_ne!(r.addr(), null_mut());
assert!(r.mmap_in_advance());
range.mmap_flags = MmapXenFlags::GRANT.bits();
let r = MmapXen::new(&range).unwrap();
assert_eq!(r.flags(), range.mmap_flags);
assert_eq!(r.data(), range.mmap_data);
assert_ne!(r.addr(), null_mut());
assert!(r.mmap_in_advance());
range.mmap_flags = MmapXenFlags::GRANT.bits() | MmapXenFlags::NO_ADVANCE_MAP.bits();
let r = MmapXen::new(&range).unwrap();
assert_eq!(r.flags(), range.mmap_flags);
assert_eq!(r.data(), range.mmap_data);
assert_eq!(r.addr(), null_mut());
assert!(!r.mmap_in_advance());
}
#[test]
fn test_foreign_map_failure() {
let mut range = MmapRange::initialized(true);
range.file_offset = Some(FileOffset::new(TempFile::new().unwrap().into_file(), 0));
range.prot = None;
let r = MmapXenForeign::new(&range);
assert_eq!(format!("{:?}", r.unwrap_err()), "UnexpectedError");
let mut range = MmapRange::initialized(true);
range.flags = None;
let r = MmapXenForeign::new(&range);
assert_eq!(format!("{:?}", r.unwrap_err()), "UnexpectedError");
let mut range = MmapRange::initialized(true);
range.file_offset = Some(FileOffset::new(TempFile::new().unwrap().into_file(), 1));
let r = MmapXenForeign::new(&range);
assert_eq!(format!("{:?}", r.unwrap_err()), "InvalidOffsetLength");
let mut range = MmapRange::initialized(true);
range.size = 0;
let r = MmapXenForeign::new(&range);
assert_eq!(r.unwrap_err().raw_os_error(), libc::EINVAL);
}
#[test]
fn test_foreign_map_success() {
let range = MmapRange::initialized(true);
let r = MmapXenForeign::new(&range).unwrap();
assert_ne!(r.addr(), null_mut());
assert_eq!(r.domid, range.mmap_data);
assert_eq!(r.guest_base, range.addr);
}
#[test]
fn test_grant_map_failure() {
let mut range = MmapRange::initialized(true);
range.prot = None;
let r = MmapXenGrant::new(&range, MmapXenFlags::empty());
assert_eq!(format!("{:?}", r.unwrap_err()), "UnexpectedError");
let mut range = MmapRange::initialized(true);
range.prot = None;
MmapXenGrant::new(&range, MmapXenFlags::NO_ADVANCE_MAP).unwrap();
let mut range = MmapRange::initialized(true);
range.flags = None;
let r = MmapXenGrant::new(&range, MmapXenFlags::NO_ADVANCE_MAP);
assert_eq!(format!("{:?}", r.unwrap_err()), "UnexpectedError");
let mut range = MmapRange::initialized(true);
range.file_offset = Some(FileOffset::new(TempFile::new().unwrap().into_file(), 1));
let r = MmapXenGrant::new(&range, MmapXenFlags::NO_ADVANCE_MAP);
assert_eq!(format!("{:?}", r.unwrap_err()), "InvalidOffsetLength");
let mut range = MmapRange::initialized(true);
range.size = 0;
let r = MmapXenGrant::new(&range, MmapXenFlags::empty());
assert_eq!(r.unwrap_err().raw_os_error(), libc::EINVAL);
}
#[test]
fn test_grant_map_success() {
let range = MmapRange::initialized(true);
let r = MmapXenGrant::new(&range, MmapXenFlags::NO_ADVANCE_MAP).unwrap();
assert_eq!(r.addr(), null_mut());
assert_eq!(r.domid, range.mmap_data);
assert_eq!(r.guest_base, range.addr);
let mut range = MmapRange::initialized(true);
range.size = 0;
MmapXenGrant::new(&range, MmapXenFlags::NO_ADVANCE_MAP).unwrap();
let range = MmapRange::initialized(true);
let r = MmapXenGrant::new(&range, MmapXenFlags::empty()).unwrap();
assert_ne!(r.addr(), null_mut());
assert_eq!(r.domid, range.mmap_data);
assert_eq!(r.guest_base, range.addr);
}
#[test]
fn test_grant_ref_alloc() {
let wrapper = GntDevMapGrantRef::new(0, 0x1000, 0x100).unwrap();
let r = wrapper.as_fam_struct_ref();
assert_eq!(r.count, 0x100);
assert_eq!(r.pad, 0);
assert_eq!(r.index, 0);
}
}