xref: /cloud-hypervisor/hypervisor/src/cpu.rs (revision 19d36c765fdf00be749d95b3e61028bc302d6d73)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4 //
5 // Copyright © 2020, Microsoft Corporation
6 //
7 // Copyright 2018-2019 CrowdStrike, Inc.
8 //
9 //
10 
11 use thiserror::Error;
12 use vm_memory::GuestAddress;
13 
14 #[cfg(target_arch = "aarch64")]
15 use crate::aarch64::{RegList, VcpuInit};
16 #[cfg(target_arch = "x86_64")]
17 use crate::arch::x86::{CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters};
18 #[cfg(feature = "tdx")]
19 use crate::kvm::{TdxExitDetails, TdxExitStatus};
20 use crate::{CpuState, MpState, StandardRegisters};
21 
22 #[cfg(target_arch = "x86_64")]
23 #[derive(Copy, Clone, Default)]
24 pub enum CpuVendor {
25     #[default]
26     Unknown,
27     Intel,
28     AMD,
29 }
30 
31 #[derive(Error, Debug)]
32 ///
33 /// Enum for CPU error
34 pub enum HypervisorCpuError {
35     ///
36     /// Setting standard registers error
37     ///
38     #[error("Failed to set standard register: {0}")]
39     SetStandardRegs(#[source] anyhow::Error),
40     ///
41     /// Setting standard registers error
42     ///
43     #[error("Failed to get standard registers: {0}")]
44     GetStandardRegs(#[source] anyhow::Error),
45     ///
46     /// Setting special register error
47     ///
48     #[error("Failed to set special registers: {0}")]
49     SetSpecialRegs(#[source] anyhow::Error),
50     ///
51     /// Getting standard register error
52     ///
53     #[error("Failed to get special registers: {0}")]
54     GetSpecialRegs(#[source] anyhow::Error),
55     ///
56     /// Setting floating point registers error
57     ///
58     #[error("Failed to set floating point registers: {0}")]
59     SetFloatingPointRegs(#[source] anyhow::Error),
60     ///
61     /// Getting floating point register error
62     ///
63     #[error("Failed to get floating points registers: {0}")]
64     GetFloatingPointRegs(#[source] anyhow::Error),
65     ///
66     /// Setting Cpuid error
67     ///
68     #[error("Failed to set Cpuid: {0}")]
69     SetCpuid(#[source] anyhow::Error),
70     ///
71     /// Getting Cpuid error
72     ///
73     #[error("Failed to get Cpuid: {0}")]
74     GetCpuid(#[source] anyhow::Error),
75     ///
76     /// Setting lapic state error
77     ///
78     #[error("Failed to set Lapic state: {0}")]
79     SetLapicState(#[source] anyhow::Error),
80     ///
81     /// Getting Lapic state error
82     ///
83     #[error("Failed to get Lapic state: {0}")]
84     GetlapicState(#[source] anyhow::Error),
85     ///
86     /// Setting MSR entries error
87     ///
88     #[error("Failed to set Msr entries: {0}")]
89     SetMsrEntries(#[source] anyhow::Error),
90     ///
91     /// Getting Msr entries error
92     ///
93     #[error("Failed to get Msr entries: {0}")]
94     GetMsrEntries(#[source] anyhow::Error),
95     ///
96     /// Setting multi-processing  state error
97     ///
98     #[error("Failed to set MP state: {0}")]
99     SetMpState(#[source] anyhow::Error),
100     ///
101     /// Getting multi-processing  state error
102     ///
103     #[error("Failed to get MP state: {0}")]
104     GetMpState(#[source] anyhow::Error),
105     ///
106     /// Setting Saved Processor Extended States error
107     ///
108     #[cfg(feature = "kvm")]
109     #[error("Failed to set Saved Processor Extended States: {0}")]
110     SetXsaveState(#[source] anyhow::Error),
111     ///
112     /// Getting Saved Processor Extended States error
113     ///
114     #[cfg(feature = "kvm")]
115     #[error("Failed to get Saved Processor Extended States: {0}")]
116     GetXsaveState(#[source] anyhow::Error),
117     ///
118     /// Getting the VP state components error
119     ///
120     #[cfg(feature = "mshv")]
121     #[error("Failed to get VP State Components: {0}")]
122     GetAllVpStateComponents(#[source] anyhow::Error),
123     ///
124     /// Setting the VP state components error
125     ///
126     #[cfg(feature = "mshv")]
127     #[error("Failed to set VP State Components: {0}")]
128     SetAllVpStateComponents(#[source] anyhow::Error),
129     ///
130     /// Setting Extended Control Registers error
131     ///
132     #[error("Failed to set Extended Control Registers: {0}")]
133     SetXcsr(#[source] anyhow::Error),
134     ///
135     /// Getting Extended Control Registers error
136     ///
137     #[error("Failed to get Extended Control Registers: {0}")]
138     GetXcsr(#[source] anyhow::Error),
139     ///
140     /// Running Vcpu error
141     ///
142     #[error("Failed to run vcpu: {0}")]
143     RunVcpu(#[source] anyhow::Error),
144     ///
145     /// Getting Vcpu events error
146     ///
147     #[error("Failed to get Vcpu events: {0}")]
148     GetVcpuEvents(#[source] anyhow::Error),
149     ///
150     /// Setting Vcpu events error
151     ///
152     #[error("Failed to set Vcpu events: {0}")]
153     SetVcpuEvents(#[source] anyhow::Error),
154     ///
155     /// Vcpu Init error
156     ///
157     #[error("Failed to init vcpu: {0}")]
158     VcpuInit(#[source] anyhow::Error),
159     ///
160     /// Vcpu Finalize error
161     ///
162     #[error("Failed to finalize vcpu: {0}")]
163     VcpuFinalize(#[source] anyhow::Error),
164     ///
165     /// Setting one reg error
166     ///
167     #[error("Failed to set one reg: {0}")]
168     SetRegister(#[source] anyhow::Error),
169     ///
170     /// Getting one reg error
171     ///
172     #[error("Failed to get one reg: {0}")]
173     GetRegister(#[source] anyhow::Error),
174     ///
175     /// Getting guest clock paused error
176     ///
177     #[error("Failed to notify guest its clock was paused: {0}")]
178     NotifyGuestClockPaused(#[source] anyhow::Error),
179     ///
180     /// Setting debug register error
181     ///
182     #[error("Failed to set debug registers: {0}")]
183     SetDebugRegs(#[source] anyhow::Error),
184     ///
185     /// Getting debug register error
186     ///
187     #[error("Failed to get debug registers: {0}")]
188     GetDebugRegs(#[source] anyhow::Error),
189     ///
190     /// Setting misc register error
191     ///
192     #[error("Failed to set misc registers: {0}")]
193     SetMiscRegs(#[source] anyhow::Error),
194     ///
195     /// Getting misc register error
196     ///
197     #[error("Failed to get misc registers: {0}")]
198     GetMiscRegs(#[source] anyhow::Error),
199     ///
200     /// Write to Guest Mem
201     ///
202     #[error("Failed to write to Guest Mem at: {0}")]
203     GuestMemWrite(#[source] anyhow::Error),
204     /// Enabling HyperV SynIC error
205     ///
206     #[error("Failed to enable HyperV SynIC")]
207     EnableHyperVSyncIc(#[source] anyhow::Error),
208     ///
209     /// Getting AArch64 core register error
210     ///
211     #[error("Failed to get aarch64 core register: {0}")]
212     GetAarchCoreRegister(#[source] anyhow::Error),
213     ///
214     /// Setting AArch64 core register error
215     ///
216     #[error("Failed to set aarch64 core register: {0}")]
217     SetAarchCoreRegister(#[source] anyhow::Error),
218     ///
219     /// Getting registers list error
220     ///
221     #[error("Failed to retrieve list of registers: {0}")]
222     GetRegList(#[source] anyhow::Error),
223     ///
224     /// Getting AArch64 system register error
225     ///
226     #[error("Failed to get system register: {0}")]
227     GetSysRegister(#[source] anyhow::Error),
228     ///
229     /// Setting AArch64 system register error
230     ///
231     #[error("Failed to set system register: {0}")]
232     SetSysRegister(#[source] anyhow::Error),
233     ///
234     /// GVA translation error
235     ///
236     #[error("Failed to translate GVA: {0}")]
237     TranslateVirtualAddress(#[source] anyhow::Error),
238     ///
239     /// Set cpu attribute error
240     ///
241     #[error("Failed to set vcpu attribute: {0}")]
242     SetVcpuAttribute(#[source] anyhow::Error),
243     ///
244     /// Check if cpu has a certain attribute error
245     ///
246     #[error("Failed to check if vcpu has attribute: {0}")]
247     HasVcpuAttribute(#[source] anyhow::Error),
248     ///
249     /// Failed to initialize TDX on CPU
250     ///
251     #[cfg(feature = "tdx")]
252     #[error("Failed to initialize TDX: {0}")]
253     InitializeTdx(#[source] std::io::Error),
254     ///
255     /// Unknown TDX VM call
256     ///
257     #[cfg(feature = "tdx")]
258     #[error("Unknown TDX VM call")]
259     UnknownTdxVmCall,
260     #[cfg(target_arch = "aarch64")]
261     ///
262     /// Failed to initialize PMU
263     ///
264     #[error("Failed to initialize PMU")]
265     InitializePmu,
266     #[cfg(target_arch = "x86_64")]
267     ///
268     /// Error getting TSC frequency
269     ///
270     #[error("Failed to get TSC frequency: {0}")]
271     GetTscKhz(#[source] anyhow::Error),
272     ///
273     /// Error setting TSC frequency
274     ///
275     #[error("Failed to set TSC frequency: {0}")]
276     SetTscKhz(#[source] anyhow::Error),
277     ///
278     /// Error reading value at given GPA
279     ///
280     #[error("Failed to read from GPA: {0}")]
281     GpaRead(#[source] anyhow::Error),
282     ///
283     /// Error writing value at given GPA
284     ///
285     #[error("Failed to write to GPA: {0}")]
286     GpaWrite(#[source] anyhow::Error),
287     ///
288     /// Error getting CPUID leaf
289     ///
290     #[error("Failed to get CPUID entries: {0}")]
291     GetCpuidVales(#[source] anyhow::Error),
292     ///
293     /// Setting SEV control register error
294     ///
295     #[cfg(feature = "sev_snp")]
296     #[error("Failed to set sev control register: {0}")]
297     SetSevControlRegister(#[source] anyhow::Error),
298 
299     /// Error injecting NMI
300     ///
301     #[error("Failed to inject NMI")]
302     Nmi(#[source] anyhow::Error),
303 }
304 
305 #[derive(Debug)]
306 pub enum VmExit {
307     #[cfg(target_arch = "x86_64")]
308     IoapicEoi(u8 /* vector */),
309     Ignore,
310     Reset,
311     Shutdown,
312     Hyperv,
313     #[cfg(feature = "tdx")]
314     Tdx,
315     #[cfg(feature = "kvm")]
316     Debug,
317 }
318 
319 ///
320 /// Result type for returning from a function
321 ///
322 pub type Result<T> = anyhow::Result<T, HypervisorCpuError>;
323 ///
324 /// Trait to represent a generic Vcpu
325 ///
326 pub trait Vcpu: Send + Sync {
327     ///
328     /// Returns StandardRegisters with default value set
329     ///
330     fn create_standard_regs(&self) -> StandardRegisters {
331         unimplemented!();
332     }
333     ///
334     /// Returns the vCPU general purpose registers.
335     ///
336     fn get_regs(&self) -> Result<StandardRegisters>;
337     ///
338     /// Sets the vCPU general purpose registers.
339     ///
340     fn set_regs(&self, regs: &StandardRegisters) -> Result<()>;
341     #[cfg(target_arch = "x86_64")]
342     ///
343     /// Returns the vCPU special registers.
344     ///
345     fn get_sregs(&self) -> Result<SpecialRegisters>;
346     #[cfg(target_arch = "x86_64")]
347     ///
348     /// Sets the vCPU special registers
349     ///
350     fn set_sregs(&self, sregs: &SpecialRegisters) -> Result<()>;
351     #[cfg(target_arch = "x86_64")]
352     ///
353     /// Returns the floating point state (FPU) from the vCPU.
354     ///
355     fn get_fpu(&self) -> Result<FpuState>;
356     #[cfg(target_arch = "x86_64")]
357     ///
358     /// Set the floating point state (FPU) of a vCPU
359     ///
360     fn set_fpu(&self, fpu: &FpuState) -> Result<()>;
361     #[cfg(target_arch = "x86_64")]
362     ///
363     /// X86 specific call to setup the CPUID registers.
364     ///
365     fn set_cpuid2(&self, cpuid: &[CpuIdEntry]) -> Result<()>;
366     #[cfg(target_arch = "x86_64")]
367     ///
368     /// X86 specific call to enable HyperV SynIC
369     ///
370     fn enable_hyperv_synic(&self) -> Result<()>;
371     #[cfg(target_arch = "x86_64")]
372     ///
373     /// X86 specific call to retrieve the CPUID registers.
374     ///
375     fn get_cpuid2(&self, num_entries: usize) -> Result<Vec<CpuIdEntry>>;
376     #[cfg(target_arch = "x86_64")]
377     ///
378     /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
379     ///
380     fn get_lapic(&self) -> Result<LapicState>;
381     #[cfg(target_arch = "x86_64")]
382     ///
383     /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
384     ///
385     fn set_lapic(&self, lapic: &LapicState) -> Result<()>;
386     #[cfg(target_arch = "x86_64")]
387     ///
388     /// Returns the model-specific registers (MSR) for this vCPU.
389     ///
390     fn get_msrs(&self, msrs: &mut Vec<MsrEntry>) -> Result<usize>;
391     #[cfg(target_arch = "x86_64")]
392     ///
393     /// Setup the model-specific registers (MSR) for this vCPU.
394     ///
395     fn set_msrs(&self, msrs: &[MsrEntry]) -> Result<usize>;
396     ///
397     /// Returns the vcpu's current "multiprocessing state".
398     ///
399     fn get_mp_state(&self) -> Result<MpState>;
400     ///
401     /// Sets the vcpu's current "multiprocessing state".
402     ///
403     fn set_mp_state(&self, mp_state: MpState) -> Result<()>;
404     #[cfg(target_arch = "x86_64")]
405     ///
406     /// Let the guest know that it has been paused, which prevents from
407     /// potential soft lockups when being resumed.
408     ///
409     fn notify_guest_clock_paused(&self) -> Result<()> {
410         Ok(())
411     }
412     ///
413     /// Sets debug registers to set hardware breakpoints and/or enable single step.
414     ///
415     fn set_guest_debug(&self, _addrs: &[GuestAddress], _singlestep: bool) -> Result<()> {
416         Err(HypervisorCpuError::SetDebugRegs(anyhow!("unimplemented")))
417     }
418     ///
419     /// Sets the type of CPU to be exposed to the guest and optional features.
420     ///
421     #[cfg(target_arch = "aarch64")]
422     fn vcpu_init(&self, kvi: &VcpuInit) -> Result<()>;
423 
424     #[cfg(target_arch = "aarch64")]
425     fn vcpu_finalize(&self, feature: i32) -> Result<()>;
426 
427     ///
428     /// Gets a list of the guest registers that are supported for the
429     /// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
430     ///
431     #[cfg(target_arch = "aarch64")]
432     fn get_reg_list(&self, reg_list: &mut RegList) -> Result<()>;
433     ///
434     /// Gets the value of a system register
435     ///
436     #[cfg(target_arch = "aarch64")]
437     fn get_sys_reg(&self, sys_reg: u32) -> Result<u64>;
438     ///
439     /// Configure core registers for a given CPU.
440     ///
441     #[cfg(target_arch = "aarch64")]
442     fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> Result<()>;
443     ///
444     /// Check if the CPU supports PMU
445     ///
446     #[cfg(target_arch = "aarch64")]
447     fn has_pmu_support(&self) -> bool;
448     ///
449     /// Initialize PMU
450     ///
451     #[cfg(target_arch = "aarch64")]
452     fn init_pmu(&self, irq: u32) -> Result<()>;
453     ///
454     /// Retrieve the vCPU state.
455     /// This function is necessary to snapshot the VM
456     ///
457     fn state(&self) -> Result<CpuState>;
458     ///
459     /// Set the vCPU state.
460     /// This function is required when restoring the VM
461     ///
462     fn set_state(&self, state: &CpuState) -> Result<()>;
463     ///
464     /// Triggers the running of the current virtual CPU returning an exit reason.
465     ///
466     fn run(&self) -> std::result::Result<VmExit, HypervisorCpuError>;
467     #[cfg(target_arch = "x86_64")]
468     ///
469     /// Translate guest virtual address to guest physical address
470     ///
471     fn translate_gva(&self, gva: u64, flags: u64) -> Result<(u64, u32)>;
472     ///
473     /// Initialize TDX support on the vCPU
474     ///
475     #[cfg(feature = "tdx")]
476     fn tdx_init(&self, _hob_address: u64) -> Result<()> {
477         unimplemented!()
478     }
479     ///
480     /// Set the "immediate_exit" state
481     ///
482     fn set_immediate_exit(&self, _exit: bool) {}
483     #[cfg(feature = "tdx")]
484     ///
485     /// Returns the details about TDX exit reason
486     ///
487     fn get_tdx_exit_details(&mut self) -> Result<TdxExitDetails> {
488         unimplemented!()
489     }
490     #[cfg(feature = "tdx")]
491     ///
492     /// Set the status code for TDX exit
493     ///
494     fn set_tdx_status(&mut self, _status: TdxExitStatus) {
495         unimplemented!()
496     }
497     #[cfg(target_arch = "x86_64")]
498     ///
499     /// Return the list of initial MSR entries for a VCPU
500     ///
501     fn boot_msr_entries(&self) -> Vec<MsrEntry>;
502 
503     #[cfg(target_arch = "x86_64")]
504     ///
505     /// Get the frequency of the TSC if available
506     ///
507     fn tsc_khz(&self) -> Result<Option<u32>> {
508         Ok(None)
509     }
510     #[cfg(target_arch = "x86_64")]
511     ///
512     /// Set the frequency of the TSC if available
513     ///
514     fn set_tsc_khz(&self, _freq: u32) -> Result<()> {
515         Ok(())
516     }
517     #[cfg(target_arch = "x86_64")]
518     ///
519     /// X86 specific call to retrieve cpuid leaf
520     ///
521     fn get_cpuid_values(
522         &self,
523         _function: u32,
524         _index: u32,
525         _xfem: u64,
526         _xss: u64,
527     ) -> Result<[u32; 4]> {
528         unimplemented!()
529     }
530     #[cfg(feature = "mshv")]
531     fn set_sev_control_register(&self, _reg: u64) -> Result<()> {
532         unimplemented!()
533     }
534 
535     #[cfg(target_arch = "x86_64")]
536     ///
537     /// Trigger NMI interrupt
538     ///
539     fn nmi(&self) -> Result<()>;
540 }
541