mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 20:48:55 +00:00
0b27074f9f
These tests require access to kvm and cannot run in every context. The tests do not pass on aarch64, so the DO_NOT_RUN_AARCH64 flag remains. BUG=b:244623107 TEST=presubmit Change-Id: I221e1055dfe2da7c2f0763f1f26acc211ced4400 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3990013 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Auto-Submit: Dennis Kempin <denniskempin@google.com>
473 lines
14 KiB
Rust
473 lines
14 KiB
Rust
// Copyright 2022 The ChromiumOS Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
use base::pagesize;
|
|
use base::Event;
|
|
use base::FromRawDescriptor;
|
|
use base::MappedRegion;
|
|
use base::MemoryMappingBuilder;
|
|
use base::SIGRTMIN;
|
|
use kvm::dirty_log_bitmap_size;
|
|
use kvm::Cap;
|
|
use kvm::Datamatch;
|
|
use kvm::IoeventAddress;
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use kvm::IrqRoute;
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use kvm::IrqSource;
|
|
use kvm::Kvm;
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use kvm::PicId;
|
|
use kvm::Vcpu;
|
|
use kvm::Vm;
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use kvm_sys::kvm_enable_cap;
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use kvm_sys::kvm_msr_entry;
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use kvm_sys::KVM_CAP_HYPERV_SYNIC;
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use kvm_sys::KVM_IRQCHIP_IOAPIC;
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use libc::EINVAL;
|
|
use vm_memory::GuestAddress;
|
|
use vm_memory::GuestMemory;
|
|
|
|
#[test]
|
|
fn dirty_log_size() {
|
|
let page_size = pagesize();
|
|
assert_eq!(dirty_log_bitmap_size(0), 0);
|
|
assert_eq!(dirty_log_bitmap_size(page_size), 1);
|
|
assert_eq!(dirty_log_bitmap_size(page_size * 8), 1);
|
|
assert_eq!(dirty_log_bitmap_size(page_size * 8 + 1), 2);
|
|
assert_eq!(dirty_log_bitmap_size(page_size * 100), 13);
|
|
}
|
|
|
|
#[test]
|
|
fn new() {
|
|
Kvm::new().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn create_vm() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
|
|
Vm::new(&kvm, gm).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn check_extension() {
|
|
let kvm = Kvm::new().unwrap();
|
|
assert!(kvm.check_extension(Cap::UserMemory));
|
|
// I assume nobody is testing this on s390
|
|
assert!(!kvm.check_extension(Cap::S390UserSigp));
|
|
}
|
|
|
|
#[test]
|
|
fn check_vm_extension() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
assert!(vm.check_extension(Cap::UserMemory));
|
|
// I assume nobody is testing this on s390
|
|
assert!(!vm.check_extension(Cap::S390UserSigp));
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn get_supported_cpuid() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let mut cpuid = kvm.get_supported_cpuid().unwrap();
|
|
let cpuid_entries = cpuid.mut_entries_slice();
|
|
assert!(cpuid_entries.len() > 0);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn get_emulated_cpuid() {
|
|
let kvm = Kvm::new().unwrap();
|
|
kvm.get_emulated_cpuid().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn get_msr_index_list() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let msr_list = kvm.get_msr_index_list().unwrap();
|
|
assert!(msr_list.len() >= 2);
|
|
}
|
|
|
|
#[test]
|
|
fn add_memory() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm =
|
|
GuestMemory::new(&[(GuestAddress(0), 0x1000), (GuestAddress(0x5000), 0x5000)]).unwrap();
|
|
let mut vm = Vm::new(&kvm, gm).unwrap();
|
|
let mem_size = 0x1000;
|
|
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
|
|
vm.add_memory_region(GuestAddress(0x1000), Box::new(mem), false, false)
|
|
.unwrap();
|
|
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
|
|
vm.add_memory_region(GuestAddress(0x10000), Box::new(mem), false, false)
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn add_memory_ro() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
|
|
let mut vm = Vm::new(&kvm, gm).unwrap();
|
|
let mem_size = 0x1000;
|
|
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
|
|
vm.add_memory_region(GuestAddress(0x1000), Box::new(mem), true, false)
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn remove_memory_region() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
|
|
let mut vm = Vm::new(&kvm, gm).unwrap();
|
|
let mem_size = 0x1000;
|
|
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
|
|
let mem_ptr = mem.as_ptr();
|
|
let slot = vm
|
|
.add_memory_region(GuestAddress(0x1000), Box::new(mem), false, false)
|
|
.unwrap();
|
|
let removed_mem = vm.remove_memory_region(slot).unwrap();
|
|
assert_eq!(removed_mem.size(), mem_size);
|
|
assert_eq!(removed_mem.as_ptr(), mem_ptr);
|
|
}
|
|
|
|
#[test]
|
|
fn remove_invalid_memory() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
|
|
let mut vm = Vm::new(&kvm, gm).unwrap();
|
|
assert!(vm.remove_memory_region(0).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn overlap_memory() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let mut vm = Vm::new(&kvm, gm).unwrap();
|
|
let mem_size = 0x2000;
|
|
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
|
|
assert!(vm
|
|
.add_memory_region(GuestAddress(0x2000), Box::new(mem), false, false)
|
|
.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn get_memory() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let obj_addr = GuestAddress(0xf0);
|
|
vm.get_memory().write_obj_at_addr(67u8, obj_addr).unwrap();
|
|
let read_val: u8 = vm.get_memory().read_obj_from_addr(obj_addr).unwrap();
|
|
assert_eq!(read_val, 67u8);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn clock_handling() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let mut clock_data = vm.get_clock().unwrap();
|
|
clock_data.clock += 1000;
|
|
vm.set_clock(&clock_data).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn pic_handling() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
vm.create_irq_chip().unwrap();
|
|
let pic_state = vm.get_pic_state(PicId::Secondary).unwrap();
|
|
vm.set_pic_state(PicId::Secondary, &pic_state).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn ioapic_handling() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
vm.create_irq_chip().unwrap();
|
|
let ioapic_state = vm.get_ioapic_state().unwrap();
|
|
vm.set_ioapic_state(&ioapic_state).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn pit_handling() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
vm.create_irq_chip().unwrap();
|
|
vm.create_pit().unwrap();
|
|
let pit_state = vm.get_pit_state().unwrap();
|
|
vm.set_pit_state(&pit_state).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn register_ioevent() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let evtfd = Event::new().unwrap();
|
|
vm.register_ioevent(&evtfd, IoeventAddress::Pio(0xf4), Datamatch::AnyLength)
|
|
.unwrap();
|
|
vm.register_ioevent(&evtfd, IoeventAddress::Mmio(0x1000), Datamatch::AnyLength)
|
|
.unwrap();
|
|
vm.register_ioevent(
|
|
&evtfd,
|
|
IoeventAddress::Pio(0xc1),
|
|
Datamatch::U8(Some(0x7fu8)),
|
|
)
|
|
.unwrap();
|
|
vm.register_ioevent(
|
|
&evtfd,
|
|
IoeventAddress::Pio(0xc2),
|
|
Datamatch::U16(Some(0x1337u16)),
|
|
)
|
|
.unwrap();
|
|
vm.register_ioevent(
|
|
&evtfd,
|
|
IoeventAddress::Pio(0xc4),
|
|
Datamatch::U32(Some(0xdeadbeefu32)),
|
|
)
|
|
.unwrap();
|
|
vm.register_ioevent(
|
|
&evtfd,
|
|
IoeventAddress::Pio(0xc8),
|
|
Datamatch::U64(Some(0xdeadbeefdeadbeefu64)),
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn unregister_ioevent() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let evtfd = Event::new().unwrap();
|
|
vm.register_ioevent(&evtfd, IoeventAddress::Pio(0xf4), Datamatch::AnyLength)
|
|
.unwrap();
|
|
vm.register_ioevent(&evtfd, IoeventAddress::Mmio(0x1000), Datamatch::AnyLength)
|
|
.unwrap();
|
|
vm.register_ioevent(
|
|
&evtfd,
|
|
IoeventAddress::Mmio(0x1004),
|
|
Datamatch::U8(Some(0x7fu8)),
|
|
)
|
|
.unwrap();
|
|
vm.unregister_ioevent(&evtfd, IoeventAddress::Pio(0xf4), Datamatch::AnyLength)
|
|
.unwrap();
|
|
vm.unregister_ioevent(&evtfd, IoeventAddress::Mmio(0x1000), Datamatch::AnyLength)
|
|
.unwrap();
|
|
vm.unregister_ioevent(
|
|
&evtfd,
|
|
IoeventAddress::Mmio(0x1004),
|
|
Datamatch::U8(Some(0x7fu8)),
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn irqfd_resample() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let evtfd1 = Event::new().unwrap();
|
|
let evtfd2 = Event::new().unwrap();
|
|
vm.create_irq_chip().unwrap();
|
|
vm.register_irqfd_resample(&evtfd1, &evtfd2, 4).unwrap();
|
|
vm.unregister_irqfd(&evtfd1, 4).unwrap();
|
|
// Ensures the ioctl is actually reading the resamplefd.
|
|
vm.register_irqfd_resample(&evtfd1, unsafe { &Event::from_raw_descriptor(-1) }, 4)
|
|
.unwrap_err();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn set_gsi_routing() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
vm.create_irq_chip().unwrap();
|
|
vm.set_gsi_routing(&[]).unwrap();
|
|
vm.set_gsi_routing(&[IrqRoute {
|
|
gsi: 1,
|
|
source: IrqSource::Irqchip {
|
|
chip: KVM_IRQCHIP_IOAPIC,
|
|
pin: 3,
|
|
},
|
|
}])
|
|
.unwrap();
|
|
vm.set_gsi_routing(&[IrqRoute {
|
|
gsi: 1,
|
|
source: IrqSource::Msi {
|
|
address: 0xf000000,
|
|
data: 0xa0,
|
|
},
|
|
}])
|
|
.unwrap();
|
|
vm.set_gsi_routing(&[
|
|
IrqRoute {
|
|
gsi: 1,
|
|
source: IrqSource::Irqchip {
|
|
chip: KVM_IRQCHIP_IOAPIC,
|
|
pin: 3,
|
|
},
|
|
},
|
|
IrqRoute {
|
|
gsi: 2,
|
|
source: IrqSource::Msi {
|
|
address: 0xf000000,
|
|
data: 0xa0,
|
|
},
|
|
},
|
|
])
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn create_vcpu() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
Vcpu::new(0, &kvm, &vm).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn debugregs() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
|
|
let mut dregs = vcpu.get_debugregs().unwrap();
|
|
dregs.dr7 = 13;
|
|
vcpu.set_debugregs(&dregs).unwrap();
|
|
let dregs2 = vcpu.get_debugregs().unwrap();
|
|
assert_eq!(dregs.dr7, dregs2.dr7);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn xcrs() {
|
|
let kvm = Kvm::new().unwrap();
|
|
if !kvm.check_extension(Cap::Xcrs) {
|
|
return;
|
|
}
|
|
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
|
|
let mut xcrs = vcpu.get_xcrs().unwrap();
|
|
xcrs.xcrs[0].value = 1;
|
|
vcpu.set_xcrs(&xcrs).unwrap();
|
|
let xcrs2 = vcpu.get_xcrs().unwrap();
|
|
assert_eq!(xcrs.xcrs[0].value, xcrs2.xcrs[0].value);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn get_msrs() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
|
|
let mut msrs = vec![
|
|
// This one should succeed
|
|
kvm_msr_entry {
|
|
index: 0x0000011e,
|
|
..Default::default()
|
|
},
|
|
// This one will fail to fetch
|
|
kvm_msr_entry {
|
|
index: 0x000003f1,
|
|
..Default::default()
|
|
},
|
|
];
|
|
vcpu.get_msrs(&mut msrs).unwrap();
|
|
assert_eq!(msrs.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn get_hyperv_cpuid() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
|
|
let cpuid = vcpu.get_hyperv_cpuid();
|
|
// Older kernels don't support so tolerate this kind of failure.
|
|
match cpuid {
|
|
Ok(_) => {}
|
|
Err(e) => {
|
|
assert_eq!(e.errno(), EINVAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn enable_feature() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
vm.create_irq_chip().unwrap();
|
|
let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
|
|
let cap: kvm_enable_cap = kvm_sys::kvm_enable_cap {
|
|
cap: KVM_CAP_HYPERV_SYNIC,
|
|
..Default::default()
|
|
};
|
|
unsafe { vcpu.kvm_enable_cap(&cap) }.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn mp_state() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
vm.create_irq_chip().unwrap();
|
|
let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
|
|
let state = vcpu.get_mp_state().unwrap();
|
|
vcpu.set_mp_state(&state).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn set_signal_mask() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
|
|
vcpu.set_signal_mask(&[SIGRTMIN() + 0]).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn vcpu_mmap_size() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let mmap_size = kvm.get_vcpu_mmap_size().unwrap();
|
|
let page_size = pagesize();
|
|
assert!(mmap_size >= page_size);
|
|
assert!(mmap_size % page_size == 0);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
fn set_identity_map_addr() {
|
|
let kvm = Kvm::new().unwrap();
|
|
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
|
|
let vm = Vm::new(&kvm, gm).unwrap();
|
|
vm.set_identity_map_addr(GuestAddress(0x20000)).unwrap();
|
|
}
|