diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 135923db79a51f8ae212bd2a891cd2376c3c10b5..beec5fcef4ff2966efce148ed2563382ae6e9303 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -617,8 +617,8 @@ mod test { write: Arc::new(|_: &[u8], _: GuestAddress, _: u64| -> bool { true }), }; - let ram1 = Arc::new(HostMemMapping::new(GuestAddress(0), 1000, false).unwrap()); - let ram2 = Arc::new(HostMemMapping::new(GuestAddress(2000), 1000, false).unwrap()); + let ram1 = Arc::new(HostMemMapping::new(GuestAddress(0), 1000, -1, 0, false).unwrap()); + let ram2 = Arc::new(HostMemMapping::new(GuestAddress(2000), 1000, -1, 0, false).unwrap()); let region_a = Region::init_ram_region(ram1.clone()); let region_b = Region::init_ram_region(ram2.clone()); root.add_subregion(region_a, ram1.start_address().raw_value()) @@ -681,7 +681,7 @@ mod test { fn test_write_and_read_object() { let root = Region::init_container_region(8000); let space = AddressSpace::new(root.clone()).unwrap(); - let ram1 = Arc::new(HostMemMapping::new(GuestAddress(0), 1000, false).unwrap()); + let ram1 = Arc::new(HostMemMapping::new(GuestAddress(0), 1000, -1, 0, false).unwrap()); let region_a = Region::init_ram_region(ram1.clone()); root.add_subregion(region_a, ram1.start_address().raw_value()) .unwrap(); diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs index 0a781b773a98cc658cf3f603e4476cacde6d1b2e..25a79fd95c8173260604123d56549a7fef8e6ee0 100644 --- a/address_space/src/host_mmap.rs +++ b/address_space/src/host_mmap.rs @@ -10,29 +10,114 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::fs::File; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; -use crate::errors::{ErrorKind, Result}; +use crate::errors::{ErrorKind, Result, ResultExt}; use crate::{AddressRange, GuestAddress}; -/// Create a new HostMemMapping. +/// FileBackend represents backend-file of `HostMemMapping`. +pub struct FileBackend { + /// File we used to map memory. + pub file: File, + /// Offset from where the file begins. + pub offset: u64, +} + +impl FileBackend { + /// Construct a new FileBackend according to path and length. + /// If the file is already created, this function does not change its length. + /// + /// # Arguments + /// + /// * `file_path` - The path of file. + /// * `file_len` - The size of file. + /// + /// # Errors + /// + /// Return Error if + /// * fail to create the file. + /// * fail to open the file. + /// * fail to set file length. + pub fn new(file_path: &str, file_len: u64) -> Result { + let path = std::path::Path::new(&file_path); + let file = if path.is_dir() { + let fs_path = format!("{}{}", file_path, "/stratovirt_backmem_XXXXXX"); + let fs_cstr = std::ffi::CString::new(fs_path).unwrap().into_raw(); + + let raw_fd = unsafe { libc::mkstemp(fs_cstr) }; + if raw_fd < 0 { + return Err(std::io::Error::last_os_error()) + .chain_err(|| "Create file-backend failed"); + } + + unsafe { libc::unlink(fs_cstr) }; + unsafe { File::from_raw_fd(raw_fd) } + } else { + // Open the file, if not exist, create it. + std::fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(path) + .chain_err(|| "Open file-backend failed")? + }; + + if file.metadata().unwrap().len() == 0 { + file.set_len(file_len) + .chain_err(|| "Set file length failed.")?; + } + + Ok(FileBackend { + file, + offset: 0_u64, + }) + } +} + +/// Create HostMemMappings according to address ranges. /// /// # Arguments /// /// * `ranges` - The guest address range that will be mapped. +/// * `file_path` - The path of backend-file. /// * `omit_vm_memory` - Dump guest memory in core file or not. pub fn create_host_mmaps( ranges: &[(u64, u64)], + file_path: Option<&str>, omit_vm_memory: bool, ) -> Result>> { let mut mappings = Vec::new(); - for range in ranges.iter() { - mappings.push(Arc::new(HostMemMapping::new( - GuestAddress(range.0), - range.1, - omit_vm_memory, - )?)); + match file_path { + Some(path) => { + // create file-backend + let file_len = ranges.iter().fold(0, |acc, x| acc + x.1); + let mut f_back = FileBackend::new(path, file_len)?; + for range in ranges.iter() { + mappings.push(Arc::new(HostMemMapping::new( + GuestAddress(range.0), + range.1, + f_back.file.as_raw_fd(), + f_back.offset, + omit_vm_memory, + )?)); + + f_back.offset += range.1; + } + } + None => { + for range in ranges.iter() { + mappings.push(Arc::new(HostMemMapping::new( + GuestAddress(range.0), + range.1, + -1, + 0, + omit_vm_memory, + )?)); + } + } } Ok(mappings) @@ -59,6 +144,8 @@ impl HostMemMapping { /// /// * `guest_addr` - The start address im memory. /// * `size` - Size of memory that will be mapped. + /// * `file_back` - The file's raw fd that backs memory, + /// * `file_offset` - Offset in the file that backs memory. /// * `omit_vm_memory` - Dump guest memory in core file or not. /// /// # Errors @@ -67,16 +154,23 @@ impl HostMemMapping { pub fn new( guest_addr: GuestAddress, size: u64, + file_back: RawFd, + file_offset: u64, omit_vm_memory: bool, ) -> Result { + let mut flags = libc::MAP_PRIVATE | libc::MAP_NORESERVE; + if file_back == -1 { + flags |= libc::MAP_ANONYMOUS; + } + let host_addr = unsafe { let hva = libc::mmap( std::ptr::null_mut() as *mut libc::c_void, size as libc::size_t, libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_NORESERVE, - -1, - 0, + flags, + file_back, + file_offset as i64, ); if hva == libc::MAP_FAILED { return Err(ErrorKind::Mmap.into()); @@ -146,9 +240,18 @@ mod test { #[test] fn test_ramblock_creation() { - let ram1 = HostMemMapping::new(GuestAddress(0), 100u64, false).unwrap(); - let ram2 = HostMemMapping::new(GuestAddress(0), 100u64, false).unwrap(); + let ram1 = HostMemMapping::new(GuestAddress(0), 100u64, -1, 0, false).unwrap(); + let ram2 = HostMemMapping::new(GuestAddress(0), 100u64, -1, 0, false).unwrap(); identify(ram1, 0, 100); identify(ram2, 0, 100); } + + #[test] + fn test_file_backend() { + let file_path = String::from("/tmp/"); + let file_size = 100u64; + let f_back = FileBackend::new(&file_path, file_size); + assert!(f_back.is_ok()); + assert_eq!(f_back.as_ref().unwrap().offset, 0u64); + } } diff --git a/address_space/src/lib.rs b/address_space/src/lib.rs index 98a7ae60f6aab6fb9e03dfd702ebab989577555b..98f4380ec5ec302c78e5fac7d3a8ca57f7904a8c 100644 --- a/address_space/src/lib.rs +++ b/address_space/src/lib.rs @@ -18,7 +18,7 @@ //! ```rust //! use std::sync::{Arc, Mutex}; //! extern crate address_space; -//! use address_space::{AddressSpace, Region, GuestAddress, HostMemMapping, RegionOps}; +//! use address_space::{AddressSpace, Region, GuestAddress, HostMemMapping, RegionOps, FileBackend}; //! //! struct DummyDevice; //! impl DummyDevice { @@ -37,7 +37,7 @@ //! let space = AddressSpace::new(Region::init_container_region(u64::max_value())).unwrap(); //! //! // 2. create an Ram-type Region, and set it's priority -//! let mem_mapping = Arc::new(HostMemMapping::new(GuestAddress(0), 0x1000, false).unwrap()); +//! let mem_mapping = Arc::new(HostMemMapping::new(GuestAddress(0), 0x1000, -1, 0, false).unwrap()); //! let ram_region = Region::init_ram_region(mem_mapping.clone()); //! ram_region.set_priority(10); //! @@ -87,7 +87,7 @@ mod region; pub use address::{AddressRange, GuestAddress}; pub use address_space::AddressSpace; -pub use host_mmap::{create_host_mmaps, HostMemMapping}; +pub use host_mmap::{create_host_mmaps, FileBackend, HostMemMapping}; #[cfg(target_arch = "x86_64")] pub use listener::KvmIoListener; pub use listener::KvmMemoryListener; diff --git a/address_space/src/listener.rs b/address_space/src/listener.rs index 66a37317f0cde8b80a964a7769d1a9ba6d208160..c7aca78d42c7e91750a700d2471e8f8d2c479c41 100644 --- a/address_space/src/listener.rs +++ b/address_space/src/listener.rs @@ -519,7 +519,8 @@ mod test { } fn create_ram_range(addr: u64, size: u64, offset_in_region: u64) -> FlatRange { - let mem_mapping = Arc::new(HostMemMapping::new(GuestAddress(addr), size, false).unwrap()); + let mem_mapping = + Arc::new(HostMemMapping::new(GuestAddress(addr), size, -1, 0, false).unwrap()); FlatRange { addr_range: AddressRange::new( mem_mapping.start_address().unchecked_add(offset_in_region), diff --git a/address_space/src/region.rs b/address_space/src/region.rs index 45e70c0f3eb281de51ed05d52fa99d2f6de5bd41..236c09554bbee99f0a34a4d9fe68108b70b9ce7d 100644 --- a/address_space/src/region.rs +++ b/address_space/src/region.rs @@ -677,7 +677,8 @@ mod test { #[test] fn test_ram_region() { - let mem_mapping = Arc::new(HostMemMapping::new(GuestAddress(0), 1024u64, false).unwrap()); + let mem_mapping = + Arc::new(HostMemMapping::new(GuestAddress(0), 1024u64, -1, 0, false).unwrap()); let ram_region = Region::init_ram_region(mem_mapping.clone()); let data: [u8; 10] = [10; 10]; let mut res_data: [u8; 10] = [0; 10]; @@ -711,7 +712,7 @@ mod test { fn test_ram_region_access() { // the target guest address is 0~1024 (1024 not included) let rgn_start = GuestAddress(0); - let host_mmap = HostMemMapping::new(GuestAddress(0), 1024u64, false).unwrap(); + let host_mmap = HostMemMapping::new(GuestAddress(0), 1024u64, -1, 0, false).unwrap(); let ram_region = Region::init_ram_region(Arc::new(host_mmap)); let mut file = std::fs::File::create("/tmp/test_read_write_buffer.tmp").unwrap(); let mut file_read = std::fs::File::open("/tmp/test_read_write_buffer.tmp").unwrap(); diff --git a/boot_loader/src/x86_64/bootparam.rs b/boot_loader/src/x86_64/bootparam.rs index 16914e9d17415be64cd6da9040b5d9f9f23de4b3..e29239dc43280e16d12ee0693e72528083c79019 100644 --- a/boot_loader/src/x86_64/bootparam.rs +++ b/boot_loader/src/x86_64/bootparam.rs @@ -159,7 +159,8 @@ mod test { // test setup_boot_params function let root = Region::init_container_region(0x2000_0000); let space = AddressSpace::new(root.clone()).unwrap(); - let ram1 = Arc::new(HostMemMapping::new(GuestAddress(0), 0x1000_0000, false).unwrap()); + let ram1 = + Arc::new(HostMemMapping::new(GuestAddress(0), 0x1000_0000, -1, 0, false).unwrap()); let region_a = Region::init_ram_region(ram1.clone()); root.add_subregion(region_a, ram1.start_address().raw_value()) .unwrap(); diff --git a/boot_loader/src/x86_64/mod.rs b/boot_loader/src/x86_64/mod.rs index 3e0589b934304181aa6ff9ae3fd01310d9c501b9..2d10c57ee650ceec1b22bed7e26a05c55667c700 100644 --- a/boot_loader/src/x86_64/mod.rs +++ b/boot_loader/src/x86_64/mod.rs @@ -419,7 +419,8 @@ mod test { fn test_x86_bootloader_and_kernel_cmdline() { let root = Region::init_container_region(0x2000_0000); let space = AddressSpace::new(root.clone()).unwrap(); - let ram1 = Arc::new(HostMemMapping::new(GuestAddress(0), 0x1000_0000, false).unwrap()); + let ram1 = + Arc::new(HostMemMapping::new(GuestAddress(0), 0x1000_0000, -1, 0, false).unwrap()); let region_a = Region::init_ram_region(ram1.clone()); root.add_subregion(region_a, ram1.start_address().raw_value()) .unwrap(); diff --git a/device_model/src/micro_vm/mod.rs b/device_model/src/micro_vm/mod.rs index 0f0cbad115fba7ced1ede7f2cfb3ea39d21ef585..06a320d5141f71f49f223fad089c9be3e7d75686 100644 --- a/device_model/src/micro_vm/mod.rs +++ b/device_model/src/micro_vm/mod.rs @@ -228,7 +228,8 @@ impl LightMachine { // Init guest-memory // Define ram-region ranges according to architectures let ram_ranges = Self::arch_ram_ranges(vm_config.machine_config.mem_size); - let mem_mappings = create_host_mmaps(&ram_ranges, vm_config.machine_config.omit_vm_memory)?; + let mem_mappings = + create_host_mmaps(&ram_ranges, None, vm_config.machine_config.omit_vm_memory)?; for mmap in mem_mappings.iter() { sys_mem.root().add_subregion( Region::init_ram_region(mmap.clone()), diff --git a/device_model/src/mmio/virtio_mmio.rs b/device_model/src/mmio/virtio_mmio.rs index 90877f85d68af68e6f8cba055c15f56140d30a2f..de30cbcafdd6f9ac352079323c8150d5e1cfdd67 100644 --- a/device_model/src/mmio/virtio_mmio.rs +++ b/device_model/src/mmio/virtio_mmio.rs @@ -526,8 +526,9 @@ mod tests { fn address_space_init() -> Arc { let root = Region::init_container_region(1 << 36); let sys_space = AddressSpace::new(root).unwrap(); - let host_mmap = - Arc::new(HostMemMapping::new(GuestAddress(0), SYSTEM_SPACE_SIZE, false).unwrap()); + let host_mmap = Arc::new( + HostMemMapping::new(GuestAddress(0), SYSTEM_SPACE_SIZE, -1, 0, false).unwrap(), + ); sys_space .root() .add_subregion( diff --git a/device_model/src/virtio/queue.rs b/device_model/src/virtio/queue.rs index 0efa78a55112291b10f10a519b8a2bda6a16cce8..a6ee9cd493416e2550278b6d436ba581dac3866e 100644 --- a/device_model/src/virtio/queue.rs +++ b/device_model/src/virtio/queue.rs @@ -745,8 +745,9 @@ mod tests { fn address_space_init() -> Arc { let root = Region::init_container_region(1 << 36); let sys_space = AddressSpace::new(root).unwrap(); - let host_mmap = - Arc::new(HostMemMapping::new(GuestAddress(0), SYSTEM_SPACE_SIZE, false).unwrap()); + let host_mmap = Arc::new( + HostMemMapping::new(GuestAddress(0), SYSTEM_SPACE_SIZE, -1, 0, false).unwrap(), + ); sys_space .root() .add_subregion(