Skip to content

Commit d28c9c6

Browse files
committed
Add signal-based dirty page tracker for tracking host-memory-writes into shared memory.
Add new SnapshotManager and Snapshot structs. Install DirtyPageTracker immediately after allocating shared memory. Uninstall DirtyPageTracker immediately before setting up VM and mapping memory into VM. Use dirty pages to create snapshots with new snapshotmanager. Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent a69bf07 commit d28c9c6

15 files changed

+2555
-74
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hyperlight_host/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ anyhow = "1.0"
4444
metrics = "0.24.2"
4545
serde_json = "1.0"
4646
elfcore = "2.0"
47+
lockfree ="0.5"
4748

4849
[target.'cfg(windows)'.dependencies]
4950
windows = { version = "0.61", features = [

src/hyperlight_host/src/hypervisor/hyperv_linux.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,7 @@ mod tests {
12021202
return;
12031203
}
12041204
const MEM_SIZE: usize = 0x3000;
1205-
let gm = shared_mem_with_code(CODE.as_slice(), MEM_SIZE, 0).unwrap();
1205+
let mut gm = shared_mem_with_code(CODE.as_slice(), MEM_SIZE, 0).unwrap();
12061206
let rsp_ptr = GuestPtr::try_from(0).unwrap();
12071207
let pml4_ptr = GuestPtr::try_from(0).unwrap();
12081208
let entrypoint_ptr = GuestPtr::try_from(0).unwrap();
@@ -1212,6 +1212,7 @@ mod tests {
12121212
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE | MemoryRegionFlags::EXECUTE,
12131213
crate::mem::memory_region::MemoryRegionType::Code,
12141214
);
1215+
gm.stop_tracking_dirty_pages().unwrap();
12151216
let config: SandboxConfiguration = Default::default();
12161217

12171218
super::HypervLinuxDriver::new(

src/hyperlight_host/src/hypervisor/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@ pub(crate) mod tests {
513513
#[cfg(gdb)]
514514
use crate::hypervisor::DbgMemAccessHandlerCaller;
515515
use crate::mem::ptr::RawPtr;
516+
use crate::mem::shared_mem::SharedMemory;
516517
use crate::sandbox::uninitialized::GuestBinary;
517518
#[cfg(any(crashdump, gdb))]
518519
use crate::sandbox::uninitialized::SandboxRuntimeConfig;
@@ -582,6 +583,9 @@ pub(crate) mod tests {
582583
GuestPtr::try_from(Offset::from(0))
583584
}?;
584585

586+
gshm.shared_mem
587+
.with_exclusivity(|e| e.stop_tracking_dirty_pages())??;
588+
585589
let mut vm = set_up_hypervisor_partition(
586590
&mut gshm,
587591
&config,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
Copyright 2025 The Hyperlight Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
use std::sync::Arc;
18+
19+
use tracing::{Span, instrument};
20+
21+
#[cfg(target_os = "linux")]
22+
pub use super::linux_dirty_page_tracker::LinuxDirtyPageTracker as PlatformDirtyPageTracker;
23+
use super::shared_mem::HostMapping;
24+
#[cfg(target_os = "windows")]
25+
pub use super::windows_dirty_page_tracker::WindowsDirtyPageTracker as PlatformDirtyPageTracker;
26+
use crate::Result;
27+
28+
/// Trait defining the interface for dirty page tracking implementations
29+
pub trait DirtyPageTracking {
30+
#[cfg(test)]
31+
fn get_dirty_pages(&self) -> Result<Vec<usize>>;
32+
fn uninstall(self) -> Result<Vec<usize>>;
33+
}
34+
35+
/// Cross-platform dirty page tracker that delegates to platform-specific implementations
36+
#[derive(Debug)]
37+
pub struct DirtyPageTracker {
38+
inner: PlatformDirtyPageTracker,
39+
}
40+
41+
impl DirtyPageTracker {
42+
/// Create a new dirty page tracker for the given shared memory
43+
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
44+
pub fn new(mapping: Arc<HostMapping>) -> Result<Self> {
45+
let inner = PlatformDirtyPageTracker::new(mapping)?;
46+
Ok(Self { inner })
47+
}
48+
}
49+
50+
impl DirtyPageTracking for DirtyPageTracker {
51+
fn uninstall(self) -> Result<Vec<usize>> {
52+
self.inner.stop_tracking_and_get_dirty_pages()
53+
}
54+
55+
#[cfg(test)]
56+
fn get_dirty_pages(&self) -> Result<Vec<usize>> {
57+
self.inner.get_dirty_pages()
58+
}
59+
}

src/hyperlight_host/src/mem/layout.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ pub(crate) struct SandboxMemoryLayout {
119119
// other
120120
pub(crate) peb_address: usize,
121121
code_size: usize,
122+
pub(super) input_size: usize,
123+
pub(super) output_size: usize,
122124
// The total size of the page tables
123125
total_page_table_size: usize,
124126
// The offset in the sandbox memory where the code starts
@@ -246,7 +248,7 @@ impl SandboxMemoryLayout {
246248
pub(crate) const BASE_ADDRESS: usize = 0x0;
247249

248250
// the offset into a sandbox's input/output buffer where the stack starts
249-
const STACK_POINTER_SIZE_BYTES: u64 = 8;
251+
pub(crate) const STACK_POINTER_SIZE_BYTES: u64 = 8;
250252

251253
/// Create a new `SandboxMemoryLayout` with the given
252254
/// `SandboxConfiguration`, code size and stack/heap size.
@@ -295,11 +297,13 @@ impl SandboxMemoryLayout {
295297
input_data_buffer_offset + cfg.get_input_data_size(),
296298
PAGE_SIZE_USIZE,
297299
);
300+
let input_size = output_data_buffer_offset - input_data_buffer_offset;
298301
// make sure heap buffer starts at 4K boundary
299302
let guest_heap_buffer_offset = round_up_to(
300303
output_data_buffer_offset + cfg.get_output_data_size(),
301304
PAGE_SIZE_USIZE,
302305
);
306+
let output_size = guest_heap_buffer_offset - output_data_buffer_offset;
303307
// make sure guard page starts at 4K boundary
304308
let guard_page_offset = round_up_to(guest_heap_buffer_offset + heap_size, PAGE_SIZE_USIZE);
305309
let guest_user_stack_buffer_offset = guard_page_offset + PAGE_SIZE_USIZE;
@@ -324,7 +328,9 @@ impl SandboxMemoryLayout {
324328
code_size,
325329
host_function_definitions_buffer_offset,
326330
input_data_buffer_offset,
331+
input_size,
327332
output_data_buffer_offset,
333+
output_size,
328334
guest_heap_buffer_offset,
329335
guest_user_stack_buffer_offset,
330336
peb_address,

0 commit comments

Comments
 (0)