Skip to content

Commit 931e297

Browse files
committed
Implement wasmtime_memory_image APIs
Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
1 parent 529eb5d commit 931e297

1 file changed

Lines changed: 75 additions & 12 deletions

File tree

src/hyperlight_wasm_runtime/src/platform.rs

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -172,32 +172,95 @@ pub extern "C" fn wasmtime_init_traps(handler: wasmtime_trap_handler_t) -> i32 {
172172
0
173173
}
174174

175-
// The wasmtime_memory_image APIs are not yet supported.
175+
// Copy a VA range to a new VA. Old and new VA, and len, must be
176+
// page-aligned.
177+
fn copy_va_mapping(base: *const u8, len: usize, to_va: *mut u8, remap_original: bool) {
178+
// TODO: make this more efficient by directly exposing the ability
179+
// to traverse an entire VA range in
180+
// hyperlight_guest_bin::paging::virt_to_phys, and coalescing
181+
// continuous ranges there.
182+
let base_u = base as u64;
183+
let va_page_bases = (base_u..(base_u + len as u64)).step_by(vmem::PAGE_SIZE);
184+
let mappings = va_page_bases.flat_map(paging::virt_to_phys);
185+
for mapping in mappings {
186+
// TODO: Deduplicate with identical logic in hyperlight_host snapshot.
187+
let (new_kind, was_writable) = match mapping.kind {
188+
// Skip unmapped pages, since they will be unmapped in
189+
// both the original and the new copy
190+
vmem::MappingKind::Unmapped => continue,
191+
vmem::MappingKind::Basic(bm) if bm.writable => (vmem::MappingKind::Cow(vmem::CowMapping {
192+
readable: bm.readable,
193+
executable: bm.executable,
194+
}), true),
195+
vmem::MappingKind::Basic(bm) => (vmem::MappingKind::Basic(vmem::BasicMapping {
196+
readable: bm.readable,
197+
writable: false,
198+
executable: bm.executable,
199+
}), false),
200+
vmem::MappingKind::Cow(cm) => (vmem::MappingKind::Cow(cm), false),
201+
};
202+
if remap_original && was_writable {
203+
// If necessary, remap the original page as Cow, instead
204+
// of whatever it is now, to ensure that any more writes to
205+
// that region do not change the image base.
206+
//
207+
// TODO: could the table traversal needed for this be fused
208+
// with the table traversal that got the original mapping,
209+
// above?
210+
unsafe {
211+
paging::map_region(
212+
mapping.phys_base,
213+
mapping.virt_base as *mut u8,
214+
vmem::PAGE_SIZE as u64,
215+
new_kind,
216+
);
217+
}
218+
}
219+
// map the same pages to the new VA
220+
unsafe {
221+
paging::map_region(
222+
mapping.phys_base,
223+
to_va.wrapping_add((mapping.virt_base - base_u) as usize),
224+
vmem::PAGE_SIZE as u64,
225+
new_kind,
226+
);
227+
}
228+
}
229+
}
230+
231+
// Create a copy-on-write memory image from some existing VA range.
232+
// `ptr` and `len` must be page-aligned (which is guaranteed by the
233+
// wasmtime-platform.h interface).
176234
#[no_mangle]
177235
pub extern "C" fn wasmtime_memory_image_new(
178-
_ptr: *const u8,
179-
_len: usize,
236+
ptr: *const u8,
237+
len: usize,
180238
ret: &mut *mut c_void,
181239
) -> i32 {
182-
*ret = core::ptr::null_mut();
240+
// Choose an arbitrary VA, which we will use as the memory image
241+
// identifier. We will construct the image by mapping a copy of
242+
// the original VA range here, making the original copy CoW as we
243+
// go.
244+
let new_virt = FIRST_VADDR.fetch_add(0x100_0000_0000, Ordering::Relaxed) as *mut u8;
245+
copy_va_mapping(ptr, len, new_virt, true);
246+
*ret = new_virt as *mut c_void;
183247
0
184248
}
185249

186250
#[no_mangle]
187251
pub extern "C" fn wasmtime_memory_image_map_at(
188-
_image: *mut c_void,
189-
_addr: *mut u8,
190-
_len: usize,
252+
image: *mut c_void,
253+
addr: *mut u8,
254+
len: usize,
191255
) -> i32 {
192-
/* This should never be called because wasmtime_memory_image_new
193-
* returns NULL */
194-
panic!("wasmtime_memory_image_map_at");
256+
copy_va_mapping(image as *mut u8, len, addr, false);
257+
0
195258
}
196259

197260
#[no_mangle]
198261
pub extern "C" fn wasmtime_memory_image_free(_image: *mut c_void) {
199-
/* This should never be called because wasmtime_memory_image_new
200-
* returns NULL */
262+
/* This should never be called in practice, because we simple
263+
* restore the snapshot rather than actually unload/destroy instances */
201264
panic!("wasmtime_memory_image_free");
202265
}
203266

0 commit comments

Comments
 (0)