Skip to content

I/O virtual memory (IOMMU) support #327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
74 changes: 60 additions & 14 deletions src/guest_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
use std::convert::From;
use std::fs::File;
use std::io;
use std::mem::size_of;
use std::ops::{BitAnd, BitOr, Deref};
use std::rc::Rc;
use std::sync::atomic::Ordering;
Expand Down Expand Up @@ -374,9 +375,9 @@ pub trait GuestMemory {
/// - the error code returned by the callback 'f'
/// - the size of the already handled data when encountering the first hole
/// - the size of the already handled data when the whole range has been handled
fn try_access<F>(&self, count: usize, addr: GuestAddress, mut f: F) -> Result<usize>
fn try_access<'a, F>(&'a self, count: usize, addr: GuestAddress, mut f: F) -> Result<usize>
where
F: FnMut(usize, usize, MemoryRegionAddress, &Self::R) -> Result<usize>,
F: FnMut(usize, usize, MemoryRegionAddress, &'a Self::R) -> Result<usize>,
{
let mut cur = addr;
let mut total = 0;
Expand Down Expand Up @@ -464,8 +465,8 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
self.try_access(
buf.len(),
addr,
|offset, _count, caddr, region| -> Result<usize> {
region.write(&buf[offset..], caddr)
|offset, count, caddr, region| -> Result<usize> {
region.write(&buf[offset..(offset + count)], caddr)
},
)
}
Expand All @@ -474,8 +475,8 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
self.try_access(
buf.len(),
addr,
|offset, _count, caddr, region| -> Result<usize> {
region.read(&mut buf[offset..], caddr)
|offset, count, caddr, region| -> Result<usize> {
region.read(&mut buf[offset..(offset + count)], caddr)
},
)
}
Expand Down Expand Up @@ -591,17 +592,62 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
}

fn store<O: AtomicAccess>(&self, val: O, addr: GuestAddress, order: Ordering) -> Result<()> {
// `find_region` should really do what `to_region_addr` is doing right now, except
// it should keep returning a `Result`.
self.to_region_addr(addr)
.ok_or(Error::InvalidGuestAddress(addr))
.and_then(|(region, region_addr)| region.store(val, region_addr, order))
let expected = size_of::<O>();

let completed = self.try_access(
expected,
addr,
|offset, len, region_addr, region| -> Result<usize> {
assert_eq!(offset, 0);
if len < expected {
return Err(Error::PartialBuffer {
expected,
completed: len,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

completed should be 0, since you didn't read anything. So here you could also return Ok(0) ("no more data") and let the if below return Error::PartialBuffer.

});
}
region.store(val, region_addr, order).map(|()| expected)
},
)?;

if completed < expected {
Err(Error::PartialBuffer {
expected,
completed,
})
} else {
Ok(())
}
}

fn load<O: AtomicAccess>(&self, addr: GuestAddress, order: Ordering) -> Result<O> {
self.to_region_addr(addr)
.ok_or(Error::InvalidGuestAddress(addr))
.and_then(|(region, region_addr)| region.load(region_addr, order))
let expected = size_of::<O>();
let mut result = None::<O>;

let completed = self.try_access(
expected,
addr,
|offset, len, region_addr, region| -> Result<usize> {
assert_eq!(offset, 0);
if len < expected {
return Err(Error::PartialBuffer {
expected,
completed: len,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

});
}
result = Some(region.load(region_addr, order)?);
Ok(expected)
},
)?;

if completed < expected {
Err(Error::PartialBuffer {
expected,
completed,
})
} else {
// Must be set because `completed == expected`
Ok(result.unwrap())
}
}
}

Expand Down