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