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