Skip to content

Commit 9ce7558

Browse files
vireshkjiangliu
authored andcommitted
volatile_memory: Add helpers to copy to/from volatile slice
Add separate helpers to copy from and to the volatile slice. This allows the real logic to be present at a single place, which can be easily updated for special cases later on. For example extra memory mapping for systems where the regions can't be mapped in advance, like in case of Xen's Grant mappings. Signed-off-by: Viresh Kumar <[email protected]>
1 parent f93faad commit 9ce7558

File tree

1 file changed

+63
-44
lines changed

1 file changed

+63
-44
lines changed

src/volatile_memory.rs

Lines changed: 63 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use crate::atomic_integer::AtomicInteger;
3737
use crate::bitmap::{Bitmap, BitmapSlice, BS};
3838
use crate::{AtomicAccess, ByteValued, Bytes};
3939

40-
use copy_slice_impl::copy_slice;
40+
use copy_slice_impl::{copy_from_volatile_slice, copy_to_volatile_slice};
4141

4242
/// `VolatileMemory` related errors.
4343
#[allow(missing_docs)]
@@ -390,7 +390,7 @@ impl<'a, B: BitmapSlice> VolatileSlice<'a, B> {
390390
// a slice and thus has to live outside of guest memory (there can be more slices to
391391
// guest memory without violating rust's aliasing rules)
392392
// - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
393-
unsafe { copy_slice(buf.as_mut_ptr() as *mut u8, self.as_ptr(), total) }
393+
unsafe { copy_from_volatile_slice(buf.as_mut_ptr() as *mut u8, self, total) }
394394
} else {
395395
let count = self.size / size_of::<T>();
396396
let source = self.get_array_ref::<T>(0, count).unwrap();
@@ -468,9 +468,7 @@ impl<'a, B: BitmapSlice> VolatileSlice<'a, B> {
468468
// a slice and thus has to live outside of guest memory (there can be more slices to
469469
// guest memory without violating rust's aliasing rules)
470470
// - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
471-
let count = unsafe { copy_slice(self.as_ptr(), buf.as_ptr() as *const u8, total) };
472-
473-
self.bitmap.mark_dirty(0, count * size_of::<T>());
471+
unsafe { copy_to_volatile_slice(self, buf.as_ptr() as *const u8, total) };
474472
} else {
475473
let count = self.size / size_of::<T>();
476474
// It's ok to use unwrap here because `count` was computed based on the current
@@ -523,22 +521,17 @@ impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
523521
}
524522

525523
let total = buf.len().min(self.len() - addr);
524+
let dst = self.subslice(addr, total)?;
526525

527526
// SAFETY:
528527
// We check above that `addr` is a valid offset within this volatile slice, and by
529528
// the invariants of `VolatileSlice::new`, this volatile slice points to contiguous
530-
// memory of length self.len(). Furthermore, both src and dst of the call to copy_slice
531-
// are valid for reads and writes respectively of length `total` since total is the minimum
532-
// of lengths of the memory areas pointed to. The areas do not overlap, since `dst` is
533-
// inside guest memory, and buf is a slice (no slices to guest memory are possible without
534-
// violating rust's aliasing rules).
535-
let count = unsafe {
536-
let dst = self.as_ptr().add(addr);
537-
copy_slice(dst, buf.as_ptr(), total)
538-
};
539-
540-
self.bitmap.mark_dirty(addr, count);
541-
Ok(count)
529+
// memory of length self.len(). Furthermore, both src and dst of the call to
530+
// copy_to_volatile_slice are valid for reads and writes respectively of length `total`
531+
// since total is the minimum of lengths of the memory areas pointed to. The areas do not
532+
// overlap, since `dst` is inside guest memory, and buf is a slice (no slices to guest
533+
// memory are possible without violating rust's aliasing rules).
534+
Ok(unsafe { copy_to_volatile_slice(&dst, buf.as_ptr(), total) })
542535
}
543536

544537
/// # Examples
@@ -565,19 +558,17 @@ impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
565558
}
566559

567560
let total = buf.len().min(self.len() - addr);
561+
let src = self.subslice(addr, total)?;
568562

