Skip to content

Commit fb7abb9

Browse files
committed
Add Copy on Write support on the host for nanvix
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
1 parent 3517c0c commit fb7abb9

1 file changed

Lines changed: 39 additions & 13 deletions

File tree

src/hyperlight_host/src/sandbox/file_mapping.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ use crate::mem::memory_region::{HostRegionBase, MemoryRegionKind};
4141
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags, MemoryRegionType};
4242
use crate::{Result, log_then_return};
4343

44+
/// Returns the guest-side permission flags for file mappings.
45+
///
46+
/// With the `nanvix-unstable` feature, files are mapped as
47+
/// `READ | WRITE | EXECUTE` (copy-on-write). Otherwise the default
48+
/// is `READ | EXECUTE` (read-only + executable).
49+
fn file_mapping_flags() -> MemoryRegionFlags {
50+
#[cfg(feature = "nanvix-unstable")]
51+
{
52+
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE | MemoryRegionFlags::EXECUTE
53+
}
54+
#[cfg(not(feature = "nanvix-unstable"))]
55+
{
56+
MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE
57+
}
58+
}
59+
4460
/// A prepared (host-side) file mapping ready to be applied to a VM.
4561
///
4662
/// Created by [`prepare_file_cow`]. The host-side OS resources (file
@@ -166,7 +182,7 @@ impl PreparedFileMapping {
166182
Ok(MemoryRegion {
167183
host_region: host_base..host_end,
168184
guest_region: guest_start..guest_end,
169-
flags: MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE,
185+
flags: file_mapping_flags(),
170186
region_type: MemoryRegionType::MappedFile,
171187
})
172188
}
@@ -186,7 +202,7 @@ impl PreparedFileMapping {
186202
host_region: *mmap_base as usize
187203
..(*mmap_base as usize).wrapping_add(*mmap_size),
188204
guest_region: guest_start..guest_end,
189-
flags: MemoryRegionFlags::READ | MemoryRegionFlags::EXECUTE,
205+
flags: file_mapping_flags(),
190206
region_type: MemoryRegionType::MappedFile,
191207
})
192208
}
@@ -294,9 +310,11 @@ pub(crate) fn prepare_file_cow(
294310
use std::os::windows::io::AsRawHandle;
295311

296312
use windows::Win32::Foundation::HANDLE;
297-
use windows::Win32::System::Memory::{
298-
CreateFileMappingW, FILE_MAP_READ, MapViewOfFile, PAGE_READONLY,
299-
};
313+
use windows::Win32::System::Memory::{CreateFileMappingW, MapViewOfFile};
314+
#[cfg(feature = "nanvix-unstable")]
315+
use windows::Win32::System::Memory::{FILE_MAP_COPY, PAGE_WRITECOPY};
316+
#[cfg(not(feature = "nanvix-unstable"))]
317+
use windows::Win32::System::Memory::{FILE_MAP_READ, PAGE_READONLY};
300318

301319
let file = std::fs::File::options().read(true).open(file_path)?;
302320
let file_size = file.metadata()?.len();
@@ -312,18 +330,23 @@ pub(crate) fn prepare_file_cow(
312330

313331
let file_handle = HANDLE(file.as_raw_handle());
314332

315-
// Create a read-only file mapping object backed by the actual file.
333+
// nanvix-unstable maps files as RWX (CoW), so use
334+
// PAGE_WRITECOPY / FILE_MAP_COPY; otherwise PAGE_READONLY
335+
#[cfg(feature = "nanvix-unstable")]
336+
let (page_prot, map_access) = (PAGE_WRITECOPY, FILE_MAP_COPY);
337+
#[cfg(not(feature = "nanvix-unstable"))]
338+
let (page_prot, map_access) = (PAGE_READONLY, FILE_MAP_READ);
339+
316340
// Pass 0,0 for size to use the file's actual size — Windows will
317341
// NOT extend a read-only file, so requesting page-aligned size
318342
// would fail for files smaller than one page.
319343
let mapping_handle =
320-
unsafe { CreateFileMappingW(file_handle, None, PAGE_READONLY, 0, 0, None) }
344+
unsafe { CreateFileMappingW(file_handle, None, page_prot, 0, 0, None) }
321345
.map_err(|e| HyperlightError::Error(format!("CreateFileMappingW failed: {e}")))?;
322346

323-
// Map a read-only view into the host process.
324347
// Passing 0 for dwNumberOfBytesToMap maps the entire file; the OS
325348
// rounds up to the next page boundary and zero-fills the remainder.
326-
let view = unsafe { MapViewOfFile(mapping_handle, FILE_MAP_READ, 0, 0, 0) };
349+
let view = unsafe { MapViewOfFile(mapping_handle, map_access, 0, 0, 0) };
327350
if view.Value.is_null() {
328351
unsafe {
329352
let _ = windows::Win32::Foundation::CloseHandle(mapping_handle);
@@ -363,12 +386,15 @@ pub(crate) fn prepare_file_cow(
363386
// MSHV's map_user_memory requires host-writable pages (the
364387
// kernel module calls get_user_pages with write access).
365388
// KVM's KVM_MEM_READONLY slots work with read-only host pages.
389+
// nanvix-unstable needs PROT_WRITE for CoW guest mappings.
366390
// PROT_EXEC is never needed — the hypervisor backs guest R+X
367391
// pages without requiring host-side execute permission.
368-
#[cfg(mshv3)]
369-
let prot = libc::PROT_READ | libc::PROT_WRITE;
370-
#[cfg(not(mshv3))]
371-
let prot = libc::PROT_READ;
392+
let needs_write = cfg!(mshv3) || cfg!(feature = "nanvix-unstable");
393+
let prot = if needs_write {
394+
libc::PROT_READ | libc::PROT_WRITE
395+
} else {
396+
libc::PROT_READ
397+
};
372398

373399
libc::mmap(
374400
std::ptr::null_mut(),

0 commit comments

Comments
 (0)