Skip to content

Commit 8d0147d

Browse files
tkreuzerjiangliu
authored andcommitted
Port the mmap backend to windows
This moves the Unix specific parts of the mmap module into mmap-unix.rs and adds mmap-windows.rs, containing the Windows implementation. The Windows implementation uses VirtualAlloc, VirtualFree, CreateFileMappingA and MapViewOfFile to provide the same functionality as on Unix. The external dependencies are defined in the same file, avoiding additional crate dependencies. Signed-off-by: Timo Kreuzer <[email protected]>
1 parent 08b24bf commit 8d0147d

File tree

7 files changed

+468
-152
lines changed

7 files changed

+468
-152
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ For a typical hypervisor, there are seveval components, such as boot loader, vir
55

66
## Platform Support
77
- Arch: x86, AMD64, ARM64
8-
- OS: Linux/Unix
8+
- OS: Linux/Unix/Windows
99

1010
## Usage
1111
First, add the following to your `Cargo.toml`:

TODO.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
### TODO List
22
- Abstraction layer to seperate VM memory management from VM memory accessor.
33
- Help needed to refine documentation and usage examples.
4-
- Support of Windows OS.

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ pub use guest_memory::{
3939
MemoryRegionAddress, Result as GuestMemoryResult,
4040
};
4141

42+
#[cfg(all(feature = "backend-mmap", unix))]
43+
mod mmap_unix;
44+
45+
#[cfg(all(feature = "backend-mmap", windows))]
46+
mod mmap_windows;
47+
4248
#[cfg(feature = "backend-mmap")]
4349
pub mod mmap;
4450
#[cfg(feature = "backend-mmap")]

src/mmap.rs

Lines changed: 52 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,27 @@
2020
//! - [GuestMemoryMmap](struct.GuestMemoryMmap.html): provides methods to access a collection of
2121
//! GuestRegionMmap objects.
2222
23-
use libc;
2423
use std::io::{self, Read, Write};
2524
use std::ops::Deref;
26-
use std::os::unix::io::AsRawFd;
27-
use std::ptr::null_mut;
2825
use std::sync::Arc;
2926

3027
use address::Address;
3128
use guest_memory::*;
32-
use volatile_memory::{self, compute_offset, VolatileMemory, VolatileSlice};
29+
use volatile_memory::VolatileMemory;
3330
use Bytes;
3431

