Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/hypervisor/tests/kvm/x86_64.rs
5394 views
1
// Copyright 2022 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use hypervisor::kvm::get_cpuid_with_initial_capacity;
6
use hypervisor::kvm::Kvm;
7
use hypervisor::kvm::KvmVcpu;
8
use hypervisor::kvm::KvmVm;
9
use hypervisor::DeliveryMode;
10
use hypervisor::DeliveryStatus;
11
use hypervisor::DestinationMode;
12
use hypervisor::Fpu;
13
use hypervisor::Hypervisor;
14
use hypervisor::HypervisorCap;
15
use hypervisor::HypervisorX86_64;
16
use hypervisor::IoapicRedirectionTableEntry;
17
use hypervisor::IoapicState;
18
use hypervisor::IrqRoute;
19
use hypervisor::IrqSource;
20
use hypervisor::IrqSourceChip;
21
use hypervisor::LapicState;
22
use hypervisor::PicInitState;
23
use hypervisor::PicState;
24
use hypervisor::PitChannelState;
25
use hypervisor::PitRWMode;
26
use hypervisor::PitRWState;
27
use hypervisor::PitState;
28
use hypervisor::TriggerMode;
29
use hypervisor::Vm;
30
use hypervisor::VmCap;
31
use hypervisor::VmX86_64;
32
use kvm_sys::*;
33
use vm_memory::GuestAddress;
34
use vm_memory::GuestMemory;
35
36
#[test]
37
fn get_supported_cpuid() {
38
let hypervisor = Kvm::new().unwrap();
39
let cpuid = hypervisor.get_supported_cpuid().unwrap();
40
assert!(!cpuid.cpu_id_entries.is_empty());
41
}
42
43
#[test]
44
fn get_msr_index_list() {
45
let kvm = Kvm::new().unwrap();
46
let msr_list = kvm.get_msr_index_list().unwrap();
47
assert!(msr_list.len() >= 2);
48
}
49
50
#[test]
51
fn entries_double_on_error() {
52
let hypervisor = Kvm::new().unwrap();
53
let cpuid = get_cpuid_with_initial_capacity(&hypervisor, KVM_GET_SUPPORTED_CPUID, 4).unwrap();
54
assert!(cpuid.cpu_id_entries.len() > 4);
55
}
56
57
#[test]
58
fn check_vm_arch_capability() {
59
let kvm = Kvm::new().unwrap();
60
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
61
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
62
assert!(vm.check_capability(VmCap::PvClock));
63
}
64
65
#[test]
66
fn pic_state() {
67
let state = PicState {
68
last_irr: 0b00000001,
69
irr: 0b00000010,
70
imr: 0b00000100,
71
isr: 0b00001000,
72
priority_add: 0b00010000,
73
irq_base: 0b00100000,
74
read_reg_select: false,
75
poll: true,
76
special_mask: true,
77
init_state: PicInitState::Icw3,
78
auto_eoi: true,
79
rotate_on_auto_eoi: false,
80
special_fully_nested_mode: true,
81
use_4_byte_icw: true,
82
elcr: 0b01000000,
83
elcr_mask: 0b10000000,
84
};
85
86
let kvm_state = kvm_pic_state::from(&state);
87
88
assert_eq!(kvm_state.last_irr, 0b00000001);
89
assert_eq!(kvm_state.irr, 0b00000010);
90
assert_eq!(kvm_state.imr, 0b00000100);
91
assert_eq!(kvm_state.isr, 0b00001000);
92
assert_eq!(kvm_state.priority_add, 0b00010000);
93
assert_eq!(kvm_state.irq_base, 0b00100000);
94
assert_eq!(kvm_state.read_reg_select, 0);
95
assert_eq!(kvm_state.poll, 1);
96
assert_eq!(kvm_state.special_mask, 1);
97
assert_eq!(kvm_state.init_state, 0b10);
98
assert_eq!(kvm_state.auto_eoi, 1);
99
assert_eq!(kvm_state.rotate_on_auto_eoi, 0);
100
assert_eq!(kvm_state.special_fully_nested_mode, 1);
101
assert_eq!(kvm_state.auto_eoi, 1);
102
assert_eq!(kvm_state.elcr, 0b01000000);
103
assert_eq!(kvm_state.elcr_mask, 0b10000000);
104
105
let orig_state = PicState::from(&kvm_state);
106
assert_eq!(state, orig_state);
107
}
108
109
#[test]
110
fn ioapic_state() {
111
let mut entry = IoapicRedirectionTableEntry::default();
112
let noredir = IoapicRedirectionTableEntry::default();
113
114
// default entry should be 0
115
assert_eq!(entry.get(0, 64), 0);
116
117
// set some values on our entry
118
entry.set_vector(0b11111111);
119
entry.set_delivery_mode(DeliveryMode::SMI);
120
entry.set_dest_mode(DestinationMode::Physical);
121
entry.set_delivery_status(DeliveryStatus::Pending);
122
entry.set_polarity(1);
123
entry.set_remote_irr(true);
124
entry.set_trigger_mode(TriggerMode::Level);
125
entry.set_interrupt_mask(true);
126
entry.set_dest_id(0b10101010);
127
128
// Bit repr as: destid-reserved--------------------------------flags----vector--
129
let bit_repr = 0b1010101000000000000000000000000000000000000000011111001011111111;
130
// where flags is [interrupt_mask(1), trigger_mode(Level=1), remote_irr(1), polarity(1),
131
// delivery_status(Pending=1), dest_mode(Physical=0), delivery_mode(SMI=010)]
132
133
assert_eq!(entry.get(0, 64), bit_repr);
134
135
let mut state = IoapicState {
136
base_address: 1,
137
ioregsel: 2,
138
ioapicid: 4,
139
current_interrupt_level_bitmap: 8,
140
redirect_table: [noredir; 24],
141
};
142
143
// Initialize first 24 (kvm_state limit) redirection entries
144
for i in 0..24 {
145
state.redirect_table[i] = entry;
146
}
147
148
let kvm_state = kvm_ioapic_state::from(&state);
149
assert_eq!(kvm_state.base_address, 1);
150
assert_eq!(kvm_state.ioregsel, 2);
151
assert_eq!(kvm_state.id, 4);
152
assert_eq!(kvm_state.irr, 8);
153
assert_eq!(kvm_state.pad, 0);
154
// check first 24 entries
155
for i in 0..24 {
156
assert_eq!(
157
{
158
// SAFETY: trivially safe
159
unsafe { kvm_state.redirtbl[i].bits }
160
},
161
bit_repr
162
);
163
}
164
165
// compare with a conversion back
166
assert_eq!(state, IoapicState::from(&kvm_state));
167
}
168
169
#[test]
170
fn lapic_state() {
171
let mut state = LapicState { regs: [0; 64] };
172
// Apic id register, 4 bytes each with a different bit set
173
state.regs[2] = 1 | 2 << 8 | 4 << 16 | 8 << 24;
174
175
let kvm_state = kvm_lapic_state::from(&state);
176
177
// check little endian bytes in kvm_state
178
for i in 0..4 {
179
assert_eq!(kvm_state.regs[32 + i] as u8, 2u8.pow(i as u32));
180
}
181
182
// Test converting back to a LapicState
183
assert_eq!(state, LapicState::from(&kvm_state));
184
}
185
186
#[test]
187
fn pit_state() {
188
let channel = PitChannelState {
189
count: 256,
190
latched_count: 512,
191
count_latched: PitRWState::LSB,
192
status_latched: false,
193
status: 7,
194
read_state: PitRWState::MSB,
195
write_state: PitRWState::Word1,
196
reload_value: 8,
197
rw_mode: PitRWMode::Both,
198
mode: 5,
199
bcd: false,
200
gate: true,
201
count_load_time: 1024,
202
};
203
204
let kvm_channel = kvm_pit_channel_state::from(&channel);
205
206
// compare the various field translations
207
assert_eq!(kvm_channel.count, 256);
208
assert_eq!(kvm_channel.latched_count, 512);
209
assert_eq!(kvm_channel.count_latched, 1);
210
assert_eq!(kvm_channel.status_latched, 0);
211
assert_eq!(kvm_channel.status, 7);
212
assert_eq!(kvm_channel.read_state, 2);
213
assert_eq!(kvm_channel.write_state, 4);
214
assert_eq!(kvm_channel.write_latch, 8);
215
assert_eq!(kvm_channel.rw_mode, 3);
216
assert_eq!(kvm_channel.mode, 5);
217
assert_eq!(kvm_channel.bcd, 0);
218
assert_eq!(kvm_channel.gate, 1);
219
assert_eq!(kvm_channel.count_load_time, 1024);
220
221
// convert back and compare
222
assert_eq!(channel, PitChannelState::from(&kvm_channel));
223
224
// convert the full pitstate
225
let state = PitState {
226
channels: [channel, channel, channel],
227
flags: 255,
228
};
229
let kvm_state = kvm_pit_state2::from(&state);
230
231
assert_eq!(kvm_state.flags, 255);
232
233
// compare a channel
234
assert_eq!(channel, PitChannelState::from(&kvm_state.channels[0]));
235
// convert back and compare
236
assert_eq!(state, PitState::from(&kvm_state));
237
}
238
239
#[test]
240
fn clock_handling() {
241
let kvm = Kvm::new().unwrap();
242
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
243
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
244
let mut clock_data = vm.get_pvclock().unwrap();
245
clock_data.clock += 1000;
246
vm.set_pvclock(&clock_data).unwrap();
247
}
248
249
#[test]
250
fn set_gsi_routing() {
251
let kvm = Kvm::new().unwrap();
252
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
253
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
254
vm.create_irq_chip().unwrap();
255
vm.set_gsi_routing(&[]).unwrap();
256
vm.set_gsi_routing(&[IrqRoute {
257
gsi: 1,
258
source: IrqSource::Irqchip {
259
chip: IrqSourceChip::Ioapic,
260
pin: 3,
261
},
262
}])
263
.unwrap();
264
vm.set_gsi_routing(&[IrqRoute {
265
gsi: 1,
266
source: IrqSource::Msi {
267
address: 0xf000000,
268
data: 0xa0,
269
},
270
}])
271
.unwrap();
272
vm.set_gsi_routing(&[
273
IrqRoute {
274
gsi: 1,
275
source: IrqSource::Irqchip {
276
chip: IrqSourceChip::Ioapic,
277
pin: 3,
278
},
279
},
280
IrqRoute {
281
gsi: 2,
282
source: IrqSource::Msi {
283
address: 0xf000000,
284
data: 0xa0,
285
},
286
},
287
])
288
.unwrap();
289
}
290
291
#[test]
292
fn set_identity_map_addr() {
293
let kvm = Kvm::new().unwrap();
294
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
295
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
296
vm.set_identity_map_addr(GuestAddress(0x20000)).unwrap();
297
}
298
299
#[test]
300
fn mp_state() {
301
let kvm = Kvm::new().unwrap();
302
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
303
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
304
vm.create_irq_chip().unwrap();
305
let vcpu: KvmVcpu = vm.create_kvm_vcpu(0).unwrap();
306
let state = vcpu.get_mp_state().unwrap();
307
vcpu.set_mp_state(&state).unwrap();
308
}
309
310
#[test]
311
fn enable_feature() {
312
let kvm = Kvm::new().unwrap();
313
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
314
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
315
vm.create_irq_chip().unwrap();
316
let vcpu = vm.create_vcpu(0).unwrap();
317
// SAFETY: trivially safe
318
unsafe { vcpu.enable_raw_capability(kvm_sys::KVM_CAP_HYPERV_SYNIC, &[0; 4]) }.unwrap();
319
}
320
321
#[test]
322
fn from_fpu() {
323
// Fpu has the largest arrays in our struct adapters. Test that they're small enough for
324
// Rust to copy.
325
let mut fpu: Fpu = Default::default();
326
let m = fpu.xmm.len();
327
let n = fpu.xmm[0].len();
328
fpu.xmm[m - 1][n - 1] = 42;
329
330
let fpu = kvm_fpu::from(&fpu);
331
assert_eq!(fpu.xmm.len(), m);
332
assert_eq!(fpu.xmm[0].len(), n);
333
assert_eq!(fpu.xmm[m - 1][n - 1], 42);
334
}
335
336
#[test]
337
fn debugregs() {
338
let kvm = Kvm::new().unwrap();
339
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
340
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
341
let vcpu = vm.create_vcpu(0).unwrap();
342
let mut dregs = vcpu.get_debugregs().unwrap();
343
dregs.dr7 = 13;
344
vcpu.set_debugregs(&dregs).unwrap();
345
let dregs2 = vcpu.get_debugregs().unwrap();
346
assert_eq!(dregs.dr7, dregs2.dr7);
347
}
348
349
#[test]
350
fn xcrs() {
351
let kvm = Kvm::new().unwrap();
352
if !kvm.check_capability(HypervisorCap::Xcrs) {
353
return;
354
}
355
356
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
357
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
358
let vcpu = vm.create_vcpu(0).unwrap();
359
vcpu.set_xcr(0, 1).unwrap();
360
let xcrs = vcpu.get_xcrs().unwrap();
361
let xcr0 = xcrs.get(&0).unwrap();
362
assert_eq!(*xcr0, 1);
363
}
364
365
#[test]
366
fn get_msr() {
367
let kvm = Kvm::new().unwrap();
368
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
369
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
370
let vcpu = vm.create_vcpu(0).unwrap();
371
372
// This one should succeed
373
let _value = vcpu.get_msr(0x0000011e).unwrap();
374
375
// This one will fail to fetch
376
vcpu.get_msr(0xffffffff)
377
.expect_err("invalid MSR index should fail");
378
}
379
380
#[test]
381
fn set_msr() {
382
let kvm = Kvm::new().unwrap();
383
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
384
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
385
let vcpu = vm.create_vcpu(0).unwrap();
386
387
const MSR_TSC_AUX: u32 = 0xc0000103;
388
vcpu.set_msr(MSR_TSC_AUX, 42).unwrap();
389
let msr_tsc_aux = vcpu.get_msr(MSR_TSC_AUX).unwrap();
390
assert_eq!(msr_tsc_aux, 42);
391
}
392
393
#[test]
394
fn set_msr_unsupported() {
395
let kvm = Kvm::new().unwrap();
396
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
397
let vm = KvmVm::new(&kvm, gm, Default::default()).unwrap();
398
let vcpu = vm.create_vcpu(0).unwrap();
399
400
assert_eq!(
401
vcpu.set_msr(u32::MAX, u64::MAX),
402
Err(base::Error::new(libc::EPERM))
403
);
404
}
405
406