569563
// SAFETY:
570564
// We check above that `addr` is a valid offset within this volatile slice, and by
571565
// the invariants of `VolatileSlice::new`, this volatile slice points to contiguous
572-
// memory of length self.len(). Furthermore, both src and dst of the call to copy_slice
573-
// are valid for reads and writes respectively of length `total` since total is the minimum
574-
// of lengths of the memory areas pointed to. The areas do not overlap, since `dst` is
575-
// inside guest memory, and buf is a slice (no slices to guest memory are possible without
576-
// violating rust's aliasing rules).
577-
unsafe {
578-
let src = self.as_ptr().add(addr);
579-
Ok(copy_slice(buf.as_mut_ptr(), src, total))
580-
}
566+
// memory of length self.len(). Furthermore, both src and dst of the call to
567+
// copy_from_volatile_slice are valid for reads and writes respectively of length `total`
568+
// since total is the minimum of lengths of the memory areas pointed to. The areas do not
569+
// overlap, since `dst` is inside guest memory, and buf is a slice (no slices to guest
570+
// memory are possible without violating rust's aliasing rules).
571+
unsafe { Ok(copy_from_volatile_slice(buf.as_mut_ptr(), &src, total)) }
581572
}
582573

583574
/// # Examples
@@ -680,16 +671,13 @@ impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
680671
// Read::read.
681672
assert!(bytes_read <= count);
682673

674+
let slice = self.subslice(addr, bytes_read)?;
675+
683676
// SAFETY: We have checked via compute_end_offset that accessing the specified
684677
// region of guest memory is valid. We asserted that the value returned by `read` is between
685678
// 0 and count (the length of the buffer passed to it), and that the
686679
// regions don't overlap because we allocated the Vec outside of guest memory.
687-
unsafe {
688-
copy_slice(self.as_ptr().add(addr), dst.as_ptr(), bytes_read);
689-
}
690-
691-
self.bitmap.mark_dirty(addr, bytes_read);
692-
Ok(bytes_read)
680+
Ok(unsafe { copy_to_volatile_slice(&slice, dst.as_ptr(), bytes_read) })
693681
}
694682

695683
/// # Examples
@@ -726,14 +714,12 @@ impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
726714
// Read into buffer that can be copied into guest memory
727715
src.read_exact(&mut dst).map_err(Error::IOError)?;
728716

717+
let slice = self.subslice(addr, count)?;
718+
729719
// SAFETY: We have checked via compute_end_offset that accessing the specified
730720
// region of guest memory is valid. We know that `dst` has len `count`, and that the
731721
// regions don't overlap because we allocated the Vec outside of guest memory
732-
unsafe {
733-
copy_slice(self.as_ptr().add(addr), dst.as_ptr(), count);
734-
}
735-
736-
self.bitmap.mark_dirty(addr, count);
722+
unsafe { copy_to_volatile_slice(&slice, dst.as_ptr(), count) };
737723
Ok(())
738724
}
739725

@@ -765,14 +751,17 @@ impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
765751
{
766752
let _ = self.compute_end_offset(addr, count)?;
767753
let mut src = Vec::with_capacity(count);
754+
755+
let slice = self.subslice(addr, count)?;
756+
768757
// SAFETY: We checked the addr and count so accessing the slice is safe.
769758
// It is safe to read from volatile memory. The Vec has capacity for exactly `count`
770759
// many bytes, and the memory regions pointed to definitely do not overlap, as we
771760
// allocated src outside of guest memory.
772761
// The call to set_len is safe because the bytes between 0 and count have been initialized
773762
// via copying from guest memory, and the Vec's capacity is `count`
774763
unsafe {
775-
copy_slice(src.as_mut_ptr(), self.as_ptr().add(addr), count);
764+
copy_from_volatile_slice(src.as_mut_ptr(), &slice, count);
776765
src.set_len(count);
777766
}
778767

@@ -814,14 +803,16 @@ impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
814803
let _ = self.compute_end_offset(addr, count)?;
815804
let mut src = Vec::with_capacity(count);
816805

806+
let slice = self.subslice(addr, count)?;
807+
817808
// SAFETY: We checked the addr and count so accessing the slice is safe.
818809
// It is safe to read from volatile memory. The Vec has capacity for exactly `count`
819810
// many bytes, and the memory regions pointed to definitely do not overlap, as we
820811
// allocated src outside of guest memory.
821812
// The call to set_len is safe because the bytes between 0 and count have been initialized
822813
// via copying from guest memory, and the Vec's capacity is `count`
823814
unsafe {
824-
copy_slice(src.as_mut_ptr(), self.as_ptr().add(addr), count);
815+
copy_from_volatile_slice(src.as_mut_ptr(), &slice, count);
825816
src.set_len(count);
826817
}
827818

@@ -1176,7 +1167,9 @@ where
11761167
// a slice and thus has to live outside of guest memory (there can be more slices to
11771168
// guest memory without violating rust's aliasing rules)
11781169
// - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
1179-
return unsafe { copy_slice(buf.as_mut_ptr() as *mut u8, source.as_ptr(), total) };
1170+
return unsafe {
1171+
copy_from_volatile_slice(buf.as_mut_ptr() as *mut u8, &source, total)
1172+
};
11801173
}
11811174