35-
/// A backend driver to access guest's physical memory by mmapping guest's memory into the current
36-
/// process.
37-
/// For a combination of 32-bit hypervisor and 64-bit virtual machine, only partial of guest's
38-
/// physical memory may be mapped into current process due to limited process virtual address
39-
/// space size.
40-
#[derive(Debug)]
41-
pub struct MmapRegion {
42-
addr: *mut u8,
43-
size: usize,
32+
#[cfg(unix)]
33+
pub use mmap_unix::MmapRegion;
34+
35+
#[cfg(windows)]
36+
pub use mmap_windows::MmapRegion;
37+
38+
// For MmapRegion
39+
pub(crate) trait AsSlice {
40+
unsafe fn as_slice(&self) -> &[u8];
41+
42+
#[allow(clippy::mut_from_ref)]
43+
unsafe fn as_mut_slice(&self) -> &mut [u8];
4444
}
4545

4646
/// Errors that can happen when creating a memory map
@@ -54,116 +54,6 @@ pub enum MmapError {
5454
MemoryRegionOverlap,
5555
}
5656

57-
// Send and Sync aren't automatically inherited for the raw address pointer.
58-
// Accessing that pointer is only done through the stateless interface which
59-
// allows the object to be shared by multiple threads without a decrease in
60-
// safety.
61-
unsafe impl Send for MmapRegion {}
62-
unsafe impl Sync for MmapRegion {}
63-
64-
impl MmapRegion {
65-
/// Creates an anonymous shared mapping of `size` bytes.
66-
///
67-
/// # Arguments
68-
/// * `size` - Size of memory region in bytes.
69-
pub fn new(size: usize) -> io::Result<Self> {
70-
// This is safe because we are creating an anonymous mapping in a place not already used by
71-
// any other area in this process.
72-
let addr = unsafe {
73-
libc::mmap(
74-
null_mut(),
75-
size,
76-
libc::PROT_READ | libc::PROT_WRITE,
77-
libc::MAP_ANONYMOUS | libc::MAP_SHARED | libc::MAP_NORESERVE,
78-
-1,
79-
0,
80-
)
81-
};
82-
if addr == libc::MAP_FAILED {
83-
return Err(io::Error::last_os_error());
84-
}
85-
Ok(Self {
86-
addr: addr as *mut u8,
87-
size,
88-
})
89-
}
90-
91-
/// Maps the `size` bytes starting at `offset` bytes of the given `fd`.
92-
///
93-
/// # Arguments
94-
/// * `fd` - File descriptor to mmap from.
95-
/// * `size` - Size of memory region in bytes.
96-
/// * `offset` - Offset in bytes from the beginning of `fd` to start the mmap.
97-
pub fn from_fd(fd: &AsRawFd, size: usize, offset: libc::off_t) -> io::Result<Self> {
98-
// This is safe because we are creating a mapping in a place not already used by any other
99-
// area in this process.
100-
let addr = unsafe {
101-
libc::mmap(
102-
null_mut(),
103-
size,
104-
libc::PROT_READ | libc::PROT_WRITE,
105-
libc::MAP_SHARED,
106-
fd.as_raw_fd(),
107-
offset,
108-
)
109-
};
110-
if addr == libc::MAP_FAILED {
111-
return Err(io::Error::last_os_error());
112-
}
113-
Ok(Self {
114-
addr: addr as *mut u8,
115-
size,
116-
})
117-
}
118-
119-
/// Returns a pointer to the beginning of the memory region. Should only be
120-
/// used for passing this region to ioctls for setting guest memory.
121-
pub fn as_ptr(&self) -> *mut u8 {
122-
self.addr
123-
}
124-
125-
unsafe fn as_slice(&self) -> &[u8] {
126-
// This is safe because we mapped the area at addr ourselves, so this slice will not
127-
// overflow. However, it is possible to alias.
128-
std::slice::from_raw_parts(self.addr, self.size)
129-
}
130-
131-
// safe because it's expected interior mutability
132-
#[allow(clippy::mut_from_ref)]
133-
unsafe fn as_mut_slice(&self) -> &mut [u8] {
134-
// This is safe because we mapped the area at addr ourselves, so this slice will not
135-
// overflow. However, it is possible to alias.
136-
std::slice::from_raw_parts_mut(self.addr, self.size)
137-
}
138-
}
139-
140-
impl VolatileMemory for MmapRegion {
141-
fn len(&self) -> usize {
142-
self.size
143-
}
144-
145-
fn get_slice(&self, offset: usize, count: usize) -> volatile_memory::Result<VolatileSlice> {
146-
let end = compute_offset(offset, count)?;
147-
if end > self.size {
148-
return Err(volatile_memory::Error::OutOfBounds { addr: end });
149-
}
150-
151-
// Safe because we checked that offset + count was within our range and we only ever hand
152-
// out volatile accessors.
153-
Ok(unsafe { VolatileSlice::new((self.addr as usize + offset) as *mut _, count) })
154-
}
155-
}
156-
157-
impl Drop for MmapRegion {
158-
fn drop(&mut self) {
159-
// This is safe because we mmap the area at addr ourselves, and nobody
160-
// else is holding a reference to it.
161-
unsafe {
162-
libc::munmap(self.addr as *mut libc::c_void, self.size);
163-
}
164-
}
165-
}
166-
16757
/// Tracks a mapping of memory in the current process and the corresponding base address
16858
/// in the guest's memory space.
16959
#[derive(Debug)]
@@ -262,7 +152,11 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
262152
/// # use std::path::Path;
263153
/// # let start_addr = GuestAddress(0x1000);
264154
/// # let gm = GuestMemoryMmap::new(&vec![(start_addr, 0x400)]).unwrap();
265-
/// let mut file = File::open(Path::new("/dev/urandom")).unwrap();
155+
/// let mut file = if cfg!(unix) {
156+
/// File::open(Path::new("/dev/urandom")).unwrap()
157+
/// } else {
158+
/// File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe")).unwrap()
159+
/// };
266160
/// let addr = GuestAddress(0x1010);
267161
/// gm.read_from(addr, &mut file, 128).unwrap();
268162
/// let read_addr = addr.checked_add(8).unwrap();
@@ -283,12 +177,18 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
283177
/// * Read bytes from /dev/urandom
284178
///
285179
/// ```
180+
/// # extern crate tempfile;
181+
/// # use self::tempfile::tempfile;
286182
/// # use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
287183
/// # use std::fs::File;
288184
/// # use std::path::Path;
289185
/// # let start_addr = GuestAddress(0x1000);
290186
/// # let gm = GuestMemoryMmap::new(&vec![(start_addr, 0x400)]).unwrap();
291-
/// let mut file = File::open(Path::new("/dev/urandom")).unwrap();
187+
/// let mut file = if cfg!(unix) {
188+
/// File::open(Path::new("/dev/urandom")).unwrap()
189+
/// } else {
190+
/// File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe")).unwrap()
191+
/// };
292192
/// let addr = GuestAddress(0x1010);
293193
/// gm.read_exact_from(addr, &mut file, 128).unwrap();
294194
/// let read_addr = addr.checked_add(8).unwrap();
@@ -304,18 +204,20 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
304204
.map_err(Into::into)
305205
}
306206

