Skip to content

Commit 57b1543

Browse files
committed
Implement Bytes on IoMemory instead of GuestMemory
Rust only allows us to give one trait the blanket implementations for `Bytes`. We want `IoMemory` to be our primary external interface becaue it has users specify the access permissions they need, and because we can (and do) provide a blanket `IoMemory` implementation for all `GuestMemory` types. Also, while `IoMemory` (as the more general trait) only has a restricted interface when compared to `GuestMemory`, this interface is enough to implement `Bytes`; notably, accesses to `IoMemory` require specifying the access mode, which is naturally trivial for `Bytes` methods like `read()` or `write()`. Signed-off-by: Hanna Czenczek <[email protected]>
1 parent 07e9bf8 commit 57b1543

File tree

1 file changed

+27
-12
lines changed

1 file changed

+27
-12
lines changed

src/guest_memory.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use crate::bitmap::MS;
5656
use crate::bytes::{AtomicAccess, Bytes};
5757
use crate::io::{ReadVolatile, WriteVolatile};
5858
use crate::volatile_memory::{self, VolatileSlice};
59-
use crate::GuestMemoryRegion;
59+
use crate::{GuestMemoryRegion, IoMemory, Permissions};
6060

6161
/// Errors associated with handling guest memory accesses.
6262
#[allow(missing_docs)]
@@ -552,13 +552,19 @@ impl<'a, M: GuestMemory + ?Sized> Iterator for GuestMemorySliceIterator<'a, M> {
552552
/// returning `None`, ensuring that it will only return `None` from that point on.
553553
impl<M: GuestMemory + ?Sized> FusedIterator for GuestMemorySliceIterator<'_, M> {}
554554

555-
impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
555+
/// Allow accessing [`IoMemory`] (and [`GuestMemory`]) objects via [`Bytes`].
556+
///
557+
/// Thanks to the [blanket implementation of `IoMemory` for all `GuestMemory`
558+
/// types](../io_memory/trait.IoMemory.html#impl-IoMemory-for-M), this blanket implementation
559+
/// extends to all [`GuestMemory`] types.
560+
impl<T: IoMemory + ?Sized> Bytes<GuestAddress> for T {
556561
type E = Error;
557562

558563
fn write(&self, buf: &[u8], addr: GuestAddress) -> Result<usize> {
559564
self.try_access(
560565
buf.len(),
561566
addr,
567+
Permissions::Write,
562568
|offset, count, caddr, region| -> Result<usize> {
563569
region.write(&buf[offset..(offset + count)], caddr)
564570
},
@@ -569,6 +575,7 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
569575
self.try_access(
570576
buf.len(),
571577
addr,
578+
Permissions::Read,
572579
|offset, count, caddr, region| -> Result<usize> {
573580
region.read(&mut buf[offset..(offset + count)], caddr)
574581
},
@@ -636,9 +643,12 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
636643
where
637644
F: ReadVolatile,
638645
{
639-
self.try_access(count, addr, |_, len, caddr, region| -> Result<usize> {
640-
region.read_volatile_from(caddr, src, len)
641-
})
646+
self.try_access(
647+
count,
648+
addr,
649+
Permissions::Write,
650+
|_, len, caddr, region| -> Result<usize> { region.read_volatile_from(caddr, src, len) },
651+
)
642652
}
643653

644654
fn read_exact_volatile_from<F>(
@@ -664,11 +674,16 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
664674
where
665675
F: WriteVolatile,
666676
{
667-
self.try_access(count, addr, |_, len, caddr, region| -> Result<usize> {
668-
// For a non-RAM region, reading could have side effects, so we
669-
// must use write_all().
670-
region.write_all_volatile_to(caddr, dst, len).map(|()| len)
671-
})
677+
self.try_access(
678+
count,
679+
addr,
680+
Permissions::Read,
681+
|_, len, caddr, region| -> Result<usize> {
682+
// For a non-RAM region, reading could have side effects, so we
683+
// must use write_all().
684+
region.write_all_volatile_to(caddr, dst, len).map(|()| len)
685+
},
686+
)
672687
}
673688

674689
fn write_all_volatile_to<F>(&self, addr: GuestAddress, dst: &mut F, count: usize) -> Result<()>
@@ -688,7 +703,7 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
688703
fn store<O: AtomicAccess>(&self, val: O, addr: GuestAddress, order: Ordering) -> Result<()> {
689704
// No need to check past the first iterator item: It either has the size of `O`, then there
690705
// can be no further items; or it does not, and then `VolatileSlice::store()` will fail.
691-
self.get_slices(addr, size_of::<O>())
706+
self.get_slices(addr, size_of::<O>(), Permissions::Write)?
692707
.next()
693708
.unwrap()? // count > 0 never produces an empty iterator
694709
.store(val, 0, order)
@@ -698,7 +713,7 @@ impl<T: GuestMemory + ?Sized> Bytes<GuestAddress> for T {
698713
fn load<O: AtomicAccess>(&self, addr: GuestAddress, order: Ordering) -> Result<O> {
699714
// No need to check past the first iterator item: It either has the size of `O`, then there
700715
// can be no further items; or it does not, and then `VolatileSlice::store()` will fail.
701-
self.get_slices(addr, size_of::<O>())
716+
self.get_slices(addr, size_of::<O>(), Permissions::Read)?
702717
.next()
703718
.unwrap()? // count > 0 never produces an empty iterator
704719
.load(0, order)

0 commit comments

Comments
 (0)