Coverage Report

Created: 2026-03-31 07:58

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