307-
/// Reads data from the region to a writable object.
207+
/// Writes data from the region to a writable object.
308208
///
309209
/// # Examples
310210
///
311-
/// * Write 128 bytes to /dev/null
211+
/// * Write 128 bytes to a temp file
312212
///
313213
/// ```
214+
/// # extern crate tempfile;
215+
/// # use self::tempfile::tempfile;
314216
/// # use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
315217
/// # use std::fs::OpenOptions;
316218
/// # let start_addr = GuestAddress(0x1000);
317219
/// # let gm = GuestMemoryMmap::new(&vec![(start_addr, 0x400)]).unwrap();
318-
/// let mut file = OpenOptions::new().write(true).open("/dev/null").unwrap();
220+
/// let mut file = tempfile().unwrap();
319221
/// let mut mem = [0u8; 1024];
320222
/// gm.write_to(start_addr, &mut file, 128).unwrap();
321223
/// ```
@@ -329,18 +231,20 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
329231
.map_err(Into::into)
330232
}
331233

332-
/// Reads data from the region to a writable object.
234+
/// Writes data from the region to a writable object.
333235
///
334236
/// # Examples
335237
///
336-
/// * Write 128 bytes to /dev/null
238+
/// * Write 128 bytes to a temp file
337239
///
338240
/// ```
241+
/// # extern crate tempfile;
242+
/// # use self::tempfile::tempfile;
339243
/// # use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
340244
/// # use std::fs::OpenOptions;
341245
/// # let start_addr = GuestAddress(0x1000);
342246
/// # let gm = GuestMemoryMmap::new(&vec![(start_addr, 0x400)]).unwrap();
343-
/// let mut file = OpenOptions::new().write(true).open("/dev/null").unwrap();
247+
/// let mut file = tempfile().unwrap();
344248
/// let mut mem = [0u8; 1024];
345249
/// gm.write_all_to(start_addr, &mut file, 128).unwrap();
346250
/// ```
@@ -495,7 +399,6 @@ mod tests {
495399
use super::*;
496400
use std::fs::File;
497401
use std::mem;
498-
use std::os::unix::io::FromRawFd;
499402
use std::path::Path;
500403

501404
use Bytes;
@@ -512,13 +415,6 @@ mod tests {
512415
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
513416
}
514417

515-
#[test]
516-
fn map_invalid_fd() {
517-
let fd = unsafe { std::fs::File::from_raw_fd(-1) };
518-
let e = MmapRegion::from_fd(&fd, 1024, 0).unwrap_err();
519-
assert_eq!(e.raw_os_error(), Some(libc::EBADF));
520-
}
521-
522418
#[test]
523419
fn slice_addr() {
524420
let m = MmapRegion::new(5).unwrap();
@@ -720,20 +616,29 @@ mod tests {
720616
fn read_to_and_write_from_mem() {
721617
let gm = GuestMemoryMmap::new(&[(GuestAddress(0x1000), 0x400)]).unwrap();
722618
let addr = GuestAddress(0x1010);
619+
let mut file = if cfg!(unix) {
620+
File::open(Path::new("/dev/zero")).unwrap()
621+
} else {
622+
File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe")).unwrap()
623+
};
723624
gm.write_obj(!0u32, addr).unwrap();
724-
gm.read_exact_from(
725-
addr,
726-
&mut File::open(Path::new("/dev/zero")).unwrap(),
727-
mem::size_of::<u32>(),
728-
)
729-
.unwrap();
625+
gm.read_exact_from(addr, &mut file, mem::size_of::<u32>())
626+
.unwrap();
730627
let value: u32 = gm.read_obj(addr).unwrap();
731-
assert_eq!(value, 0);
628+
if cfg!(unix) {
629+
assert_eq!(value, 0);
630+
} else {
631+
assert_eq!(value, 0x0090_5a4d);
632+
}
732633

733634
let mut sink = Vec::new();
734635
gm.write_all_to(addr, &mut sink, mem::size_of::<u32>())
735636
.unwrap();
736-
assert_eq!(sink, vec![0; mem::size_of::<u32>()]);
637+
if cfg!(unix) {
638+
assert_eq!(sink, vec![0; mem::size_of::<u32>()]);
639+
} else {
640+
assert_eq!(sink, vec![0x4d, 0x5a, 0x90, 0x00]);
641+
};
737642
}
738643

739644
#[test]

0 commit comments

Comments
 (0)