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