Skip to content

Commit d34cf9c

Browse files
committed
[tests] aarch64: remove amd64-isms from enabled tests
Either by disabling them, or by rewriting them to do a similar thing on aarch64. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
1 parent 3c184cd commit d34cf9c

4 files changed

Lines changed: 143 additions & 44 deletions

File tree

src/hyperlight_host/src/sandbox/initialized_multi_use.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,12 +1215,12 @@ mod tests {
12151215
match res.unwrap_err() {
12161216
HyperlightError::GuestAborted(_, msg) => {
12171217
// msg should indicate we got an invalid opcode exception
1218+
#[cfg(target_arch = "x86_64")]
12181219
assert!(msg.contains("InvalidOpcode"));
1220+
#[cfg(target_arch = "aarch64")]
1221+
assert!(msg.contains("0x2000000"));
12191222
}
1220-
e => panic!(
1221-
"Expected HyperlightError::GuestExecutionError but got {:?}",
1222-
e
1223-
),
1223+
e => panic!("Expected HyperlightError::GuestAborted but got {:?}", e),
12241224
}
12251225
}
12261226

@@ -1306,7 +1306,10 @@ mod tests {
13061306
.evolve()
13071307
.unwrap();
13081308

1309+
#[cfg(target_arch = "x86_64")]
13091310
let expected = &[0x90, 0x90, 0x90, 0xC3]; // NOOP slide to RET
1311+
#[cfg(target_arch = "aarch64")]
1312+
let expected = &[0x1f, 0x20, 0x03, 0xd5, 0xc0, 0x03, 0x5f, 0xd6];
13101313
let map_mem = page_aligned_memory(expected);
13111314
let guest_base = 0x1_0000_0000; // Arbitrary guest base address
13121315

@@ -1488,8 +1491,9 @@ mod tests {
14881491
let dr0_initial: u64 = sandbox.call("GetDr0", ()).unwrap();
14891492
assert_eq!(dr0_initial, 0, "DR0 should initially be 0");
14901493

1491-
// Dirty DR0 by setting it to a known non-zero value
1492-
const DIRTY_VALUE: u64 = 0xDEAD_BEEF_CAFE_BABE;
1494+
// Dirty DR0 by setting it to a known non-zero value, avoiding
1495+
// bits that are reserved in aarch64 DBGBVR0_EL1
1496+
const DIRTY_VALUE: u64 = 0xFFFF_FEDC_7654_3210;
14931497
sandbox.call::<()>("SetDr0", DIRTY_VALUE).unwrap();
14941498
let dr0_dirty: u64 = sandbox.call("GetDr0", ()).unwrap();
14951499
assert_eq!(

src/hyperlight_host/tests/integration_test.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,12 @@ fn execute_on_heap() {
711711

712712
#[cfg(not(feature = "executable_heap"))]
713713
assert!(
714-
result.unwrap_err().to_string().contains("PageFault"),
714+
result.unwrap_err().to_string().contains(
715+
#[cfg(target_arch = "x86_64")]
716+
"PageFault",
717+
#[cfg(target_arch = "aarch64")]
718+
"Exception Syndrome: 0x86",
719+
),
715720
"should get page fault"
716721
);
717722
});
@@ -1644,6 +1649,7 @@ fn interrupt_infinite_moving_loop_stress_test() {
16441649
}
16451650

16461651
#[test]
1652+
#[cfg(target_arch = "x86_64")]
16471653
fn exception_handler_installation_and_validation() {
16481654
with_rust_sandbox(|mut sandbox| {
16491655
// Verify handler count starts at 0
@@ -1692,21 +1698,33 @@ fn fill_heap_and_cause_exception() {
16921698

16931699
// Verify the message was properly formatted (proves no-allocation path worked)
16941700
// Exception vector 6 is #UD (Invalid Opcode from ud2 instruction)
1701+
#[cfg(target_arch = "x86_64")]
1702+
let vector = "Exception vector: 6";
1703+
#[cfg(target_arch = "aarch64")]
1704+
let vector = "Exception vector: CurrentSP0 Synchronous";
16951705
assert!(
1696-
message.contains("Exception vector: 6"),
1697-
"Message should contain 'Exception vector: 6'\nFull error: {:?}",
1706+
message.contains(vector),
1707+
"Message should contain '{}'\nFull error: {:?}",
1708+
vector,
16981709
err
16991710
);
17001711
assert!(
17011712
message.contains("Faulting Instruction:"),
17021713
"Message should contain 'Faulting Instruction:'\nFull error: {:?}",
17031714
err
17041715
);
1716+
#[cfg(target_arch = "x86_64")]
17051717
assert!(
17061718
message.contains("Stack Pointer:"),
17071719
"Message should contain 'Stack Pointer:'\nFull error: {:?}",
17081720
err
17091721
);
1722+
#[cfg(target_arch = "aarch64")]
1723+
assert!(
1724+
message.contains("Exception Syndrome:"),
1725+
"Message should contain 'Exception Syndrome:'\nFull error: {:?}",
1726+
err
1727+
);
17101728
}
17111729
_ => panic!("Expected GuestAborted error, got: {:?}", err),
17121730
}

src/tests/rust_guests/dummyguest/src/main.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,36 @@ fn halt() {
3333
// VmAction::Halt = 108; using raw constant to avoid pulling in
3434
// anyhow (via hyperlight_common's TryFrom impl) which requires alloc.
3535
unsafe {
36+
#[cfg(target_arch = "x86_64")]
3637
asm!(
3738
"out dx, eax",
3839
"cli",
3940
"hlt",
4041
in("dx") 108u16,
4142
in("eax") 0u32,
4243
);
44+
#[cfg(target_arch = "aarch64")]
45+
asm!(
46+
"str {val}, [{addr}]",
47+
val = in(reg) 0, addr = in(reg) 0xffff_ffff_e000u64 + 108 * 8,
48+
);
4349
}
4450
}
4551

4652
fn mmio_read() {
4753
unsafe {
54+
#[cfg(target_arch = "x86_64")]
4855
asm!("mov al, [0x8000]");
56+
57+
let mut out: u8;
58+
#[cfg(target_arch = "aarch64")]
59+
asm!("ldr {0:x}, [{1}]", out(reg) out, in(reg) 0x8000);
4960
}
5061
}
5162

5263
#[allow(non_snake_case)]
5364
#[no_mangle]
54-
pub extern "win64" fn entrypoint(a: i64, b: i64, c: i32) -> i32 {
65+
pub extern "C" fn entrypoint(a: i64, b: i64, c: i32) -> i32 {
5566
if a != 0x230000 || b != 1234567890 || c != 4096 {
5667
mmio_read();
5768
}

src/tests/rust_guests/simpleguest/src/main.rs

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,6 @@ fn call_malloc(size: i32) -> i32 {
341341
}
342342

343343
#[guest_function("FillHeapAndCauseException")]
344-
#[cfg(target_arch = "x86_64")]
345344
fn fill_heap_and_cause_exception() {
346345
let layout: Layout = Layout::new::<u8>();
347346
let mut ptr = unsafe { alloc::alloc::alloc_zeroed(layout) };
@@ -351,7 +350,7 @@ fn fill_heap_and_cause_exception() {
351350
}
352351

353352
// trigger an undefined instruction exception
354-
unsafe { core::arch::asm!("ud2") };
353+
trigger_exception();
355354
}
356355

357356
#[guest_function("ExhaustHeap")]
@@ -452,7 +451,13 @@ fn test_guest_panic(message: String) {
452451
fn execute_on_heap() -> String {
453452
unsafe {
454453
// NO-OP followed by RET
455-
let heap_memory = Box::new([0x90u8, 0xC3]);
454+
let mut heap_memory = Box::new(
455+
#[cfg(target_arch = "x86_64")]
456+
[0x90u8, 0xC3],
457+
#[cfg(target_arch = "aarch64")]
458+
[0x1f, 0x20, 0x03, 0xd5, 0xc0, 0x03, 0x5f, 0xd6],
459+
);
460+
dicachesync(heap_memory.as_mut_ptr(), heap_memory.len());
456461
let heap_fn: fn() = core::mem::transmute(Box::into_raw(heap_memory));
457462
heap_fn();
458463
black_box(heap_fn); // avoid optimization when running in release mode
@@ -485,17 +490,23 @@ fn log_message(message: String, level: i32) {
485490
}
486491

487492
#[guest_function("TriggerException")]
488-
#[cfg(target_arch = "x86_64")]
489493
fn trigger_exception() {
490494
// trigger an undefined instruction exception
491-
unsafe { core::arch::asm!("ud2") };
495+
#[cfg(target_arch = "x86_64")]
496+
unsafe {
497+
core::arch::asm!("ud2")
498+
};
499+
#[cfg(target_arch = "aarch64")]
500+
unsafe {
501+
core::arch::asm!("udf #0")
502+
};
492503
}
493504

494505
/// Execute an OUT instruction with an arbitrary port and value.
495506
/// This is used to test that invalid OUT ports cause errors.
496507
#[guest_function("OutbWithPort")]
497-
#[cfg(target_arch = "x86_64")]
498508
fn outb_with_port(port: u32, value: u32) {
509+
#[cfg(target_arch = "x86_64")]
499510
unsafe {
500511
core::arch::asm!(
501512
"out dx, eax",
@@ -504,6 +515,12 @@ fn outb_with_port(port: u32, value: u32) {
504515
options(preserves_flags, nomem, nostack)
505516
);
506517
}
518+
#[cfg(target_arch = "aarch64")]
519+
unsafe {
520+
(hyperlight_common::layout::io_page().unwrap().1 as *mut u64)
521+
.wrapping_add(port as usize)
522+
.write_volatile(value as u64);
523+
}
507524
}
508525

509526
// =============================================================================
@@ -716,16 +733,28 @@ fn use_sse2_registers() {
716733
}
717734

718735
#[guest_function("SetDr0")]
719-
#[cfg(target_arch = "x86_64")]
720736
fn set_dr0(value: u64) {
721-
unsafe { core::arch::asm!("mov dr0, {}", in(reg) value) };
737+
#[cfg(target_arch = "x86_64")]
738+
unsafe {
739+
core::arch::asm!("mov dr0, {}", in(reg) value)
740+
};
741+
#[cfg(target_arch = "aarch64")]
742+
unsafe {
743+
core::arch::asm!("msr dbgbvr0_el1, {}", in(reg) value)
744+
};
722745
}
723746

724747
#[guest_function("GetDr0")]
725-
#[cfg(target_arch = "x86_64")]
726748
fn get_dr0() -> u64 {
727749
let value: u64;
728-
unsafe { core::arch::asm!("mov {}, dr0", out(reg) value) };
750+
#[cfg(target_arch = "x86_64")]
751+
unsafe {
752+
core::arch::asm!("mov {}, dr0", out(reg) value)
753+
};
754+
#[cfg(target_arch = "aarch64")]
755+
unsafe {
756+
core::arch::asm!("mrs {}, dbgbvr0_el1", out(reg) value)
757+
};
729758
value
730759
}
731760

@@ -759,7 +788,6 @@ fn read_from_user_memory(num: u64, expected: Vec<u8>) -> Result<Vec<u8>> {
759788
Ok(bytes)
760789
}
761790

762-
#[cfg(target_arch = "x86_64")]
763791
#[guest_function("ReadMappedBuffer")]
764792
fn read_mapped_buffer(base: u64, len: u64, do_map: bool) -> Vec<u8> {
765793
let base = base as usize as *const u8;
@@ -786,15 +814,13 @@ fn read_mapped_buffer(base: u64, len: u64, do_map: bool) -> Vec<u8> {
786814
data.to_vec()
787815
}
788816

789-
#[cfg(target_arch = "x86_64")]
790817
#[guest_function("CheckMapped")]
791818
fn check_mapped_buffer(base: u64) -> bool {
792819
hyperlight_guest_bin::paging::virt_to_phys(base)
793820
.next()
794821
.is_some()
795822
}
796823

797-
#[cfg(target_arch = "x86_64")]
798824
#[guest_function("WriteMappedBuffer")]
799825
fn write_mapped_buffer(base: u64, len: u64) -> bool {
800826
let base = base as usize as *mut u8;
@@ -823,7 +849,60 @@ fn write_mapped_buffer(base: u64, len: u64) -> bool {
823849
true
824850
}
825851

826-
#[cfg(target_arch = "x86_64")]
852+
fn dicachesync(_base: *mut u8, _len: usize) {
853+
#[cfg(target_arch = "aarch64")]
854+
unsafe {
855+
let ctr_el0: u64;
856+
core::arch::asm!("mrs {}, ctr_el0", out(reg) ctr_el0);
857+
let iminline = 4 * (1 << (ctr_el0 & 0xf));
858+
#[allow(unused)]
859+
let dminline = 4 * (1 << ((ctr_el0 >> 16) & 0xf));
860+
// See the comment in the `KVM_EXIT_ARM_NISV` case of
861+
// `run_vcpu` in
862+
// src/hyperlight_host/src/hypervisor/virtual_machine/kvm.rs
863+
// for an explanation of why this cache maintenance sequence
864+
// is so complex.
865+
core::arch::asm!("
866+
ldr xzr, [{addr}]
867+
msr nzcv, xzr
868+
b 2f
869+
870+
0: ldr xzr, [{tmp}]
871+
msr nzcv, xzr
872+
b 3f
873+
1: ldr xzr, [{tmp}]
874+
msr nzcv, xzr
875+
b 4f
876+
877+
2: mov {tmp}, {addr}
878+
879+
3: dc cvau, {tmp}
880+
b.eq 0b
881+
add {tmp}, {tmp}, {dminline:x}
882+
cmp {tmp}, {max}
883+
b.lt 3b
884+
885+
dsb ish
886+
887+
mov {tmp}, {addr}
888+
889+
4: ic ivau, {tmp}
890+
b.eq 1b
891+
add {tmp}, {tmp}, {iminline:x}
892+
cmp {tmp}, {max}
893+
b.lt 4b
894+
895+
dsb ish
896+
isb
897+
",
898+
iminline = in(reg) iminline,
899+
dminline = in(reg) dminline,
900+
addr = in(reg) _base as usize,
901+
max = in(reg) _base as usize + _len,
902+
tmp = out(reg) _);
903+
}
904+
}
905+
827906
#[guest_function("ExecMappedBuffer")]
828907
fn exec_mapped_buffer(base: u64, len: u64) -> bool {
829908
let base = base as usize as *mut u8;
@@ -847,6 +926,9 @@ fn exec_mapped_buffer(base: u64, len: u64) -> bool {
847926

848927
// Should be safe as long as data is something like a NOOP followed by a RET
849928
let func: fn() = unsafe { core::mem::transmute(data.as_ptr()) };
929+
930+
dicachesync(base, len);
931+
850932
func();
851933

852934
true
@@ -991,7 +1073,6 @@ fn fuzz_guest_trace(max_depth: u32, msg: String) -> u32 {
9911073
fuzz_traced_function(0, max_depth, &msg)
9921074
}
9931075

994-
#[cfg(target_arch = "x86_64")]
9951076
#[guest_function("CorruptOutputSizePrefix")]
9961077
fn corrupt_output_size_prefix() -> i32 {
9971078
unsafe {
@@ -1004,19 +1085,11 @@ fn corrupt_output_size_prefix() -> i32 {
10041085
buf[8..12].copy_from_slice(&0xFFFF_FFFBu32.to_le_bytes());
10051086
buf[12..16].copy_from_slice(&[0u8; 4]);
10061087
buf[16..24].copy_from_slice(&8_u64.to_le_bytes());
1007-
1008-
core::arch::asm!(
1009-
"out dx, eax",
1010-
"cli",
1011-
"hlt",
1012-
in("dx") hyperlight_common::outb::VmAction::Halt as u16,
1013-
in("eax") 0u32,
1014-
options(noreturn),
1015-
);
1088+
outb_with_port(hyperlight_common::outb::VmAction::Halt as u32, 0u32);
1089+
unreachable!();
10161090
}
10171091
}
10181092

1019-
#[cfg(target_arch = "x86_64")]
10201093
#[guest_function("CorruptOutputBackPointer")]
10211094
fn corrupt_output_back_pointer() -> i32 {
10221095
unsafe {
@@ -1028,15 +1101,8 @@ fn corrupt_output_back_pointer() -> i32 {
10281101
buf[0..8].copy_from_slice(&24_u64.to_le_bytes());
10291102
buf[8..16].copy_from_slice(&[0u8; 8]);
10301103
buf[16..24].copy_from_slice(&0xDEAD_u64.to_le_bytes());
1031-
1032-
core::arch::asm!(
1033-
"out dx, eax",
1034-
"cli",
1035-
"hlt",
1036-
in("dx") hyperlight_common::outb::VmAction::Halt as u16,
1037-
in("eax") 0u32,
1038-
options(noreturn),
1039-
);
1104+
outb_with_port(hyperlight_common::outb::VmAction::Halt as u32, 0u32);
1105+
unreachable!();
10401106
}
10411107
}
10421108

0 commit comments

Comments
 (0)