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