@@ -22,6 +22,7 @@ use crate::vcpu::{VcpuConfig, VcpuError};
22
22
use crate :: vstate:: memory:: { Address , GuestAddress , GuestMemoryMmap } ;
23
23
use crate :: vstate:: vcpu:: VcpuEmulation ;
24
24
use crate :: vstate:: vm:: Vm ;
25
+ use crate :: Vcpu ;
25
26
26
27
/// Errors associated with the wrappers over KVM ioctls.
27
28
#[ derive( Debug , PartialEq , Eq , thiserror:: Error , displaydoc:: Display ) ]
@@ -52,8 +53,6 @@ pub type KvmVcpuConfigureError = KvmVcpuError;
52
53
pub struct KvmVcpu {
53
54
/// Index of vcpu.
54
55
pub index : u8 ,
55
- /// KVM vcpu fd.
56
- pub fd : VcpuFd ,
57
56
/// Mmio bus.
58
57
pub mmio_bus : Option < crate :: devices:: Bus > ,
59
58
mpidr : u64 ,
@@ -67,26 +66,33 @@ impl KvmVcpu {
67
66
///
68
67
/// * `index` - Represents the 0-based CPU index between [0, max vcpus).
69
68
/// * `vm` - The vm to which this vcpu will get attached.
70
- pub fn new ( index : u8 , vm : & Vm ) -> Result < Self , KvmVcpuError > {
71
- let kvm_vcpu = vm
72
- . fd ( )
73
- . create_vcpu ( index. into ( ) )
74
- . map_err ( KvmVcpuError :: CreateVcpu ) ?;
75
-
76
- Ok ( KvmVcpu {
69
+ pub fn new ( index : u8 , _vm : & Vm ) -> Self {
70
+ KvmVcpu {
77
71
index,
78
- fd : kvm_vcpu,
79
72
mmio_bus : None ,
80
73
mpidr : 0 ,
81
74
kvi : None ,
82
- } )
75
+ }
83
76
}
84
77
85
78
/// Gets the MPIDR register value.
86
79
pub fn get_mpidr ( & self ) -> u64 {
87
80
self . mpidr
88
81
}
89
82
83
+ /// Runs the vCPU in KVM context and handles the kvm exit reason.
84
+ ///
85
+ /// Returns error or enum specifying whether emulation was handled or interrupted.
86
+ pub fn run_arch_emulation ( & self , exit : VcpuExit ) -> Result < VcpuEmulation , VcpuError > {
87
+ METRICS . vcpu . failures . inc ( ) ;
88
+ // TODO: Are we sure we want to finish running a vcpu upon
89
+ // receiving a vm exit that is not necessarily an error?
90
+ error ! ( "Unexpected exit reason on vcpu run: {:?}" , exit) ;
91
+ Err ( VcpuError :: UnhandledKvmExit ( format ! ( "{:?}" , exit) ) )
92
+ }
93
+ }
94
+
95
+ impl Vcpu {
90
96
/// Configures an aarch64 specific vcpu for booting Linux.
91
97
///
92
98
/// # Arguments
@@ -108,13 +114,13 @@ impl KvmVcpu {
108
114
109
115
setup_boot_regs (
110
116
& self . fd ,
111
- self . index ,
117
+ self . kvm_vcpu . index ,
112
118
kernel_load_addr. raw_value ( ) ,
113
119
guest_mem,
114
120
)
115
121
. map_err ( KvmVcpuError :: ConfigureRegisters ) ?;
116
122
117
- self . mpidr = get_mpidr ( & self . fd ) . map_err ( KvmVcpuError :: ConfigureRegisters ) ?;
123
+ self . kvm_vcpu . mpidr = get_mpidr ( & self . fd ) . map_err ( KvmVcpuError :: ConfigureRegisters ) ?;
118
124
119
125
Ok ( ( ) )
120
126
}
@@ -129,7 +135,7 @@ impl KvmVcpu {
129
135
vm_fd : & VmFd ,
130
136
vcpu_features : & [ VcpuFeatures ] ,
131
137
) -> Result < ( ) , KvmVcpuError > {
132
- let mut kvi = Self :: default_kvi ( vm_fd, self . index ) ?;
138
+ let mut kvi = Self :: default_kvi ( vm_fd, self . kvm_vcpu . index ) ?;
133
139
134
140
for feature in vcpu_features. iter ( ) {
135
141
let index = feature. index as usize ;
@@ -139,7 +145,7 @@ impl KvmVcpu {
139
145
self . init_vcpu ( & kvi) ?;
140
146
self . finalize_vcpu ( & kvi) ?;
141
147
142
- self . kvi = if !vcpu_features. is_empty ( ) {
148
+ self . kvm_vcpu . kvi = if !vcpu_features. is_empty ( ) {
143
149
Some ( kvi)
144
150
} else {
145
151
None
@@ -177,17 +183,17 @@ impl KvmVcpu {
177
183
} ;
178
184
get_all_registers ( & self . fd , & mut state. regs ) . map_err ( KvmVcpuError :: SaveState ) ?;
179
185
state. mpidr = get_mpidr ( & self . fd ) . map_err ( KvmVcpuError :: SaveState ) ?;
180
- state. kvi = self . kvi ;
186
+ state. kvi = self . kvm_vcpu . kvi ;
181
187
Ok ( state)
182
188
}
183
189
184
190
/// Use provided state to populate KVM internal state.
185
191
pub fn restore_state ( & mut self , vm_fd : & VmFd , state : & VcpuState ) -> Result < ( ) , KvmVcpuError > {
186
192
let kvi = match state. kvi {
187
193
Some ( kvi) => kvi,
188
- None => Self :: default_kvi ( vm_fd, self . index ) ?,
194
+ None => Self :: default_kvi ( vm_fd, self . kvm_vcpu . index ) ?,
189
195
} ;
190
- self . kvi = state. kvi ;
196
+ self . kvm_vcpu . kvi = state. kvi ;
191
197
192
198
self . init_vcpu ( & kvi) ?;
193
199
@@ -226,17 +232,6 @@ impl KvmVcpu {
226
232
Ok ( CpuConfiguration { regs } )
227
233
}
228
234
229
- /// Runs the vCPU in KVM context and handles the kvm exit reason.
230
- ///
231
- /// Returns error or enum specifying whether emulation was handled or interrupted.
232
- pub fn run_arch_emulation ( & self , exit : VcpuExit ) -> Result < VcpuEmulation , VcpuError > {
233
- METRICS . vcpu . failures . inc ( ) ;
234
- // TODO: Are we sure we want to finish running a vcpu upon
235
- // receiving a vm exit that is not necessarily an error?
236
- error ! ( "Unexpected exit reason on vcpu run: {:?}" , exit) ;
237
- Err ( VcpuError :: UnhandledKvmExit ( format ! ( "{:?}" , exit) ) )
238
- }
239
-
240
235
/// Initializes internal vcpufd.
241
236
fn init_vcpu ( & self , kvi : & kvm_bindings:: kvm_vcpu_init ) -> Result < ( ) , KvmVcpuError > {
242
237
self . fd . vcpu_init ( kvi) . map_err ( KvmVcpuError :: Init ) ?;
@@ -301,6 +296,7 @@ mod tests {
301
296
use std:: os:: unix:: io:: AsRawFd ;
302
297
303
298
use kvm_bindings:: KVM_REG_SIZE_U64 ;
299
+ use utils:: eventfd:: EventFd ;
304
300
305
301
use super :: * ;
306
302
use crate :: arch:: aarch64:: regs:: Aarch64RegisterRef ;
@@ -311,9 +307,9 @@ mod tests {
311
307
use crate :: vstate:: vm:: tests:: setup_vm;
312
308
use crate :: vstate:: vm:: Vm ;
313
309
314
- fn setup_vcpu ( mem_size : usize ) -> ( Vm , KvmVcpu , GuestMemoryMmap ) {
310
+ fn setup_vcpu ( mem_size : usize ) -> ( Vm , Vcpu , GuestMemoryMmap ) {
315
311
let ( mut vm, vm_mem) = setup_vm ( mem_size) ;
316
- let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
312
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
317
313
vcpu. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
318
314
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
319
315
@@ -326,7 +322,7 @@ mod tests {
326
322
327
323
unsafe { libc:: close ( vm. fd ( ) . as_raw_fd ( ) ) } ;
328
324
329
- let err = KvmVcpu :: new ( 0 , & vm) ;
325
+ let err = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) ;
330
326
assert_eq ! (
331
327
err. err( ) . unwrap( ) . to_string( ) ,
332
328
"Error creating vcpu: Bad file descriptor (os error 9)" . to_string( )
@@ -367,8 +363,8 @@ mod tests {
367
363
368
364
#[ test]
369
365
fn test_init_vcpu ( ) {
370
- let ( mut vm, _vm_mem ) = setup_vm ( 0x1000 ) ;
371
- let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
366
+ let ( mut vm, _ ) = setup_vm ( 0x1000 ) ;
367
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
372
368
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
373
369
374
370
// KVM_ARM_VCPU_PSCI_0_2 is set by default.
@@ -384,7 +380,7 @@ mod tests {
384
380
385
381
// Because vcpu_features vector is not empty,
386
382
// kvi field should be non empty as well.
387
- let vcpu_kvi = vcpu. kvi . unwrap ( ) ;
383
+ let vcpu_kvi = vcpu. kvm_vcpu . kvi . unwrap ( ) ;
388
384
assert ! ( ( vcpu_kvi. features[ 0 ] & ( 1 << kvm_bindings:: KVM_ARM_VCPU_PSCI_0_2 ) ) == 0 )
389
385
}
390
386
@@ -401,8 +397,8 @@ mod tests {
401
397
402
398
#[ test]
403
399
fn test_vcpu_save_restore_state ( ) {
404
- let ( mut vm, _vm_mem ) = setup_vm ( 0x1000 ) ;
405
- let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
400
+ let ( mut vm, _ ) = setup_vm ( 0x1000 ) ;
401
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
406
402
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
407
403
408
404
// Calling KVM_GET_REGLIST before KVM_VCPU_INIT will result in error.
@@ -440,8 +436,8 @@ mod tests {
440
436
//
441
437
// This should fail with ENOEXEC.
442
438
// https://elixir.bootlin.com/linux/v5.10.176/source/arch/arm64/kvm/arm.c#L1165
443
- let ( mut vm, _vm_mem ) = setup_vm ( 0x1000 ) ;
444
- let vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
439
+ let ( mut vm, _ ) = setup_vm ( 0x1000 ) ;
440
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
445
441
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
446
442
447
443
vcpu. dump_cpu_config ( ) . unwrap_err ( ) ;
@@ -450,8 +446,8 @@ mod tests {
450
446
#[ test]
451
447
fn test_dump_cpu_config_after_init ( ) {
452
448
// Test `dump_cpu_config()` after `KVM_VCPU_INIT`.
453
- let ( mut vm, _vm_mem ) = setup_vm ( 0x1000 ) ;
454
- let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
449
+ let ( mut vm, _ ) = setup_vm ( 0x1000 ) ;
450
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
455
451
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
456
452
vcpu. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
457
453
@@ -461,9 +457,9 @@ mod tests {
461
457
#[ test]
462
458
fn test_setup_non_boot_vcpu ( ) {
463
459
let ( vm, _) = setup_vm ( 0x1000 ) ;
464
- let mut vcpu1 = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
460
+ let mut vcpu1 = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
465
461
vcpu1. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
466
- let mut vcpu2 = KvmVcpu :: new ( 1 , & vm) . unwrap ( ) ;
462
+ let mut vcpu2 = Vcpu :: new ( 1 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
467
463
vcpu2. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
468
464
}
469
465
0 commit comments