@@ -14,6 +14,7 @@ use log::warn;
1414
1515use super :: get_fdt_addr;
1616use super :: regs:: * ;
17+ use crate :: vstate:: kvm:: OptionalCapabilities ;
1718use crate :: vstate:: memory:: GuestMemoryMmap ;
1819
1920/// Errors thrown while setting aarch64 registers.
@@ -79,6 +80,7 @@ pub fn setup_boot_regs(
7980 cpu_id : u8 ,
8081 boot_ip : u64 ,
8182 mem : & GuestMemoryMmap ,
83+ optional_capabilities : & OptionalCapabilities ,
8284) -> Result < ( ) , VcpuError > {
8385 let kreg_off = offset_of ! ( kvm_regs, regs) ;
8486
@@ -113,17 +115,16 @@ pub fn setup_boot_regs(
113115 // Resetting KVM_REG_ARM_PTIMER_CNT for single vcpu is enough because there is only
114116 // one timer struct with offsets per VM.
115117 // Because the access to KVM_REG_ARM_PTIMER_CNT is only present starting 6.4 kernel,
116- // we don't fail if ioctl returns an error.
118+ // we only do the reset if KVM_CAP_COUNTER_OFFSET is present as it was added
119+ // in the same patch series as the ability to set the KVM_REG_ARM_PTIMER_CNT register.
117120 // Path series which introduced the needed changes:
118121 // https://lore.kernel.org/all/[email protected] / 119122 // Note: the value observed by the guest will still be above 0, because there is a delta
120123 // time between this resetting and first call to KVM_RUN.
121- let zero: u64 = 0 ;
122- if vcpufd
123- . set_one_reg ( KVM_REG_ARM_PTIMER_CNT , & zero. to_le_bytes ( ) )
124- . is_err ( )
125- {
126- warn ! ( "Unable to reset VM physical counter. VM will use host value instead." ) ;
124+ if optional_capabilities. counter_offset {
125+ vcpufd
126+ . set_one_reg ( KVM_REG_ARM_PTIMER_CNT , & [ 0 ; 8 ] )
127+ . map_err ( |err| VcpuError :: SetOneReg ( id, err) ) ?;
127128 }
128129 }
129130 Ok ( ( ) )
@@ -246,7 +247,9 @@ mod tests {
246247 let vcpu = vm. create_vcpu ( 0 ) . unwrap ( ) ;
247248 let mem = arch_mem ( layout:: FDT_MAX_SIZE + 0x1000 ) ;
248249
249- let res = setup_boot_regs ( & vcpu, 0 , 0x0 , & mem) ;
250+ let optional_capabilities = kvm. optional_capabilities ( ) ;
251+
252+ let res = setup_boot_regs ( & vcpu, 0 , 0x0 , & mem, & optional_capabilities) ;
250253 assert ! ( matches!(
251254 res. unwrap_err( ) ,
252255 VcpuError :: SetOneReg ( 0x6030000000100042 , _)
@@ -256,14 +259,17 @@ mod tests {
256259 vm. get_preferred_target ( & mut kvi) . unwrap ( ) ;
257260 vcpu. vcpu_init ( & kvi) . unwrap ( ) ;
258261
259- setup_boot_regs ( & vcpu, 0 , 0x0 , & mem) . unwrap ( ) ;
262+ setup_boot_regs ( & vcpu, 0 , 0x0 , & mem, & optional_capabilities ) . unwrap ( ) ;
260263
261264 // Check that the register is reset on compatible kernels.
262265 // Because there is a delta in time between we reset the register and time we
263266 // read it, we cannot compare with 0. Instead we read CNTVNT_EL0 (Virtual counter)
264267 // from the host. The host value should be much bigger than the VM physical counter.
265- let mut reg_bytes = [ 0_u8 ; 8 ] ;
266- if vcpu. get_one_reg ( SYS_CNTPCT_EL0 , & mut reg_bytes) . is_ok ( ) {
268+ if optional_capabilities. counter_offset {
269+ let mut reg_bytes = [ 0_u8 ; 8 ] ;
270+ vcpu. get_one_reg ( SYS_CNTPCT_EL0 , & mut reg_bytes) . unwrap ( ) ;
271+ let counter_value = u64:: from_le_bytes ( reg_bytes) ;
272+
267273 let virt_count = unsafe {
268274 // Rust is so smart, it cannot figure out that `virt_count`
269275 // is read later in the assert!, so it complains about unused assignment.
@@ -276,7 +282,7 @@ mod tests {
276282 ) ;
277283 virt_count
278284 } ;
279- let counter_value = u64 :: from_le_bytes ( reg_bytes ) ;
285+
280286 assert ! ( counter_value < virt_count) ;
281287 }
282288 }
0 commit comments