@@ -69,11 +69,6 @@ const PSR_D_BIT: u64 = 0x0000_0200;
69
69
// Taken from arch/arm64/kvm/inject_fault.c.
70
70
const PSTATE_FAULT_BITS_64 : u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT ;
71
71
72
- // Number of general purpose registers (i.e X0..X31)
73
- const NR_GP_REGS : usize = 31 ;
74
- // Number of FP_VREG registers.
75
- const NR_FP_VREGS : usize = 32 ;
76
-
77
72
// Following are macros that help with getting the ID of a aarch64 core register.
78
73
// The core register are represented by the user_pt_regs structure. Look for it in
79
74
// arch/arm64/include/uapi/asm/ptrace.h.
@@ -169,8 +164,8 @@ arm64_sys_reg!(KVM_REG_ARM_TIMER_CNT, 3, 3, 14, 3, 2);
169
164
///
170
165
/// * `state` - Array slice of [`Aarch64Register`] structures, representing the registers of a VCPU
171
166
/// state.
172
- pub fn get_manufacturer_id_from_state ( state : & [ Aarch64Register ] ) -> Result < u32 , Error > {
173
- let midr_el1 = state . iter ( ) . find ( |reg| reg. id == MIDR_EL1 ) ;
167
+ pub fn get_manufacturer_id_from_state ( regs : & [ Aarch64Register ] ) -> Result < u32 , Error > {
168
+ let midr_el1 = regs . iter ( ) . find ( |reg| reg. id == MIDR_EL1 ) ;
174
169
match midr_el1 {
175
170
Some ( register) => Ok ( register. value as u32 >> 24 ) ,
176
171
None => Err ( Error :: GetMidrEl1 (
@@ -199,12 +194,11 @@ pub fn get_manufacturer_id_from_host() -> Result<u32, Error> {
199
194
///
200
195
/// # Arguments
201
196
///
202
- /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
203
197
/// * `cpu_id` - Index of current vcpu.
204
198
/// * `boot_ip` - Starting instruction pointer.
205
199
/// * `mem` - Reserved DRAM for current VM.
206
200
pub fn setup_boot_regs (
207
- vcpu : & VcpuFd ,
201
+ vcpufd : & VcpuFd ,
208
202
cpu_id : u8 ,
209
203
boot_ip : u64 ,
210
204
mem : & GuestMemoryMmap ,
@@ -214,15 +208,17 @@ pub fn setup_boot_regs(
214
208
// Get the register index of the PSTATE (Processor State) register.
215
209
let pstate = offset__of ! ( user_pt_regs, pstate) + kreg_off;
216
210
let id = arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , pstate) ;
217
- vcpu. set_one_reg ( id, PSTATE_FAULT_BITS_64 . into ( ) )
211
+ vcpufd
212
+ . set_one_reg ( id, PSTATE_FAULT_BITS_64 . into ( ) )
218
213
. map_err ( |err| Error :: SetOneReg ( id, err) ) ?;
219
214
220
215
// Other vCPUs are powered off initially awaiting PSCI wakeup.
221
216
if cpu_id == 0 {
222
217
// Setting the PC (Processor Counter) to the current program address (kernel address).
223
218
let pc = offset__of ! ( user_pt_regs, pc) + kreg_off;
224
219
let id = arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , pc) ;
225
- vcpu. set_one_reg ( id, boot_ip. into ( ) )
220
+ vcpufd
221
+ . set_one_reg ( id, boot_ip. into ( ) )
226
222
. map_err ( |err| Error :: SetOneReg ( id, err) ) ?;
227
223
228
224
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
@@ -231,132 +227,47 @@ pub fn setup_boot_regs(
231
227
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
232
228
let regs0 = offset__of ! ( user_pt_regs, regs) + kreg_off;
233
229
let id = arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , regs0) ;
234
- vcpu. set_one_reg ( id, get_fdt_addr ( mem) . into ( ) )
230
+ vcpufd
231
+ . set_one_reg ( id, get_fdt_addr ( mem) . into ( ) )
235
232
. map_err ( |err| Error :: SetOneReg ( id, err) ) ?;
236
233
}
237
234
Ok ( ( ) )
238
235
}
239
236
240
237
/// Read the MPIDR - Multiprocessor Affinity Register.
241
- ///
242
- /// # Arguments
243
- ///
244
- /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
245
- pub fn read_mpidr ( vcpu : & VcpuFd ) -> Result < u64 , Error > {
246
- match vcpu. get_one_reg ( MPIDR_EL1 ) {
238
+ pub fn get_mpidr ( vcpufd : & VcpuFd ) -> Result < u64 , Error > {
239
+ match vcpufd. get_one_reg ( MPIDR_EL1 ) {
247
240
Err ( err) => Err ( Error :: GetOneReg ( MPIDR_EL1 , err) ) ,
248
241
// MPIDR register is 64 bit wide on aarch64, this expect cannot fail
249
242
// on supported architectures
250
243
Ok ( val) => Ok ( val. try_into ( ) . expect ( "MPIDR register to be 64 bit" ) ) ,
251
244
}
252
245
}
253
246
254
- /// Returns ids of core registers
255
- pub fn get_core_registers_ids ( ) -> Vec < u64 > {
256
- let mut ids = vec ! [ ] ;
257
- let mut off = offset__of ! ( user_pt_regs, regs) ;
258
- // There are 31 user_pt_regs:
259
- // https://elixir.free-electrons.com/linux/v4.14.174/source/arch/arm64/include/uapi/asm/ptrace.h#L72
260
- // These actually are the general-purpose registers of the Armv8-a
261
- // architecture (i.e x0-x30 if used as a 64bit register or w0-w30 when used as a 32bit
262
- // register).
263
- for _ in 0 ..NR_GP_REGS {
264
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , off) ) ;
265
- off += std:: mem:: size_of :: < u64 > ( ) ;
266
- }
267
-
268
- // We are now entering the "Other register" section of the ARMv8-a architecture.
269
- // First one, stack pointer.
270
- let off = offset__of ! ( user_pt_regs, sp) ;
271
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , off) ) ;
272
-
273
- // Second one, the program counter.
274
- let off = offset__of ! ( user_pt_regs, pc) ;
275
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , off) ) ;
276
-
277
- // Next is the processor state.
278
- let off = offset__of ! ( user_pt_regs, pstate) ;
279
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , off) ) ;
280
-
281
- // The stack pointer associated with EL1.
282
- let off = offset__of ! ( kvm_regs, sp_el1) ;
283
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , off) ) ;
284
-
285
- // Exception Link Register for EL1, when taking an exception to EL1, this register
286
- // holds the address to which to return afterwards.
287
- let off = offset__of ! ( kvm_regs, elr_el1) ;
288
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , off) ) ;
289
-
290
- // Saved Program Status Registers, there are 5 of them used in the kernel.
291
- let mut off = offset__of ! ( kvm_regs, spsr) ;
292
- for _ in 0 ..KVM_NR_SPSR {
293
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , off) ) ;
294
- off += std:: mem:: size_of :: < u64 > ( ) ;
295
- }
296
-
297
- // Now moving on to floating point registers which are stored in the user_fpsimd_state in
298
- // the kernel: https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
299
- let mut off = offset__of ! ( kvm_regs, fp_regs) + offset__of ! ( user_fpsimd_state, vregs) ;
300
- for _ in 0 ..NR_FP_VREGS {
301
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U128 , off) ) ;
302
- off += std:: mem:: size_of :: < u128 > ( ) ;
303
- }
304
-
305
- // Floating-point Status Register.
306
- let off = offset__of ! ( kvm_regs, fp_regs) + offset__of ! ( user_fpsimd_state, fpsr) ;
307
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U32 , off) ) ;
308
-
309
- // Floating-point Control Register.
310
- let off = offset__of ! ( kvm_regs, fp_regs) + offset__of ! ( user_fpsimd_state, fpcr) ;
311
- ids. push ( arm64_core_reg_id ! ( KVM_REG_SIZE_U32 , off) ) ;
312
-
313
- ids
314
- }
315
-
316
- /// Saves the states of the core registers into `state`.
317
- ///
318
- /// # Arguments
319
- ///
320
- /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
321
- /// * `state` - Input/Output vector of registers states.
322
- pub fn save_core_registers ( vcpu : & VcpuFd , state : & mut Vec < Aarch64Register > ) -> Result < ( ) , Error > {
323
- save_registers ( vcpu, & get_core_registers_ids ( ) , state)
324
- }
325
-
326
247
/// Saves the states of the system registers into `state`.
327
248
///
328
249
/// # Arguments
329
250
///
330
- /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
331
- /// * `state` - Input/Output vector of registers states.
332
- pub fn save_all_registers ( vcpu : & VcpuFd , state : & mut Vec < Aarch64Register > ) -> Result < ( ) , Error > {
333
- // Call KVM_GET_REG_LIST to get all registers available to the guest. For ArmV8 there are
334
- // less than 500 registers.
335
- let mut reg_list = RegList :: new ( 500 ) . map_err ( Error :: Fam ) ?;
336
- vcpu. get_reg_list ( & mut reg_list)
337
- . map_err ( Error :: GetRegList ) ?;
338
-
339
- save_registers ( vcpu, reg_list. as_slice ( ) , state) ?;
340
-
341
- Ok ( ( ) )
251
+ /// * `regs` - Input/Output vector of registers.
252
+ pub fn get_all_registers ( vcpufd : & VcpuFd , state : & mut Vec < Aarch64Register > ) -> Result < ( ) , Error > {
253
+ get_registers ( vcpufd, & get_all_registers_ids ( vcpufd) ?, state)
342
254
}
343
255
344
256
/// Saves states of registers into `state`.
345
257
///
346
258
/// # Arguments
347
259
///
348
- /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
349
260
/// * `ids` - Slice of registers ids to save.
350
- /// * `state ` - Input/Output vector of registers states .
351
- pub fn save_registers (
352
- vcpu : & VcpuFd ,
261
+ /// * `regs ` - Input/Output vector of registers.
262
+ pub fn get_registers (
263
+ vcpufd : & VcpuFd ,
353
264
ids : & [ u64 ] ,
354
- state : & mut Vec < Aarch64Register > ,
265
+ regs : & mut Vec < Aarch64Register > ,
355
266
) -> Result < ( ) , Error > {
356
267
for id in ids. iter ( ) {
357
- state . push ( Aarch64Register {
268
+ regs . push ( Aarch64Register {
358
269
id : * id,
359
- value : vcpu
270
+ value : vcpufd
360
271
. get_one_reg ( * id)
361
272
. map_err ( |e| Error :: GetOneReg ( * id, e) ) ?,
362
273
} ) ;
@@ -365,15 +276,26 @@ pub fn save_registers(
365
276
Ok ( ( ) )
366
277
}
367
278
279
+ /// Returns all registers ids, including core and system
280
+ pub fn get_all_registers_ids ( vcpufd : & VcpuFd ) -> Result < Vec < u64 > , Error > {
281
+ // Call KVM_GET_REG_LIST to get all registers available to the guest. For ArmV8 there are
282
+ // less than 500 registers.
283
+ let mut reg_list = RegList :: new ( 500 ) . map_err ( Error :: Fam ) ?;
284
+ vcpufd
285
+ . get_reg_list ( & mut reg_list)
286
+ . map_err ( Error :: GetRegList ) ?;
287
+ Ok ( reg_list. as_slice ( ) . to_vec ( ) )
288
+ }
289
+
368
290
/// Set the state of the system registers.
369
291
///
370
292
/// # Arguments
371
293
///
372
- /// * `vcpu ` - Structure for the VCPU that holds the VCPU's fd .
373
- /// * `state` - Structure containing the state of the system registers.
374
- pub fn restore_registers ( vcpu : & VcpuFd , state : & [ Aarch64Register ] ) -> Result < ( ) , Error > {
375
- for reg in state {
376
- vcpu . set_one_reg ( reg. id , reg. value )
294
+ /// * `regs ` - Slice of registers to be set .
295
+ pub fn set_registers ( vcpufd : & VcpuFd , regs : & [ Aarch64Register ] ) -> Result < ( ) , Error > {
296
+ for reg in regs {
297
+ vcpufd
298
+ . set_one_reg ( reg. id , reg. value )
377
299
. map_err ( |e| Error :: SetOneReg ( reg. id , e) ) ?;
378
300
}
379
301
Ok ( ( ) )
@@ -384,8 +306,8 @@ pub fn restore_registers(vcpu: &VcpuFd, state: &[Aarch64Register]) -> Result<(),
384
306
/// # Arguments
385
307
///
386
308
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
387
- pub fn get_mpstate ( vcpu : & VcpuFd ) -> Result < kvm_mp_state , Error > {
388
- vcpu . get_mp_state ( ) . map_err ( Error :: GetMp )
309
+ pub fn get_mpstate ( vcpufd : & VcpuFd ) -> Result < kvm_mp_state , Error > {
310
+ vcpufd . get_mp_state ( ) . map_err ( Error :: GetMp )
389
311
}
390
312
391
313
/// Set the state of the system registers.
@@ -394,8 +316,8 @@ pub fn get_mpstate(vcpu: &VcpuFd) -> Result<kvm_mp_state, Error> {
394
316
///
395
317
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
396
318
/// * `state` - Structure for returning the state of the system registers.
397
- pub fn set_mpstate ( vcpu : & VcpuFd , state : kvm_mp_state ) -> Result < ( ) , Error > {
398
- vcpu . set_mp_state ( state) . map_err ( Error :: SetMp )
319
+ pub fn set_mpstate ( vcpufd : & VcpuFd , state : kvm_mp_state ) -> Result < ( ) , Error > {
320
+ vcpufd . set_mp_state ( state) . map_err ( Error :: SetMp )
399
321
}
400
322
401
323
#[ cfg( test) ]
@@ -425,7 +347,7 @@ mod tests {
425
347
vm. get_preferred_target ( & mut kvi) . unwrap ( ) ;
426
348
vcpu. vcpu_init ( & kvi) . unwrap ( ) ;
427
349
428
- setup_boot_regs ( & vcpu, 0 , 0x0 , & mem) . unwrap ( ) ;
350
+ assert ! ( setup_boot_regs( & vcpu, 0 , 0x0 , & mem) . is_ok ( ) ) ;
429
351
}
430
352
#[ test]
431
353
fn test_read_mpidr ( ) {
@@ -436,49 +358,42 @@ mod tests {
436
358
vm. get_preferred_target ( & mut kvi) . unwrap ( ) ;
437
359
438
360
// Must fail when vcpu is not initialized yet.
439
- let res = read_mpidr ( & vcpu) ;
361
+ let res = get_mpidr ( & vcpu) ;
440
362
assert_eq ! (
441
363
res. unwrap_err( ) ,
442
364
Error :: GetOneReg ( MPIDR_EL1 , kvm_ioctls:: Error :: new( 8 ) )
443
365
) ;
444
366
445
367
vcpu. vcpu_init ( & kvi) . unwrap ( ) ;
446
- assert_eq ! ( read_mpidr ( & vcpu) . unwrap( ) , 0x8000_0000 ) ;
368
+ assert_eq ! ( get_mpidr ( & vcpu) . unwrap( ) , 0x8000_0000 ) ;
447
369
}
448
370
449
371
#[ test]
450
- fn test_save_restore_regs ( ) {
372
+ fn test_get_set_regs ( ) {
451
373
let kvm = Kvm :: new ( ) . unwrap ( ) ;
452
374
let vm = kvm. create_vm ( ) . unwrap ( ) ;
453
375
let vcpu = vm. create_vcpu ( 0 ) . unwrap ( ) ;
454
376
let mut kvi: kvm_bindings:: kvm_vcpu_init = kvm_bindings:: kvm_vcpu_init:: default ( ) ;
455
377
vm. get_preferred_target ( & mut kvi) . unwrap ( ) ;
456
378
457
379
// Must fail when vcpu is not initialized yet.
458
- let mut state = Vec :: new ( ) ;
459
- let res = save_core_registers ( & vcpu, & mut state) ;
460
- assert_eq ! (
461
- res. unwrap_err( ) ,
462
- Error :: GetOneReg ( 6931039826524241920 , kvm_ioctls:: Error :: new( 8 ) )
463
- ) ;
464
-
465
- let res = save_all_registers ( & vcpu, & mut state) ;
380
+ let mut regs = Vec :: new ( ) ;
381
+ let res = get_all_registers ( & vcpu, & mut regs) ;
466
382
assert_eq ! (
467
383
res. unwrap_err( ) ,
468
384
Error :: GetRegList ( kvm_ioctls:: Error :: new( 8 ) )
469
385
) ;
470
386
471
387
vcpu. vcpu_init ( & kvi) . unwrap ( ) ;
472
- save_core_registers ( & vcpu, & mut state) . unwrap ( ) ;
473
- save_all_registers ( & vcpu, & mut state) . unwrap ( ) ;
388
+ get_all_registers ( & vcpu, & mut regs) . unwrap ( ) ;
474
389
475
- restore_registers ( & vcpu, & state ) . unwrap ( ) ;
390
+ set_registers ( & vcpu, & regs ) . unwrap ( ) ;
476
391
let off = offset__of ! ( user_pt_regs, pstate) ;
477
392
let id = arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , off) ;
478
393
let pstate = vcpu
479
394
. get_one_reg ( id)
480
395
. expect ( "Failed to call kvm get one reg" ) ;
481
- assert ! ( state . contains( & Aarch64Register { id, value: pstate } ) ) ;
396
+ assert ! ( regs . contains( & Aarch64Register { id, value: pstate } ) ) ;
482
397
}
483
398
484
399
#[ test]
0 commit comments