xref: /aosp_15_r20/external/crosvm/hypervisor/tests/kvm/x86_64.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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]
get_supported_cpuid()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]
get_msr_index_list()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]
entries_double_on_error()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]
check_vm_arch_capability()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]
pic_state()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]
ioapic_state()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]
lapic_state()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]
pit_state()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]
clock_handling()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]
set_gsi_routing()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]
set_identity_map_addr()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]
mp_state()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]
enable_feature()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]
from_fpu()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]
debugregs()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]
xcrs()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]
get_msr()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]
set_msr()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]
set_msr_unsupported()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