@@ -18,6 +18,7 @@ use crate::arch::aarch64::vcpu::{
18
18
get_all_registers, get_all_registers_ids, get_mpidr, get_mpstate, get_registers, set_mpstate,
19
19
set_registers, setup_boot_regs, VcpuError as ArchError ,
20
20
} ;
21
+ use crate :: cpu_config:: aarch64:: custom_cpu_template:: VcpuFeatures ;
21
22
use crate :: cpu_config:: templates:: CpuConfiguration ;
22
23
use crate :: vcpu:: { VcpuConfig , VcpuError } ;
23
24
use crate :: vstate:: vcpu:: VcpuEmulation ;
@@ -40,6 +41,8 @@ pub enum KvmVcpuError {
40
41
ApplyCpuTemplate ( ArchError ) ,
41
42
#[ error( "Failed to restore the state of the vcpu: {0}" ) ]
42
43
RestoreState ( ArchError ) ,
44
+ #[ error( "Failed to restore the state of the vcpu: no kvi provided" ) ]
45
+ MissingKvi ,
43
46
#[ error( "Failed to save the state of the vcpu: {0}" ) ]
44
47
SaveState ( ArchError ) ,
45
48
}
@@ -53,6 +56,7 @@ pub struct KvmVcpu {
53
56
pub fd : VcpuFd ,
54
57
pub mmio_bus : Option < crate :: devices:: Bus > ,
55
58
mpidr : u64 ,
59
+ kvi : Option < kvm_bindings:: kvm_vcpu_init > ,
56
60
}
57
61
58
62
impl KvmVcpu {
@@ -73,6 +77,7 @@ impl KvmVcpu {
73
77
fd : kvm_vcpu,
74
78
mmio_bus : None ,
75
79
mpidr : 0 ,
80
+ kvi : None ,
76
81
} )
77
82
}
78
83
@@ -118,20 +123,43 @@ impl KvmVcpu {
118
123
/// # Arguments
119
124
///
120
125
/// * `vm_fd` - The kvm `VmFd` for this microvm.
121
- pub fn init ( & self , vm_fd : & VmFd ) -> Result < ( ) , KvmVcpuError > {
122
- let mut kvi: kvm_bindings:: kvm_vcpu_init = kvm_bindings:: kvm_vcpu_init:: default ( ) ;
126
+ pub fn init (
127
+ & mut self ,
128
+ vm_fd : & VmFd ,
129
+ vcpu_features : & [ VcpuFeatures ] ,
130
+ ) -> Result < ( ) , KvmVcpuError > {
131
+ let mut kvi = Self :: default_kvi ( vm_fd, self . index ) ?;
132
+
133
+ for feature in vcpu_features. iter ( ) {
134
+ kvi. features [ feature. index as usize ] |= feature. bitmap ;
135
+ }
123
136
137
+ self . kvi = if !vcpu_features. is_empty ( ) {
138
+ Some ( kvi)
139
+ } else {
140
+ None
141
+ } ;
142
+ self . fd . vcpu_init ( & kvi) . map_err ( KvmVcpuError :: Init )
143
+ }
144
+
145
+ pub fn default_kvi (
146
+ vm_fd : & VmFd ,
147
+ index : u8 ,
148
+ ) -> Result < kvm_bindings:: kvm_vcpu_init , KvmVcpuError > {
149
+ let mut kvi: kvm_bindings:: kvm_vcpu_init = kvm_bindings:: kvm_vcpu_init:: default ( ) ;
124
150
// This reads back the kernel's preferred target type.
125
151
vm_fd
126
152
. get_preferred_target ( & mut kvi)
127
153
. map_err ( KvmVcpuError :: GetPreferredTarget ) ?;
128
154
// We already checked that the capability is supported.
129
155
kvi. features [ 0 ] |= 1 << kvm_bindings:: KVM_ARM_VCPU_PSCI_0_2 ;
156
+
130
157
// Non-boot cpus are powered off initially.
131
- if self . index > 0 {
158
+ if index > 0 {
132
159
kvi. features [ 0 ] |= 1 << kvm_bindings:: KVM_ARM_VCPU_POWER_OFF ;
133
160
}
134
- self . fd . vcpu_init ( & kvi) . map_err ( KvmVcpuError :: Init )
161
+
162
+ Ok ( kvi)
135
163
}
136
164
137
165
/// Save the KVM internal state.
@@ -142,11 +170,23 @@ impl KvmVcpu {
142
170
} ;
143
171
get_all_registers ( & self . fd , & mut state. regs ) . map_err ( KvmVcpuError :: SaveState ) ?;
144
172
state. mpidr = get_mpidr ( & self . fd ) . map_err ( KvmVcpuError :: SaveState ) ?;
173
+ state. kvi = self . kvi ;
145
174
Ok ( state)
146
175
}
147
176
148
177
/// Use provided state to populate KVM internal state.
149
- pub fn restore_state ( & self , state : & VcpuState ) -> Result < ( ) , KvmVcpuError > {
178
+ pub fn restore_state (
179
+ & mut self ,
180
+ vm_fd : & VmFd ,
181
+ state : & VcpuState ,
182
+ index : u8 ,
183
+ ) -> Result < ( ) , KvmVcpuError > {
184
+ let kvi = match state. kvi {
185
+ Some ( kvi) => kvi,
186
+ None => Self :: default_kvi ( vm_fd, index) ?,
187
+ } ;
188
+ self . fd . vcpu_init ( & kvi) . map_err ( KvmVcpuError :: Init ) ?;
189
+ self . kvi = state. kvi ;
150
190
set_registers ( & self . fd , & state. regs ) . map_err ( KvmVcpuError :: RestoreState ) ?;
151
191
set_mpstate ( & self . fd , state. mp_state ) . map_err ( KvmVcpuError :: RestoreState ) ?;
152
192
Ok ( ( ) )
@@ -192,13 +232,19 @@ pub struct VcpuState {
192
232
// The VmState will give this away for saving restoring the icc and redistributor
193
233
// registers.
194
234
pub mpidr : u64 ,
235
+ #[ version( start = 2 , default_fn = "default_kvi" ) ]
236
+ pub kvi : Option < kvm_bindings:: kvm_vcpu_init > ,
195
237
}
196
238
197
239
impl VcpuState {
198
240
fn default_old_regs ( _: u16 ) -> Vec < Aarch64RegisterOld > {
199
241
Vec :: default ( )
200
242
}
201
243
244
+ fn default_kvi ( _: u16 ) -> Option < kvm_bindings:: kvm_vcpu_init > {
245
+ None
246
+ }
247
+
202
248
fn de_regs ( & mut self , _source_version : u16 ) -> VersionizeResult < ( ) > {
203
249
let mut regs = Aarch64RegisterVec :: default ( ) ;
204
250
for reg in self . old_regs . iter ( ) {
@@ -227,31 +273,23 @@ mod tests {
227
273
#![ allow( clippy:: undocumented_unsafe_blocks) ]
228
274
use std:: os:: unix:: io:: AsRawFd ;
229
275
230
- use kvm_bindings:: KVM_REG_SIZE_U64 ;
231
276
use utils:: vm_memory:: GuestMemoryMmap ;
232
277
233
278
use super :: * ;
234
- use crate :: arch:: aarch64:: regs:: Aarch64RegisterRef ;
235
279
use crate :: cpu_config:: aarch64:: CpuConfiguration ;
236
280
use crate :: vcpu:: VcpuConfig ;
237
281
use crate :: vstate:: vm:: tests:: setup_vm;
238
282
use crate :: vstate:: vm:: Vm ;
239
283
240
284
fn setup_vcpu ( mem_size : usize ) -> ( Vm , KvmVcpu , GuestMemoryMmap ) {
241
285
let ( mut vm, vm_mem) = setup_vm ( mem_size) ;
242
- let vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
243
- vcpu. init ( vm. fd ( ) ) . unwrap ( ) ;
286
+ let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
287
+ vcpu. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
244
288
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
245
289
246
290
( vm, vcpu, vm_mem)
247
291
}
248
292
249
- fn init_vcpu ( vcpu : & VcpuFd , vm : & VmFd ) {
250
- let mut kvi = kvm_bindings:: kvm_vcpu_init:: default ( ) ;
251
- vm. get_preferred_target ( & mut kvi) . unwrap ( ) ;
252
- vcpu. vcpu_init ( & kvi) . unwrap ( ) ;
253
- }
254
-
255
293
#[ test]
256
294
fn test_create_vcpu ( ) {
257
295
let ( vm, _) = setup_vm ( 0x1000 ) ;
@@ -302,9 +340,9 @@ mod tests {
302
340
303
341
#[ test]
304
342
fn test_faulty_init_vcpu ( ) {
305
- let ( vm, vcpu, _) = setup_vcpu ( 0x10000 ) ;
343
+ let ( vm, mut vcpu, _) = setup_vcpu ( 0x10000 ) ;
306
344
unsafe { libc:: close ( vm. fd ( ) . as_raw_fd ( ) ) } ;
307
- let err = vcpu. init ( vm. fd ( ) ) ;
345
+ let err = vcpu. init ( vm. fd ( ) , & [ ] ) ;
308
346
assert ! ( err. is_err( ) ) ;
309
347
assert_eq ! (
310
348
err. err( ) . unwrap( ) . to_string( ) ,
@@ -315,7 +353,7 @@ mod tests {
315
353
#[ test]
316
354
fn test_vcpu_save_restore_state ( ) {
317
355
let ( mut vm, _vm_mem) = setup_vm ( 0x1000 ) ;
318
- let vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
356
+ let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
319
357
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
320
358
321
359
// Calling KVM_GET_REGLIST before KVM_VCPU_INIT will result in error.
@@ -327,26 +365,14 @@ mod tests {
327
365
) ) ;
328
366
329
367
// Try to restore the register using a faulty state.
330
- let mut regs = Aarch64RegisterVec :: default ( ) ;
331
- let mut reg = Aarch64RegisterRef :: new ( KVM_REG_SIZE_U64 , & [ 0 ; 8 ] ) ;
332
- reg. id = 0 ;
333
- regs. push ( reg) ;
334
- let faulty_vcpu_state = VcpuState {
335
- regs,
336
- ..Default :: default ( )
337
- } ;
338
-
339
- let res = vcpu. restore_state ( & faulty_vcpu_state) ;
368
+ let faulty_vcpu_state = VcpuState :: default ( ) ;
369
+ let res = vcpu. restore_state ( vm. fd ( ) , & faulty_vcpu_state, 0 ) ;
340
370
assert ! ( res. is_err( ) ) ;
341
- assert ! ( matches!(
342
- res. unwrap_err( ) ,
343
- KvmVcpuError :: RestoreState ( ArchError :: SetOneReg ( 0 , _) )
344
- ) ) ;
345
371
346
- init_vcpu ( & vcpu. fd , vm. fd ( ) ) ;
372
+ vcpu. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
347
373
let state = vcpu. save_state ( ) . expect ( "Cannot save state of vcpu" ) ;
348
374
assert ! ( !state. regs. is_empty( ) ) ;
349
- vcpu. restore_state ( & state)
375
+ vcpu. restore_state ( vm . fd ( ) , & state, 0 )
350
376
. expect ( "Cannot restore state of vcpu" ) ;
351
377
}
352
378
@@ -367,20 +393,20 @@ mod tests {
367
393
fn test_dump_cpu_config_after_init ( ) {
368
394
// Test `dump_cpu_config()` after `KVM_VCPU_INIT`.
369
395
let ( mut vm, _vm_mem) = setup_vm ( 0x1000 ) ;
370
- let vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
396
+ let mut vcpu = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
371
397
vm. setup_irqchip ( 1 ) . unwrap ( ) ;
372
- vcpu. init ( vm. fd ( ) ) . unwrap ( ) ;
398
+ vcpu. init ( vm. fd ( ) , & [ ] ) . unwrap ( ) ;
373
399
374
400
assert ! ( vcpu. dump_cpu_config( ) . is_ok( ) ) ;
375
401
}
376
402
377
403
#[ test]
378
404
fn test_setup_non_boot_vcpu ( ) {
379
405
let ( vm, _) = setup_vm ( 0x1000 ) ;
380
- let vcpu1 = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
381
- assert ! ( vcpu1. init( vm. fd( ) ) . is_ok( ) ) ;
382
- let vcpu2 = KvmVcpu :: new ( 1 , & vm) . unwrap ( ) ;
383
- assert ! ( vcpu2. init( vm. fd( ) ) . is_ok( ) ) ;
406
+ let mut vcpu1 = KvmVcpu :: new ( 0 , & vm) . unwrap ( ) ;
407
+ assert ! ( vcpu1. init( vm. fd( ) , & [ ] ) . is_ok( ) ) ;
408
+ let mut vcpu2 = KvmVcpu :: new ( 1 , & vm) . unwrap ( ) ;
409
+ assert ! ( vcpu2. init( vm. fd( ) , & [ ] ) . is_ok( ) ) ;
384
410
}
385
411
386
412
#[ test]
0 commit comments