11821175
let mut addr = self.addr;
@@ -1253,16 +1246,14 @@ where
12531246
let total = buf.len().min(destination.len());
12541247

12551248
// absurd formatting brought to you by clippy
1256-
let count =
12571249
// SAFETY:
12581250
// - dst is valid for writes of at least `total`, since total <= destination.len()
12591251
// - src is valid for reads of at least `total` as total <= buf.len()
12601252
// - The regions are non-overlapping as `dst` points to guest memory and `buf` is
12611253
// a slice and thus has to live outside of guest memory (there can be more slices to
12621254
// guest memory without violating rust's aliasing rules)
12631255
// - size is always a multiple of alignment, so treating *const T as *const u8 is fine
1264-
unsafe { copy_slice(destination.as_ptr(), buf.as_ptr() as *const u8, total) };
1265-
self.bitmap.mark_dirty(0, count);
1256+
unsafe { copy_to_volatile_slice(&destination, buf.as_ptr() as *const u8, total) };
12661257
} else {
12671258
let mut addr = self.addr;
12681259
for &v in buf.iter().take(self.len()) {
@@ -1371,7 +1362,7 @@ mod copy_slice_impl {
13711362
///
13721363
/// SAFETY: `src` and `dst` must be point to a contiguously allocated memory region of at least
13731364
/// length `total`. The regions must not overlap
1374-
pub(super) unsafe fn copy_slice(dst: *mut u8, src: *const u8, total: usize) -> usize {
1365+
unsafe fn copy_slice(dst: *mut u8, src: *const u8, total: usize) -> usize {
13751366
if total <= size_of::<usize>() {
13761367
// SAFETY: Invariants of copy_slice_volatile are the same as invariants of copy_slice
13771368
unsafe {
@@ -1390,6 +1381,34 @@ mod copy_slice_impl {
13901381

13911382
total
13921383
}
1384+
1385+
/// Copies `total` bytes from `slice` to `dst`
1386+
///
1387+
/// SAFETY: `slice` and `dst` must be point to a contiguously allocated memory region of at
1388+
/// least length `total`. The regions must not overlap.
1389+
pub(super) unsafe fn copy_from_volatile_slice<B: BitmapSlice>(
1390+
dst: *mut u8,
1391+
slice: &VolatileSlice<'_, B>,
1392+
total: usize,
1393+
) -> usize {
1394+
// SAFETY: guaranteed by function invariants.
1395+
copy_slice(dst, slice.as_ptr(), total)
1396+
}
1397+
1398+
/// Copies `total` bytes from 'src' to `slice`
1399+
///
1400+
/// SAFETY: `slice` and `src` must be point to a contiguously allocated memory region of at
1401+
/// least length `total`. The regions must not overlap.
1402+
pub(super) unsafe fn copy_to_volatile_slice<B: BitmapSlice>(
1403+
slice: &VolatileSlice<'_, B>,
1404+
src: *const u8,
1405+
total: usize,
1406+
) -> usize {
1407+
// SAFETY: guaranteed by function invariants.
1408+
let count = copy_slice(slice.as_ptr(), src, total);
1409+
slice.bitmap.mark_dirty(0, count);
1410+
count
1411+
}
13931412
}
13941413

13951414
#[cfg(test)]

0 commit comments

Comments
 (0)