@@ -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
}
@@ -136,14 +142,14 @@ impl KvmVcpu {
136
142
kvi. features [ index] = feature. bitmap . apply ( kvi. features [ index] ) ;
137
143
}
138
144
139
- self . kvi = if !vcpu_features. is_empty ( ) {
145
+ self . kvm_vcpu . kvi = if !vcpu_features. is_empty ( ) {
140
146
Some ( kvi)
141
147
} else {
142
148
None
143
149
} ;
144
150
145
151
// Non-boot cpus are powered off initially.
146
- if 0 < self . index {
152
+ if 0 < self . kvm_vcpu . index {
147
153
kvi. features [ 0 ] |= 1 << kvm_bindings:: KVM_ARM_VCPU_POWER_OFF ;
148
154
}
149
155
@@ -174,7 +180,7 @@ impl KvmVcpu {
174
180
} ;
175
181
get_all_registers ( & self . fd , & mut state. regs ) . map_err ( KvmVcpuError :: SaveState ) ?;
176
182
state. mpidr = get_mpidr ( & self . fd ) . map_err ( KvmVcpuError :: SaveState ) ?;
177
- state. kvi = self . kvi ;
183
+ state. kvi = self . kvm_vcpu . kvi ;
178
184
Ok ( state)
179
185
}
180
186
@@ -184,7 +190,7 @@ impl KvmVcpu {
184
190
Some ( kvi) => kvi,
185
191
None => Self :: default_kvi ( vm_fd) ?,
186
192
} ;
187
- self . kvi = state. kvi ;
193
+ self . kvm_vcpu . kvi = state. kvi ;
188
194
189
195
self . init_vcpu ( & kvi) ?;
190
196
@@ -223,17 +229,6 @@ impl KvmVcpu {
223
229
Ok ( CpuConfiguration { regs } )
224
230
}
225
231
226
- /// Runs the vCPU in KVM context and handles the kvm exit reason.
227
- ///
228
- /// Returns error or enum specifying whether emulation was handled or interrupted.
229
- pub fn run_arch_emulation ( & self , exit : VcpuExit ) -> Result < VcpuEmulation , VcpuError > {
230
- METRICS . vcpu . failures . inc ( ) ;
231
- // TODO: Are we sure we want to finish running a vcpu upon
232
- // receiving a vm exit that is not necessarily an error?
233
- error ! ( "Unexpected exit reason on vcpu run: {:?}" , exit) ;
234
- Err ( VcpuError :: UnhandledKvmExit ( format ! ( "{:?}" , exit) ) )
235
- }
236
-
237
232
/// Initializes internal vcpufd.
238
233
fn init_vcpu ( & self , kvi : & kvm_bindings:: kvm_vcpu_init ) -> Result < ( ) , KvmVcpuError > {
239
234
self . fd . vcpu_init ( kvi) . map_err ( KvmVcpuError :: Init ) ?;
@@ -298,6 +293,7 @@ mod tests {
298
293
use std:: os:: unix:: io:: AsRawFd ;
299
294
300
295
use kvm_bindings:: KVM_REG_SIZE_U64 ;
296
+ use utils:: eventfd:: EventFd ;
301
297
302
298
use super :: * ;
303
299
use crate :: arch:: aarch64:: regs:: Aarch64RegisterRef ;
@@ -308,9 +304,9 @@ mod tests {
308
304
use crate :: vstate:: vm:: tests:: setup_vm;
309
305
use crate :: vstate:: vm:: Vm ;
310
306
311
- fn setup_vcpu ( mem_size : usize ) -> ( Vm , KvmVcpu , GuestMemoryMmap ) {
307
+ fn setup_vcpu ( mem_size : usize ) -> ( Vm , Vcpu , GuestMemoryMmap ) {
312
308
let ( mut vm, vm_mem) = setup_vm ( mem_size) ;
313
- let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
309
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
314
310
vcpu. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
315
311
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
316
312
@@ -323,7 +319,7 @@ mod tests {
323
319
324
320
unsafe { libc:: close ( vm. fd ( ) . as_raw_fd ( ) ) } ;
325
321
326
- let err = KvmVcpu :: new ( 0 , & vm) ;
322
+ let err = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) ;
327
323
assert_eq ! (
328
324
err. err( ) . unwrap( ) . to_string( ) ,
329
325
"Error creating vcpu: Bad file descriptor (os error 9)" . to_string( )
@@ -364,8 +360,8 @@ mod tests {
364
360
365
361
#[ test]
366
362
fn test_init_vcpu ( ) {
367
- let ( mut vm, _vm_mem ) = setup_vm ( 0x1000 ) ;
368
- let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
363
+ let ( mut vm, _ ) = setup_vm ( 0x1000 ) ;
364
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
369
365
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
370
366
371
367
// KVM_ARM_VCPU_PSCI_0_2 is set by default.
@@ -381,7 +377,7 @@ mod tests {
381
377
382
378
// Because vcpu_features vector is not empty,
383
379
// kvi field should be non empty as well.
384
- let vcpu_kvi = vcpu. kvi . unwrap ( ) ;
380
+ let vcpu_kvi = vcpu. kvm_vcpu . kvi . unwrap ( ) ;
385
381
assert ! ( ( vcpu_kvi. features[ 0 ] & ( 1 << kvm_bindings:: KVM_ARM_VCPU_PSCI_0_2 ) ) == 0 )
386
382
}
387
383
@@ -398,8 +394,8 @@ mod tests {
398
394
399
395
#[ test]
400
396
fn test_vcpu_save_restore_state ( ) {
401
- let ( mut vm, _vm_mem ) = setup_vm ( 0x1000 ) ;
402
- let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
397
+ let ( mut vm, _ ) = setup_vm ( 0x1000 ) ;
398
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
403
399
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
404
400
405
401
// Calling KVM_GET_REGLIST before KVM_VCPU_INIT will result in error.
@@ -437,8 +433,8 @@ mod tests {
437
433
//
438
434
// This should fail with ENOEXEC.
439
435
// https://elixir.bootlin.com/linux/v5.10.176/source/arch/arm64/kvm/arm.c#L1165
440
- let ( mut vm, _vm_mem ) = setup_vm ( 0x1000 ) ;
441
- let vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
436
+ let ( mut vm, _ ) = setup_vm ( 0x1000 ) ;
437
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
442
438
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
443
439
444
440
vcpu. dump_cpu_config ( ) . unwrap_err ( ) ;
@@ -447,8 +443,8 @@ mod tests {
447
443
#[ test]
448
444
fn test_dump_cpu_config_after_init ( ) {
449
445
// Test `dump_cpu_config()` after `KVM_VCPU_INIT`.
450
- let ( mut vm, _vm_mem ) = setup_vm ( 0x1000 ) ;
451
- let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
446
+ let ( mut vm, _ ) = setup_vm ( 0x1000 ) ;
447
+ let mut vcpu = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
452
448
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
453
449
vcpu. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
454
450
@@ -458,9 +454,9 @@ mod tests {
458
454
#[ test]
459
455
fn test_setup_non_boot_vcpu ( ) {
460
456
let ( vm, _) = setup_vm ( 0x1000 ) ;
461
- let mut vcpu1 = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
457
+ let mut vcpu1 = Vcpu :: new ( 0 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
462
458
vcpu1. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
463
- let mut vcpu2 = KvmVcpu :: new ( 1 , & vm) . unwrap ( ) ;
459
+ let mut vcpu2 = Vcpu :: new ( 1 , & vm, EventFd :: new ( libc :: EFD_NONBLOCK ) . unwrap ( ) ) . unwrap ( ) ;
464
460
vcpu2. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
465
461
}
466
462
0 commit comments