mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 21:55:20 +00:00
arch: move test cases to vmm crate
This saves us from adding a "kvm" feature to arch crate merely for the purpose of running tests. Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
parent
598eaf9f86
commit
d80e383dbb
@ -589,79 +589,3 @@ fn create_pci_nodes(fdt: &mut Vec<u8>, pci_device_base: u64, pci_device_size: u6
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::aarch64::gic::create_gic;
|
|
||||||
use crate::aarch64::layout;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
const LEN: u64 = 4096;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct MMIODeviceInfo {
|
|
||||||
addr: u64,
|
|
||||||
irq: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeviceInfoForFDT for MMIODeviceInfo {
|
|
||||||
fn addr(&self) -> u64 {
|
|
||||||
self.addr
|
|
||||||
}
|
|
||||||
fn irq(&self) -> u32 {
|
|
||||||
self.irq
|
|
||||||
}
|
|
||||||
fn length(&self) -> u64 {
|
|
||||||
LEN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_create_fdt_with_devices() {
|
|
||||||
let mut regions = Vec::new();
|
|
||||||
regions.push((
|
|
||||||
GuestAddress(layout::RAM_64BIT_START),
|
|
||||||
(layout::FDT_MAX_SIZE + 0x1000) as usize,
|
|
||||||
));
|
|
||||||
let mem = GuestMemoryMmap::from_ranges(®ions).expect("Cannot initialize memory");
|
|
||||||
|
|
||||||
let dev_info: HashMap<(DeviceType, std::string::String), MMIODeviceInfo> = [
|
|
||||||
(
|
|
||||||
(DeviceType::Serial, DeviceType::Serial.to_string()),
|
|
||||||
MMIODeviceInfo { addr: 0x00, irq: 1 },
|
|
||||||
),
|
|
||||||
(
|
|
||||||
(DeviceType::Virtio(1), "virtio".to_string()),
|
|
||||||
MMIODeviceInfo {
|
|
||||||
addr: 0x00 + LEN,
|
|
||||||
irq: 2,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
(DeviceType::RTC, "rtc".to_string()),
|
|
||||||
MMIODeviceInfo {
|
|
||||||
addr: 0x00 + 2 * LEN,
|
|
||||||
irq: 3,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().unwrap();
|
|
||||||
let gic = create_gic(&vm, 1, false).unwrap();
|
|
||||||
assert!(create_fdt(
|
|
||||||
&mem,
|
|
||||||
&CString::new("console=tty0").unwrap(),
|
|
||||||
vec![0],
|
|
||||||
&dev_info,
|
|
||||||
&gic,
|
|
||||||
&None,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.is_ok())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -170,16 +170,3 @@ pub fn create_gic(
|
|||||||
.or_else(|_| GICv3::new(vm, vcpu_count).or_else(|_| GICv2::new(vm, vcpu_count)))
|
.or_else(|_| GICv3::new(vm, vcpu_count).or_else(|_| GICv2::new(vm, vcpu_count)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_create_gic() {
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().unwrap();
|
|
||||||
|
|
||||||
assert!(create_gic(&vm, 1, false).is_ok());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -154,43 +154,3 @@ pub fn setup_regs(
|
|||||||
pub fn read_mpidr(vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<u64> {
|
pub fn read_mpidr(vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<u64> {
|
||||||
vcpu.get_one_reg(MPIDR_EL1).map_err(Error::GetSysRegister)
|
vcpu.get_one_reg(MPIDR_EL1).map_err(Error::GetSysRegister)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::aarch64::layout;
|
|
||||||
use vm_memory::{GuestAddress, GuestMemoryMmap};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_setup_regs() {
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().unwrap();
|
|
||||||
let vcpu = vm.create_vcpu(0).unwrap();
|
|
||||||
let mut regions = Vec::new();
|
|
||||||
regions.push((
|
|
||||||
GuestAddress(layout::RAM_64BIT_START),
|
|
||||||
(layout::FDT_MAX_SIZE + 0x1000) as usize,
|
|
||||||
));
|
|
||||||
let mem = GuestMemoryMmap::from_ranges(®ions).expect("Cannot initialize memory");
|
|
||||||
|
|
||||||
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
|
|
||||||
vm.get_preferred_target(&mut kvi).unwrap();
|
|
||||||
vcpu.vcpu_init(&kvi).unwrap();
|
|
||||||
|
|
||||||
assert!(setup_regs(&vcpu, 0, 0x0, &mem).is_ok());
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_read_mpidr() {
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().unwrap();
|
|
||||||
let vcpu = vm.create_vcpu(0).unwrap();
|
|
||||||
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
|
|
||||||
vm.get_preferred_target(&mut kvi).unwrap();
|
|
||||||
|
|
||||||
// Must fail when vcpu is not initialized yet.
|
|
||||||
assert!(read_mpidr(&vcpu).is_err());
|
|
||||||
|
|
||||||
vcpu.vcpu_init(&kvi).unwrap();
|
|
||||||
assert_eq!(read_mpidr(&vcpu).unwrap(), 0x80000000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -23,12 +23,12 @@ pub enum Error {
|
|||||||
pub type Result<T> = result::Result<T, hypervisor::HypervisorCpuError>;
|
pub type Result<T> = result::Result<T, hypervisor::HypervisorCpuError>;
|
||||||
|
|
||||||
// Defines poached from apicdef.h kernel header.
|
// Defines poached from apicdef.h kernel header.
|
||||||
const APIC_LVT0: usize = 0x350;
|
pub const APIC_LVT0: usize = 0x350;
|
||||||
const APIC_LVT1: usize = 0x360;
|
pub const APIC_LVT1: usize = 0x360;
|
||||||
const APIC_MODE_NMI: u32 = 0x4;
|
pub const APIC_MODE_NMI: u32 = 0x4;
|
||||||
const APIC_MODE_EXTINT: u32 = 0x7;
|
pub const APIC_MODE_EXTINT: u32 = 0x7;
|
||||||
|
|
||||||
fn get_klapic_reg(klapic: &LapicState, reg_offset: usize) -> u32 {
|
pub fn get_klapic_reg(klapic: &LapicState, reg_offset: usize) -> u32 {
|
||||||
let sliceu8 = unsafe {
|
let sliceu8 = unsafe {
|
||||||
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
|
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
|
||||||
// Cursors are only readable on arrays of u8, not i8(c_char).
|
// Cursors are only readable on arrays of u8, not i8(c_char).
|
||||||
@ -41,7 +41,7 @@ fn get_klapic_reg(klapic: &LapicState, reg_offset: usize) -> u32 {
|
|||||||
.expect("Failed to read klapic register")
|
.expect("Failed to read klapic register")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_klapic_reg(klapic: &mut LapicState, reg_offset: usize, value: u32) {
|
pub fn set_klapic_reg(klapic: &mut LapicState, reg_offset: usize, value: u32) {
|
||||||
let sliceu8 = unsafe {
|
let sliceu8 = unsafe {
|
||||||
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
|
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
|
||||||
// Cursors are only readable on arrays of u8, not i8(c_char).
|
// Cursors are only readable on arrays of u8, not i8(c_char).
|
||||||
@ -54,7 +54,7 @@ fn set_klapic_reg(klapic: &mut LapicState, reg_offset: usize, value: u32) {
|
|||||||
.expect("Failed to write klapic register")
|
.expect("Failed to write klapic register")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_apic_delivery_mode(reg: u32, mode: u32) -> u32 {
|
pub fn set_apic_delivery_mode(reg: u32, mode: u32) -> u32 {
|
||||||
((reg) & !0x700) | ((mode) << 8)
|
((reg) & !0x700) | ((mode) << 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,30 +118,4 @@ mod tests {
|
|||||||
let after: Vec<u32> = v.iter().map(|x| ((*x & !0x700) | ((2) << 8))).collect();
|
let after: Vec<u32> = v.iter().map(|x| ((*x & !0x700) | ((2) << 8))).collect();
|
||||||
assert_eq!(v, after);
|
assert_eq!(v, after);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_setlint() {
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().expect("new VM fd creation failed");
|
|
||||||
assert!(hv.check_capability(hypervisor::kvm::Cap::Irqchip));
|
|
||||||
// Calling get_lapic will fail if there is no irqchip before hand.
|
|
||||||
assert!(vm.create_irq_chip().is_ok());
|
|
||||||
let vcpu = vm.create_vcpu(0).unwrap();
|
|
||||||
let klapic_before: LapicState = vcpu.get_lapic().unwrap();
|
|
||||||
|
|
||||||
// Compute the value that is expected to represent LVT0 and LVT1.
|
|
||||||
let lint0 = get_klapic_reg(&klapic_before, APIC_LVT0);
|
|
||||||
let lint1 = get_klapic_reg(&klapic_before, APIC_LVT1);
|
|
||||||
let lint0_mode_expected = set_apic_delivery_mode(lint0, APIC_MODE_EXTINT);
|
|
||||||
let lint1_mode_expected = set_apic_delivery_mode(lint1, APIC_MODE_NMI);
|
|
||||||
|
|
||||||
set_lint(&vcpu).unwrap();
|
|
||||||
|
|
||||||
// Compute the value that represents LVT0 and LVT1 after set_lint.
|
|
||||||
let klapic_actual: LapicState = vcpu.get_lapic().unwrap();
|
|
||||||
let lint0_mode_actual = get_klapic_reg(&klapic_actual, APIC_LVT0);
|
|
||||||
let lint1_mode_actual = get_klapic_reg(&klapic_actual, APIC_LVT1);
|
|
||||||
assert_eq!(lint0_mode_expected, lint0_mode_actual);
|
|
||||||
assert_eq!(lint1_mode_expected, lint1_mode_actual);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ fn write_idt_value(val: u64, guest_mem: &GuestMemoryMmap) -> Result<()> {
|
|||||||
.map_err(Error::WriteIDT)
|
.map_err(Error::WriteIDT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_segments_and_sregs(
|
pub fn configure_segments_and_sregs(
|
||||||
mem: &GuestMemoryMmap,
|
mem: &GuestMemoryMmap,
|
||||||
sregs: &mut SpecialRegisters,
|
sregs: &mut SpecialRegisters,
|
||||||
boot_prot: BootProtocol,
|
boot_prot: BootProtocol,
|
||||||
@ -222,7 +222,7 @@ fn configure_segments_and_sregs(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_page_tables(mem: &GuestMemoryMmap, sregs: &mut SpecialRegisters) -> Result<()> {
|
pub fn setup_page_tables(mem: &GuestMemoryMmap, sregs: &mut SpecialRegisters) -> Result<()> {
|
||||||
// Puts PML5 or PML4 right after zero page but aligned to 4k.
|
// Puts PML5 or PML4 right after zero page but aligned to 4k.
|
||||||
if unsafe { std::arch::x86_64::__cpuid(7).ecx } & (1 << 16) != 0 {
|
if unsafe { std::arch::x86_64::__cpuid(7).ecx } & (1 << 16) != 0 {
|
||||||
// Entry covering VA [0..256TB)
|
// Entry covering VA [0..256TB)
|
||||||
@ -362,99 +362,4 @@ mod tests {
|
|||||||
assert_eq!(X86_CR4_PAE, sregs.cr4);
|
assert_eq!(X86_CR4_PAE, sregs.cr4);
|
||||||
assert_eq!(X86_CR0_PG, sregs.cr0);
|
assert_eq!(X86_CR0_PG, sregs.cr0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_setup_fpu() {
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().expect("new VM fd creation failed");
|
|
||||||
let vcpu = vm.create_vcpu(0).unwrap();
|
|
||||||
setup_fpu(&vcpu).unwrap();
|
|
||||||
|
|
||||||
let expected_fpu: FpuState = FpuState {
|
|
||||||
fcw: 0x37f,
|
|
||||||
mxcsr: 0x1f80,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let actual_fpu: FpuState = vcpu.get_fpu().unwrap();
|
|
||||||
// TODO: auto-generate kvm related structures with PartialEq on.
|
|
||||||
assert_eq!(expected_fpu.fcw, actual_fpu.fcw);
|
|
||||||
// Setting the mxcsr register from FpuState inside setup_fpu does not influence anything.
|
|
||||||
// See 'kvm_arch_vcpu_ioctl_set_fpu' from arch/x86/kvm/x86.c.
|
|
||||||
// The mxcsr will stay 0 and the assert below fails. Decide whether or not we should
|
|
||||||
// remove it at all.
|
|
||||||
// assert!(expected_fpu.mxcsr == actual_fpu.mxcsr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_setup_msrs() {
|
|
||||||
use hypervisor::arch::x86::msr_index;
|
|
||||||
use hypervisor::x86_64::{MsrEntries, MsrEntry};
|
|
||||||
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().expect("new VM fd creation failed");
|
|
||||||
let vcpu = vm.create_vcpu(0).unwrap();
|
|
||||||
setup_msrs(&vcpu).unwrap();
|
|
||||||
|
|
||||||
// This test will check against the last MSR entry configured (the tenth one).
|
|
||||||
// See create_msr_entries for details.
|
|
||||||
let mut msrs = MsrEntries::from_entries(&[MsrEntry {
|
|
||||||
index: msr_index::MSR_IA32_MISC_ENABLE,
|
|
||||||
..Default::default()
|
|
||||||
}]);
|
|
||||||
|
|
||||||
// get_msrs returns the number of msrs that it succeed in reading. We only want to read 1
|
|
||||||
// in this test case scenario.
|
|
||||||
let read_msrs = vcpu.get_msrs(&mut msrs).unwrap();
|
|
||||||
assert_eq!(read_msrs, 1);
|
|
||||||
|
|
||||||
// Official entries that were setup when we did setup_msrs. We need to assert that the
|
|
||||||
// tenth one (i.e the one with index msr_index::MSR_IA32_MISC_ENABLE has the data we
|
|
||||||
// expect.
|
|
||||||
let entry_vec = hypervisor::x86_64::boot_msr_entries();
|
|
||||||
assert_eq!(entry_vec.as_slice()[9], msrs.as_slice()[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_setup_regs() {
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().expect("new VM fd creation failed");
|
|
||||||
let vcpu = vm.create_vcpu(0).unwrap();
|
|
||||||
|
|
||||||
let expected_regs: StandardRegisters = StandardRegisters {
|
|
||||||
rflags: 0x0000000000000002u64,
|
|
||||||
rip: 1,
|
|
||||||
rsp: 2,
|
|
||||||
rbp: 2,
|
|
||||||
rsi: 3,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
setup_regs(
|
|
||||||
&vcpu,
|
|
||||||
expected_regs.rip,
|
|
||||||
expected_regs.rsp,
|
|
||||||
expected_regs.rsi,
|
|
||||||
BootProtocol::LinuxBoot,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let actual_regs: StandardRegisters = vcpu.get_regs().unwrap();
|
|
||||||
assert_eq!(actual_regs, expected_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_setup_sregs() {
|
|
||||||
let hv = hypervisor::new().unwrap();
|
|
||||||
let vm = hv.create_vm().expect("new VM fd creation failed");
|
|
||||||
let vcpu = vm.create_vcpu(0).unwrap();
|
|
||||||
|
|
||||||
let mut expected_sregs: SpecialRegisters = vcpu.get_sregs().unwrap();
|
|
||||||
let gm = create_guest_mem();
|
|
||||||
configure_segments_and_sregs(&gm, &mut expected_sregs, BootProtocol::LinuxBoot).unwrap();
|
|
||||||
setup_page_tables(&gm, &mut expected_sregs).unwrap();
|
|
||||||
|
|
||||||
setup_sregs(&gm, &vcpu, BootProtocol::LinuxBoot).unwrap();
|
|
||||||
let actual_sregs: SpecialRegisters = vcpu.get_sregs().unwrap();
|
|
||||||
assert_eq!(expected_sregs, actual_sregs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
175
vmm/src/cpu.rs
175
vmm/src/cpu.rs
@ -1404,3 +1404,178 @@ impl Snapshottable for CpuManager {
|
|||||||
|
|
||||||
impl Transportable for CpuManager {}
|
impl Transportable for CpuManager {}
|
||||||
impl Migratable for CpuManager {}
|
impl Migratable for CpuManager {}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use arch::x86_64::interrupts::*;
|
||||||
|
use arch::x86_64::regs::*;
|
||||||
|
use arch::x86_64::BootProtocol;
|
||||||
|
use hypervisor::x86_64::{FpuState, LapicState, SpecialRegisters, StandardRegisters};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_setlint() {
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||||
|
assert!(hv.check_capability(hypervisor::kvm::Cap::Irqchip));
|
||||||
|
// Calling get_lapic will fail if there is no irqchip before hand.
|
||||||
|
assert!(vm.create_irq_chip().is_ok());
|
||||||
|
let vcpu = vm.create_vcpu(0).unwrap();
|
||||||
|
let klapic_before: LapicState = vcpu.get_lapic().unwrap();
|
||||||
|
|
||||||
|
// Compute the value that is expected to represent LVT0 and LVT1.
|
||||||
|
let lint0 = get_klapic_reg(&klapic_before, APIC_LVT0);
|
||||||
|
let lint1 = get_klapic_reg(&klapic_before, APIC_LVT1);
|
||||||
|
let lint0_mode_expected = set_apic_delivery_mode(lint0, APIC_MODE_EXTINT);
|
||||||
|
let lint1_mode_expected = set_apic_delivery_mode(lint1, APIC_MODE_NMI);
|
||||||
|
|
||||||
|
set_lint(&vcpu).unwrap();
|
||||||
|
|
||||||
|
// Compute the value that represents LVT0 and LVT1 after set_lint.
|
||||||
|
let klapic_actual: LapicState = vcpu.get_lapic().unwrap();
|
||||||
|
let lint0_mode_actual = get_klapic_reg(&klapic_actual, APIC_LVT0);
|
||||||
|
let lint1_mode_actual = get_klapic_reg(&klapic_actual, APIC_LVT1);
|
||||||
|
assert_eq!(lint0_mode_expected, lint0_mode_actual);
|
||||||
|
assert_eq!(lint1_mode_expected, lint1_mode_actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_setup_fpu() {
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||||
|
let vcpu = vm.create_vcpu(0).unwrap();
|
||||||
|
setup_fpu(&vcpu).unwrap();
|
||||||
|
|
||||||
|
let expected_fpu: FpuState = FpuState {
|
||||||
|
fcw: 0x37f,
|
||||||
|
mxcsr: 0x1f80,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let actual_fpu: FpuState = vcpu.get_fpu().unwrap();
|
||||||
|
// TODO: auto-generate kvm related structures with PartialEq on.
|
||||||
|
assert_eq!(expected_fpu.fcw, actual_fpu.fcw);
|
||||||
|
// Setting the mxcsr register from FpuState inside setup_fpu does not influence anything.
|
||||||
|
// See 'kvm_arch_vcpu_ioctl_set_fpu' from arch/x86/kvm/x86.c.
|
||||||
|
// The mxcsr will stay 0 and the assert below fails. Decide whether or not we should
|
||||||
|
// remove it at all.
|
||||||
|
// assert!(expected_fpu.mxcsr == actual_fpu.mxcsr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_setup_msrs() {
|
||||||
|
use hypervisor::arch::x86::msr_index;
|
||||||
|
use hypervisor::x86_64::{MsrEntries, MsrEntry};
|
||||||
|
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||||
|
let vcpu = vm.create_vcpu(0).unwrap();
|
||||||
|
setup_msrs(&vcpu).unwrap();
|
||||||
|
|
||||||
|
// This test will check against the last MSR entry configured (the tenth one).
|
||||||
|
// See create_msr_entries for details.
|
||||||
|
let mut msrs = MsrEntries::from_entries(&[MsrEntry {
|
||||||
|
index: msr_index::MSR_IA32_MISC_ENABLE,
|
||||||
|
..Default::default()
|
||||||
|
}]);
|
||||||
|
|
||||||
|
// get_msrs returns the number of msrs that it succeed in reading. We only want to read 1
|
||||||
|
// in this test case scenario.
|
||||||
|
let read_msrs = vcpu.get_msrs(&mut msrs).unwrap();
|
||||||
|
assert_eq!(read_msrs, 1);
|
||||||
|
|
||||||
|
// Official entries that were setup when we did setup_msrs. We need to assert that the
|
||||||
|
// tenth one (i.e the one with index msr_index::MSR_IA32_MISC_ENABLE has the data we
|
||||||
|
// expect.
|
||||||
|
let entry_vec = hypervisor::x86_64::boot_msr_entries();
|
||||||
|
assert_eq!(entry_vec.as_slice()[9], msrs.as_slice()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_setup_regs() {
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||||
|
let vcpu = vm.create_vcpu(0).unwrap();
|
||||||
|
|
||||||
|
let expected_regs: StandardRegisters = StandardRegisters {
|
||||||
|
rflags: 0x0000000000000002u64,
|
||||||
|
rip: 1,
|
||||||
|
rsp: 2,
|
||||||
|
rbp: 2,
|
||||||
|
rsi: 3,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
setup_regs(
|
||||||
|
&vcpu,
|
||||||
|
expected_regs.rip,
|
||||||
|
expected_regs.rsp,
|
||||||
|
expected_regs.rsi,
|
||||||
|
BootProtocol::LinuxBoot,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let actual_regs: StandardRegisters = vcpu.get_regs().unwrap();
|
||||||
|
assert_eq!(actual_regs, expected_regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_setup_sregs() {
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||||
|
let vcpu = vm.create_vcpu(0).unwrap();
|
||||||
|
|
||||||
|
let mut expected_sregs: SpecialRegisters = vcpu.get_sregs().unwrap();
|
||||||
|
let gm = GuestMemoryMmap::from_ranges(&vec![(GuestAddress(0), 0x10000)]).unwrap();
|
||||||
|
configure_segments_and_sregs(&gm, &mut expected_sregs, BootProtocol::LinuxBoot).unwrap();
|
||||||
|
setup_page_tables(&gm, &mut expected_sregs).unwrap();
|
||||||
|
|
||||||
|
setup_sregs(&gm, &vcpu, BootProtocol::LinuxBoot).unwrap();
|
||||||
|
let actual_sregs: SpecialRegisters = vcpu.get_sregs().unwrap();
|
||||||
|
assert_eq!(expected_sregs, actual_sregs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use arch::aarch64::layout;
|
||||||
|
use arch::aarch64::regs::*;
|
||||||
|
use hypervisor::kvm::kvm_bindings;
|
||||||
|
use vm_memory::{GuestAddress, GuestMemoryMmap};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_setup_regs() {
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
let vcpu = vm.create_vcpu(0).unwrap();
|
||||||
|
let mut regions = Vec::new();
|
||||||
|
regions.push((
|
||||||
|
GuestAddress(layout::RAM_64BIT_START),
|
||||||
|
(layout::FDT_MAX_SIZE + 0x1000) as usize,
|
||||||
|
));
|
||||||
|
let mem = GuestMemoryMmap::from_ranges(®ions).expect("Cannot initialize memory");
|
||||||
|
|
||||||
|
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
|
||||||
|
vm.get_preferred_target(&mut kvi).unwrap();
|
||||||
|
vcpu.vcpu_init(&kvi).unwrap();
|
||||||
|
|
||||||
|
assert!(setup_regs(&vcpu, 0, 0x0, &mem).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_mpidr() {
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
let vcpu = vm.create_vcpu(0).unwrap();
|
||||||
|
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
|
||||||
|
vm.get_preferred_target(&mut kvi).unwrap();
|
||||||
|
|
||||||
|
// Must fail when vcpu is not initialized yet.
|
||||||
|
assert!(read_mpidr(&vcpu).is_err());
|
||||||
|
|
||||||
|
vcpu.vcpu_init(&kvi).unwrap();
|
||||||
|
assert_eq!(read_mpidr(&vcpu).unwrap(), 0x80000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -432,3 +432,17 @@ pub mod kvm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use arch::aarch64::gic::create_gic;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_create_gic() {
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
|
||||||
|
assert!(create_gic(&vm, 1, false).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1490,6 +1490,85 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use arch::aarch64::fdt::create_fdt;
|
||||||
|
use arch::aarch64::gic::create_gic;
|
||||||
|
use arch::aarch64::{layout, DeviceInfoForFDT};
|
||||||
|
use arch::DeviceType;
|
||||||
|
use vm_memory::{GuestAddress, GuestMemoryMmap};
|
||||||
|
|
||||||
|
const LEN: u64 = 4096;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MMIODeviceInfo {
|
||||||
|
addr: u64,
|
||||||
|
irq: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceInfoForFDT for MMIODeviceInfo {
|
||||||
|
fn addr(&self) -> u64 {
|
||||||
|
self.addr
|
||||||
|
}
|
||||||
|
fn irq(&self) -> u32 {
|
||||||
|
self.irq
|
||||||
|
}
|
||||||
|
fn length(&self) -> u64 {
|
||||||
|
LEN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_create_fdt_with_devices() {
|
||||||
|
let mut regions = Vec::new();
|
||||||
|
regions.push((
|
||||||
|
GuestAddress(layout::RAM_64BIT_START),
|
||||||
|
(layout::FDT_MAX_SIZE + 0x1000) as usize,
|
||||||
|
));
|
||||||
|
let mem = GuestMemoryMmap::from_ranges(®ions).expect("Cannot initialize memory");
|
||||||
|
|
||||||
|
let dev_info: HashMap<(DeviceType, std::string::String), MMIODeviceInfo> = [
|
||||||
|
(
|
||||||
|
(DeviceType::Serial, DeviceType::Serial.to_string()),
|
||||||
|
MMIODeviceInfo { addr: 0x00, irq: 1 },
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(DeviceType::Virtio(1), "virtio".to_string()),
|
||||||
|
MMIODeviceInfo {
|
||||||
|
addr: 0x00 + LEN,
|
||||||
|
irq: 2,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(DeviceType::RTC, "rtc".to_string()),
|
||||||
|
MMIODeviceInfo {
|
||||||
|
addr: 0x00 + 2 * LEN,
|
||||||
|
irq: 3,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let hv = hypervisor::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
let gic = create_gic(&vm, 1, false).unwrap();
|
||||||
|
assert!(create_fdt(
|
||||||
|
&mem,
|
||||||
|
&CString::new("console=tty0").unwrap(),
|
||||||
|
vec![0],
|
||||||
|
&dev_info,
|
||||||
|
&gic,
|
||||||
|
&None,
|
||||||
|
&None,
|
||||||
|
)
|
||||||
|
.is_ok())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_vm() {
|
pub fn test_vm() {
|
||||||
|
Loading…
Reference in New Issue
Block a user