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