Skip to content

Commit 3e631b0

Browse files
Which came first, the snapshot or the sandbox?
This commit changes the Hyperlight API so that every sandbox is created from a snapshot. This is useful for several reasons; most immediately, in the same commit, note that it allows us to avoid precommitting to a size for the page table region, so we no longer need to estimate that regin's size. Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> Co-authored-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
1 parent a43f30a commit 3e631b0

File tree

16 files changed

+982
-700
lines changed

16 files changed

+982
-700
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
// Keep in mind that the minimum upper half GVA is 0xffff_8000_0000_0000
18+
pub const SNAPSHOT_PT_GVA: usize = 0xffff_ff00_0000_0000;

src/hyperlight_common/src/arch/amd64/vmem.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub const PAGE_RW: u64 = 1 << 1;
5454
pub const PAGE_NX: u64 = 1 << 63;
5555
/// Mask to extract the physical address from a PTE (bits 51:12)
5656
/// This masks out the lower 12 flag bits AND the upper bits including NX (bit 63)
57-
pub(crate) const PTE_ADDR_MASK: u64 = 0x000F_FFFF_FFFF_F000;
57+
pub const PTE_ADDR_MASK: u64 = 0x000F_FFFF_FFFF_F000;
5858
const PAGE_USER_ACCESS_DISABLED: u64 = 0 << 2; // U/S bit not set - supervisor mode only (no code runs in user mode for now)
5959
const PAGE_DIRTY_CLEAR: u64 = 0 << 6; // D - dirty bit cleared (set by CPU when written)
6060
const PAGE_ACCESSED_CLEAR: u64 = 0 << 5; // A - accessed bit cleared (set by CPU when accessed)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
#[cfg_attr(target_arch = "x86_64", path = "arch/amd64/layout.rs")]
18+
mod arch;
19+
20+
pub use arch::SNAPSHOT_PT_GVA;

src/hyperlight_common/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub mod flatbuffer_wrappers;
2727
/// FlatBuffers-related utilities and (mostly) generated code
2828
#[allow(clippy::all, warnings)]
2929
mod flatbuffers;
30+
// cbindgen:ignore
31+
pub mod layout;
32+
3033
/// cbindgen:ignore
3134
pub mod mem;
3235

src/hyperlight_guest_bin/src/paging.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,37 @@ pub fn ptov(x: u64) -> *mut u8 {
3838
// virtual address 0, and Rust raw pointer operations can't be
3939
// used to read/write from address 0.
4040

41-
struct GuestMappingOperations {}
41+
// We get this out of CR3 the first time that we do any mapping
42+
// operation. In the future, if snapshot/restore changes to be able to
43+
// change the snapshot pt base, we will need to modify this.
44+
static SNAPSHOT_PT_GPA: spin::Once<u64> = spin::Once::new();
45+
46+
struct GuestMappingOperations {
47+
snapshot_pt_base_gpa: u64,
48+
snapshot_pt_base_gva: u64,
49+
}
50+
impl GuestMappingOperations {
51+
fn new() -> Self {
52+
Self {
53+
snapshot_pt_base_gpa: *SNAPSHOT_PT_GPA.call_once(|| {
54+
let snapshot_pt_base_gpa: u64;
55+
unsafe {
56+
asm!("mov {}, cr3", out(reg) snapshot_pt_base_gpa);
57+
};
58+
snapshot_pt_base_gpa
59+
}),
60+
snapshot_pt_base_gva: hyperlight_common::layout::SNAPSHOT_PT_GVA as u64,
61+
}
62+
}
63+
fn phys_to_virt(&self, addr: u64) -> u64 {
64+
if addr >= self.snapshot_pt_base_gpa {
65+
self.snapshot_pt_base_gva + (addr - self.snapshot_pt_base_gpa)
66+
} else {
67+
// Assume for now that any of our own PTs are identity mapped.
68+
addr
69+
}
70+
}
71+
}
4272
impl hyperlight_common::vmem::TableOps for GuestMappingOperations {
4373
type TableAddr = u64;
4474
unsafe fn alloc_table(&self) -> u64 {
@@ -50,13 +80,15 @@ impl hyperlight_common::vmem::TableOps for GuestMappingOperations {
5080
addr + offset
5181
}
5282
unsafe fn read_entry(&self, addr: u64) -> u64 {
83+
let addr = self.phys_to_virt(addr);
5384
let ret: u64;
5485
unsafe {
5586
asm!("mov {}, qword ptr [{}]", out(reg) ret, in(reg) addr);
5687
}
5788
ret
5889
}
5990
unsafe fn write_entry(&self, addr: u64, entry: u64) {
91+
let addr = self.phys_to_virt(addr);
6092
unsafe {
6193
asm!("mov qword ptr [{}], {}", in(reg) addr, in(reg) entry);
6294
}
@@ -90,7 +122,7 @@ pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64) {
90122
use hyperlight_common::vmem;
91123
unsafe {
92124
vmem::map(
93-
&GuestMappingOperations {},
125+
&GuestMappingOperations::new(),
94126
vmem::Mapping {
95127
phys_base,
96128
virt_base: virt_base as u64,

src/hyperlight_host/src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use thiserror::Error;
3232

3333
#[cfg(target_os = "windows")]
3434
use crate::hypervisor::wrappers::HandleWrapper;
35-
use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags};
35+
use crate::mem::memory_region::MemoryRegionFlags;
3636
use crate::mem::ptr::RawPtr;
3737

3838
/// The error type for Hyperlight operations
@@ -150,7 +150,7 @@ pub enum HyperlightError {
150150

151151
/// Memory region size mismatch
152152
#[error("Memory region size mismatch: host size {0:?}, guest size {1:?} region {2:?}")]
153-
MemoryRegionSizeMismatch(usize, usize, MemoryRegion),
153+
MemoryRegionSizeMismatch(usize, usize, String),
154154

155155
/// The memory request exceeds the maximum size allowed
156156
#[error("Memory requested {0} exceeds maximum size allowed {1}")]

src/hyperlight_host/src/mem/exe.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ pub(crate) struct LoadInfo {
6464
pub(crate) info: Arc<dyn UnwindInfo>,
6565
}
6666

67+
impl LoadInfo {
68+
pub(crate) fn dummy() -> Self {
69+
LoadInfo {
70+
#[cfg(feature = "mem_profile")]
71+
info: Arc::new(DummyUnwindInfo {}),
72+
}
73+
}
74+
}
75+
6776
impl ExeInfo {
6877
pub fn from_file(path: &str) -> Result<Self> {
6978
let mut file = File::open(path)?;

0 commit comments

Comments
 (0)