77
88use std:: fmt:: { Debug , Write } ;
99use std:: mem:: offset_of;
10- use std:: path:: PathBuf ;
1110
1211use kvm_bindings:: * ;
1312use kvm_ioctls:: { VcpuExit , VcpuFd , VmFd } ;
@@ -31,8 +30,8 @@ use crate::vstate::vm::Vm;
3130pub enum VcpuArchError {
3231 /// Failed to get register {0}: {1}
3332 GetOneReg ( u64 , kvm_ioctls:: Error ) ,
34- /// Failed to set register {0}: {1 }
35- SetOneReg ( u64 , kvm_ioctls:: Error ) ,
33+ /// Failed to set register {0:#x} to value {1}: {2 }
34+ SetOneReg ( u64 , String , kvm_ioctls:: Error ) ,
3635 /// Failed to retrieve list of registers: {0}
3736 GetRegList ( kvm_ioctls:: Error ) ,
3837 /// Failed to get multiprocessor state: {0}
@@ -48,9 +47,7 @@ pub enum VcpuArchError {
4847/// Extract the Manufacturer ID from the host.
4948/// The ID is found between bits 24-31 of MIDR_EL1 register.
5049pub fn get_manufacturer_id_from_host ( ) -> Result < u32 , VcpuArchError > {
51- let midr_el1_path =
52- & PathBuf :: from ( "/sys/devices/system/cpu/cpu0/regs/identification/midr_el1" . to_string ( ) ) ;
53-
50+ let midr_el1_path = "/sys/devices/system/cpu/cpu0/regs/identification/midr_el1" ;
5451 let midr_el1 = std:: fs:: read_to_string ( midr_el1_path) . map_err ( |err| {
5552 VcpuArchError :: GetMidrEl1 ( format ! ( "Failed to get MIDR_EL1 from host path: {err}" ) )
5653 } ) ?;
@@ -181,7 +178,11 @@ impl KvmVcpu {
181178 ) -> Result < ( ) , KvmVcpuError > {
182179 for reg in vcpu_config. cpu_config . regs . iter ( ) {
183180 self . fd . set_one_reg ( reg. id , reg. as_slice ( ) ) . map_err ( |err| {
184- KvmVcpuError :: ApplyCpuTemplate ( VcpuArchError :: SetOneReg ( reg. id , err) )
181+ KvmVcpuError :: ApplyCpuTemplate ( VcpuArchError :: SetOneReg (
182+ reg. id ,
183+ reg. value_str ( ) ,
184+ err,
185+ ) )
185186 } ) ?;
186187 }
187188
@@ -325,7 +326,9 @@ impl KvmVcpu {
325326 let id = arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , pstate) ;
326327 self . fd
327328 . set_one_reg ( id, & PSTATE_FAULT_BITS_64 . to_le_bytes ( ) )
328- . map_err ( |err| VcpuArchError :: SetOneReg ( id, err) ) ?;
329+ . map_err ( |err| {
330+ VcpuArchError :: SetOneReg ( id, format ! ( "{PSTATE_FAULT_BITS_64:#x}" ) , err)
331+ } ) ?;
329332
330333 // Other vCPUs are powered off initially awaiting PSCI wakeup.
331334 if self . index == 0 {
@@ -334,17 +337,18 @@ impl KvmVcpu {
334337 let id = arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , pc) ;
335338 self . fd
336339 . set_one_reg ( id, & boot_ip. to_le_bytes ( ) )
337- . map_err ( |err| VcpuArchError :: SetOneReg ( id, err) ) ?;
340+ . map_err ( |err| VcpuArchError :: SetOneReg ( id, format ! ( "{boot_ip:#x}" ) , err) ) ?;
338341
339342 // Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
340343 // "The device tree blob (dtb) must be placed on an 8-byte boundary and must
341344 // not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
342345 // We are choosing to place it the end of DRAM. See `get_fdt_addr`.
343346 let regs0 = offset_of ! ( user_pt_regs, regs) + kreg_off;
344347 let id = arm64_core_reg_id ! ( KVM_REG_SIZE_U64 , regs0) ;
348+ let fdt_addr = get_fdt_addr ( mem) ;
345349 self . fd
346- . set_one_reg ( id, & get_fdt_addr ( mem ) . to_le_bytes ( ) )
347- . map_err ( |err| VcpuArchError :: SetOneReg ( id, err) ) ?;
350+ . set_one_reg ( id, & fdt_addr . to_le_bytes ( ) )
351+ . map_err ( |err| VcpuArchError :: SetOneReg ( id, format ! ( "{fdt_addr:#x}" ) , err) ) ?;
348352
349353 // Reset the physical counter for the guest. This way we avoid guest reading
350354 // host physical counter.
@@ -360,7 +364,9 @@ impl KvmVcpu {
360364 if optional_capabilities. counter_offset {
361365 self . fd
362366 . set_one_reg ( KVM_REG_ARM_PTIMER_CNT , & [ 0 ; 8 ] )
363- . map_err ( |err| VcpuArchError :: SetOneReg ( id, err) ) ?;
367+ . map_err ( |err| {
368+ VcpuArchError :: SetOneReg ( id, format ! ( "{KVM_REG_ARM_PTIMER_CNT:#x}" ) , err)
369+ } ) ?;
364370 }
365371 }
366372 Ok ( ( ) )
@@ -412,7 +418,7 @@ impl KvmVcpu {
412418 pub fn set_register ( & self , reg : Aarch64RegisterRef ) -> Result < ( ) , VcpuArchError > {
413419 self . fd
414420 . set_one_reg ( reg. id , reg. as_slice ( ) )
415- . map_err ( |e| VcpuArchError :: SetOneReg ( reg. id , e) ) ?;
421+ . map_err ( |e| VcpuArchError :: SetOneReg ( reg. id , reg . value_str ( ) , e) ) ?;
416422 Ok ( ( ) )
417423 }
418424
@@ -526,13 +532,16 @@ mod tests {
526532 unsafe { libc:: close ( vm. fd ( ) . as_raw_fd ( ) ) } ;
527533
528534 let err = KvmVcpu :: new ( 0 , & vm) ;
535+
536+ // dropping vm would double close the gic fd, so leak it
537+ // do the drop before assertion. Otherwise if assert fails,
538+ // we get IO runtime error instead of assert error.
539+ std:: mem:: forget ( vm) ;
540+
529541 assert_eq ! (
530542 err. err( ) . unwrap( ) . to_string( ) ,
531543 "Error creating vcpu: Bad file descriptor (os error 9)" . to_string( )
532544 ) ;
533-
534- // dropping vm would double close the gic fd, so leak it
535- std:: mem:: forget ( vm) ;
536545 }
537546
538547 #[ test]
@@ -568,16 +577,20 @@ mod tests {
568577 & vcpu_config,
569578 & optional_capabilities,
570579 ) ;
580+
581+ // dropping vcpu would double close the gic fd, so leak it
582+ // do the drop before assertion. Otherwise if assert fails,
583+ // we get IO runtime error instead of assert error.
584+ std:: mem:: forget ( vcpu) ;
585+
571586 assert_eq ! (
572587 err. unwrap_err( ) ,
573588 KvmVcpuError :: ConfigureRegisters ( VcpuArchError :: SetOneReg (
574589 0x6030000000100042 ,
590+ "0x3c5" . to_string( ) ,
575591 kvm_ioctls:: Error :: new( 9 )
576592 ) )
577593 ) ;
578-
579- // dropping vcpu would double close the gic fd, so leak it
580- std:: mem:: forget ( vcpu) ;
581594 }
582595
583596 #[ test]
@@ -629,7 +642,7 @@ mod tests {
629642 let res = vcpu. restore_state ( & faulty_vcpu_state) ;
630643 assert ! ( matches!(
631644 res. unwrap_err( ) ,
632- KvmVcpuError :: RestoreState ( VcpuArchError :: SetOneReg ( 0 , _) )
645+ KvmVcpuError :: RestoreState ( VcpuArchError :: SetOneReg ( 0 , _, _ ) )
633646 ) ) ;
634647
635648 vcpu. init ( & [ ] ) . unwrap ( ) ;
@@ -699,7 +712,7 @@ mod tests {
699712 let res = vcpu. setup_boot_regs ( 0x0 , & mem, & optional_capabilities) ;
700713 assert ! ( matches!(
701714 res. unwrap_err( ) ,
702- VcpuArchError :: SetOneReg ( 0x6030000000100042 , _)
715+ VcpuArchError :: SetOneReg ( 0x6030000000100042 , _, _ )
703716 ) ) ;
704717
705718 vcpu. init_vcpu ( ) . unwrap ( ) ;
@@ -773,9 +786,12 @@ mod tests {
773786 assert ! ( matches!( res, Err ( VcpuArchError :: GetMp ( _) ) ) , "{:?}" , res) ;
774787
775788 let res = vcpu. set_mpstate ( kvm_mp_state:: default ( ) ) ;
776- assert ! ( matches!( res, Err ( VcpuArchError :: SetMp ( _) ) ) , "{:?}" , res) ;
777789
778790 // dropping vcpu would double close the fd, so leak it
791+ // do the drop before assertion. Otherwise if assert fails,
792+ // we get IO runtime error instead of assert error.
779793 std:: mem:: forget ( vcpu) ;
794+
795+ assert ! ( matches!( res, Err ( VcpuArchError :: SetMp ( _) ) ) , "{:?}" , res) ;
780796 }
781797}
0 commit comments