Skip to content

Commit d429bb2

Browse files
committed
Add unit tests for Vm trait
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent 6d2f287 commit d429bb2

File tree

1 file changed

+224
-0
lines changed
  • src/hyperlight_host/src/hypervisor/vm

1 file changed

+224
-0
lines changed

src/hyperlight_host/src/hypervisor/vm/mod.rs

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,29 @@ pub(crate) trait Vm: Debug + Send {
181181

182182
#[cfg(test)]
183183
mod tests {
184+
use super::*;
185+
use crate::hypervisor::regs::{CommonSegmentRegister, CommonTableRegister};
186+
187+
fn boxed_vm() -> Box<dyn Vm> {
188+
let available_vm = get_available_hypervisor().as_ref().unwrap();
189+
match available_vm {
190+
#[cfg(kvm)]
191+
HypervisorType::Kvm => {
192+
use crate::hypervisor::vm::kvm::KvmVm;
193+
Box::new(KvmVm::new().unwrap())
194+
}
195+
#[cfg(mshv3)]
196+
HypervisorType::Mshv => {
197+
use crate::hypervisor::vm::mshv::MshvVm;
198+
Box::new(MshvVm::new().unwrap())
199+
}
200+
#[cfg(target_os = "windows")]
201+
HypervisorType::Whp => {
202+
use crate::hypervisor::vm::whp::WhpVm;
203+
Box::new(WhpVm::new().unwrap())
204+
}
205+
}
206+
}
184207

185208
#[test]
186209
// TODO: add support for testing on WHP
@@ -200,4 +223,205 @@ mod tests {
200223
}
201224
}
202225
}
226+
227+
#[test]
228+
fn regs() {
229+
let vm = boxed_vm();
230+
231+
let regs = CommonRegisters {
232+
rax: 1,
233+
rbx: 2,
234+
rcx: 3,
235+
rdx: 4,
236+
rsi: 5,
237+
rdi: 6,
238+
rsp: 7,
239+
rbp: 8,
240+
r8: 9,
241+
r9: 10,
242+
r10: 11,
243+
r11: 12,
244+
r12: 13,
245+
r13: 14,
246+
r14: 15,
247+
r15: 16,
248+
rip: 17,
249+
rflags: 0x2,
250+
};
251+
252+
vm.set_regs(&regs).unwrap();
253+
let read_regs = vm.regs().unwrap();
254+
assert_eq!(regs, read_regs);
255+
}
256+
257+
#[test]
258+
fn fpu() {
259+
let vm = boxed_vm();
260+
261+
let fpu = CommonFpu {
262+
fpr: [[1; 16]; 8],
263+
fcw: 2,
264+
fsw: 3,
265+
ftwx: 4,
266+
last_opcode: 5,
267+
last_ip: 6,
268+
last_dp: 7,
269+
xmm: [[8; 16]; 16],
270+
mxcsr: 9,
271+
pad1: 0,
272+
pad2: 0,
273+
};
274+
vm.set_fpu(&fpu).unwrap();
275+
#[cfg_attr(kvm, allow(unused_mut))]
276+
let mut read_fpu = vm.fpu().unwrap();
277+
#[cfg(kvm)]
278+
{
279+
read_fpu.mxcsr = fpu.mxcsr; // KVM get/set fpu does not preserve mxcsr
280+
}
281+
assert_eq!(fpu, read_fpu);
282+
}
283+
284+
#[test]
285+
fn sregs() {
286+
let vm = boxed_vm();
287+
288+
let segment = CommonSegmentRegister {
289+
base: 1,
290+
limit: 2,
291+
selector: 3,
292+
type_: 3,
293+
present: 1,
294+
dpl: 1,
295+
db: 0,
296+
s: 1,
297+
l: 1,
298+
g: 1,
299+
avl: 1,
300+
unusable: 0,
301+
padding: 0,
302+
};
303+
304+
let cs_segment = CommonSegmentRegister {
305+
base: 1,
306+
limit: 0xFFFF,
307+
selector: 0x08,
308+
type_: 0b1011, // code segment, execute/read, accessed
309+
present: 1,
310+
dpl: 1,
311+
db: 0, // must be 0 in 64-bit mode
312+
s: 1,
313+
l: 1, // 64-bit mode
314+
g: 1,
315+
avl: 1,
316+
unusable: 0,
317+
padding: 0,
318+
};
319+
let table = CommonTableRegister {
320+
base: 12,
321+
limit: 13,
322+
};
323+
let sregs = CommonSpecialRegisters {
324+
cs: cs_segment,
325+
ds: segment,
326+
es: segment,
327+
fs: segment,
328+
gs: segment,
329+
ss: segment,
330+
tr: segment,
331+
ldt: segment,
332+
gdt: table,
333+
idt: table,
334+
cr0: 0x80000001,
335+
cr2: 2,
336+
cr3: 3,
337+
cr4: 0x20,
338+
cr8: 5,
339+
efer: 0x500,
340+
apic_base: 0xFEE00900,
341+
interrupt_bitmap: [0; 4],
342+
};
343+
vm.set_sregs(&sregs).unwrap();
344+
let read_sregs = vm.sregs().unwrap();
345+
assert_eq!(sregs, read_sregs);
346+
}
347+
348+
/// Helper to create a page-aligned memory region for testing
349+
fn create_test_memory(size: usize) -> crate::mem::shared_mem::ExclusiveSharedMemory {
350+
use hyperlight_common::mem::PAGE_SIZE_USIZE;
351+
let aligned_size = size.div_ceil(PAGE_SIZE_USIZE) * PAGE_SIZE_USIZE;
352+
crate::mem::shared_mem::ExclusiveSharedMemory::new(aligned_size).unwrap()
353+
}
354+
355+
/// Helper to create a MemoryRegion from ExclusiveSharedMemory
356+
fn region_for_test_memory(
357+
mem: &crate::mem::shared_mem::ExclusiveSharedMemory,
358+
guest_base: usize,
359+
flags: crate::mem::memory_region::MemoryRegionFlags,
360+
) -> MemoryRegion {
361+
use crate::mem::memory_region::MemoryRegionType;
362+
use crate::mem::shared_mem::SharedMemory;
363+
let ptr = mem.base_addr();
364+
let len = mem.mem_size();
365+
MemoryRegion {
366+
host_region: ptr..(ptr + len),
367+
guest_region: guest_base..(guest_base + len),
368+
flags,
369+
region_type: MemoryRegionType::Heap,
370+
}
371+
}
372+
373+
#[test]
374+
fn map_memory() {
375+
use crate::mem::memory_region::MemoryRegionFlags;
376+
377+
let mut vm = boxed_vm();
378+
379+
let mem1 = create_test_memory(4096);
380+
let guest_addr: usize = 0x1000;
381+
let region = region_for_test_memory(
382+
&mem1,
383+
guest_addr,
384+
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE,
385+
);
386+
387+
// SAFETY: The memory region points to valid memory allocated by ExclusiveSharedMemory,
388+
// and will live until we drop mem1 at the end of the test.
389+
// Slot 0 is not already mapped.
390+
unsafe {
391+
vm.map_memory((0, &region)).unwrap();
392+
}
393+
394+
// Unmap the region
395+
vm.unmap_memory((0, &region)).unwrap();
396+
397+
// Unmapping a region that was already unmapped should fail
398+
vm.unmap_memory((0, &region)).unwrap_err();
399+
400+
// Unmapping a region that was never mapped should fail
401+
vm.unmap_memory((99, &region)).unwrap_err();
402+
403+
// Re-map the same region to a different slot
404+
// SAFETY: Same as above - memory is still valid and slot 1 is not mapped.
405+
unsafe {
406+
vm.map_memory((1, &region)).unwrap();
407+
}
408+
409+
// Map a second region to a different slot
410+
let mem2 = create_test_memory(4096);
411+
let guest_addr2: usize = 0x2000;
412+
let region2 = region_for_test_memory(
413+
&mem2,
414+
guest_addr2,
415+
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE,
416+
);
417+
418+
// SAFETY: Memory is valid from ExclusiveSharedMemory, slot 2 is not mapped.
419+
unsafe {
420+
vm.map_memory((2, &region2)).unwrap();
421+
}
422+
423+
// Clean up: unmap both regions
424+
vm.unmap_memory((1, &region)).unwrap();
425+
vm.unmap_memory((2, &region2)).unwrap();
426+
}
203427
}

0 commit comments

Comments
 (0)