1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
use crate::hypervisor::{
handle_ioexit, IoHandleStatus, PhysicalMemory, SerialPrinter, TestEnvironment,
};
use kvm::{Exit, System};
use x86::bits64::paging::VAddr;
use crate::X86TestFn;
/// Start the test harness.
pub fn test_start(ntests: usize) {
println!("running {} tests (using x86test runner)", ntests)
}
/// Signals that given test is ignored.
pub fn test_ignored(name: &str) {
println!("test {} ... ignored", name);
}
/// Output before a new test is run.
pub fn test_before_run(name: &str) {
print!("test {} ... ", name);
}
/// Output when a test is fails.
pub fn test_failed(_name: &str) {
println!("FAILED");
}
/// Output when a test succeeds.
pub fn test_success(_name: &str) {
println!("OK");
}
/// Summary display at the end of the test run.
pub fn test_summary(passed: usize, failed: usize, ignored: usize) {
println!(
"\ntest result: {} {} passed; {} failed; {} ignored",
if failed == 0 { "OK" } else { "FAILED" },
passed,
failed,
ignored
);
if failed != 0 {
std::process::exit(101);
}
}
/// Actual logic to run a list of KVM tests.
pub fn runner(tests: &[&X86TestFn]) {
test_start(tests.len());
let mut failed = 0;
let mut ignored = 0;
let mut passed = 0;
for test in tests {
if test.ignore {
ignored += 1;
test_ignored(test.name);
} else {
test_before_run(test.name);
let sys = System::initialize().unwrap();
let mut stack = PhysicalMemory::new(0x3000000);
let mut heap = PhysicalMemory::new(0x6000000);
let mut ptables = PhysicalMemory::new(0x9000000);
let mut test_environment =
TestEnvironment::new(&sys, &mut stack, &mut heap, &mut ptables);
let mut printer: SerialPrinter = SerialPrinter::new();
let test_fn_vaddr = VAddr::from_usize(test.testfn.0 as *const () as usize);
let mut vcpu = test_environment.create_vcpu(test_fn_vaddr);
let mut vm_is_done = false;
let mut test_panicked = false;
while !vm_is_done {
let run = unsafe { vcpu.run() }.unwrap();
match run.exit_reason {
Exit::Io => {
match handle_ioexit(test, &mut vcpu, &run, &mut printer) {
Result::Ok(IoHandleStatus::Handled) => { /* Continue */ }
Result::Ok(IoHandleStatus::TestSuccessful) => vm_is_done = true,
Result::Ok(IoHandleStatus::TestPanic(code)) => {
if !test.should_panic {
debug!(
"IoHandleStatus::TestPanic {} should_panic is {}",
code, test.should_panic
);
}
vm_is_done = true;
test_panicked = true;
}
Result::Err(err) => {
if !test.should_panic {
println!("Test failed due to unexpected IO: {:?}", err);
}
vm_is_done = true;
test_panicked = true;
}
}
}
Exit::Shutdown => {
println!(
"Exit::Shutdown cpu.get_regs() {:#x}",
vcpu.get_regs().unwrap().rip
);
println!("Exit::Shutdown cpu.get_sregs() {:#?}", vcpu.get_sregs());
vm_is_done = true;
test_panicked = true;
}
Exit::Hlt => {
vm_is_done = true;
test_panicked = if test.should_halt { false } else { true };
}
_ => {
test_panicked = true;
println!("Unknown exit reason: {:?}", run.exit_reason);
break;
}
}
}
if test_panicked == test.should_panic {
passed += 1;
test_success(test.name);
} else {
failed += 1;
test_failed(test.name);
}
}
}
test_summary(passed, failed, ignored);
}
|