@@ -5,7 +5,7 @@ use std::fmt;
55use std:: sync:: { Arc , Mutex } ;
66
77use kvm_bindings:: {
8- KVM_CLOCK_TSC_STABLE , KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE ,
8+ KVM_CLOCK_REALTIME , KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE ,
99 KVM_PIT_SPEAKER_DUMMY , MsrList , kvm_clock_data, kvm_irqchip, kvm_pit_config, kvm_pit_state2,
1010} ;
1111use kvm_ioctls:: Cap ;
@@ -30,6 +30,8 @@ pub enum ArchVmError {
3030 SetPit2 ( kvm_ioctls:: Error ) ,
3131 /// Set clock error: {0}
3232 SetClock ( kvm_ioctls:: Error ) ,
33+ /// clock_realtime requested but not present in the snapshot state
34+ ClockRealtimeNotInState ,
3335 /// Set IrqChipPicMaster error: {0}
3436 SetIrqChipPicMaster ( kvm_ioctls:: Error ) ,
3537 /// Set IrqChipPicSlave error: {0}
@@ -127,13 +129,25 @@ impl ArchVm {
127129 /// - [`kvm_ioctls::VmFd::set_irqchip`] errors.
128130 /// - [`kvm_ioctls::VmFd::set_irqchip`] errors.
129131 /// - [`kvm_ioctls::VmFd::set_irqchip`] errors.
130- pub fn restore_state ( & mut self , state : & VmState ) -> Result < ( ) , ArchVmError > {
132+ pub fn restore_state (
133+ & mut self ,
134+ state : & VmState ,
135+ clock_realtime : bool ,
136+ ) -> Result < ( ) , ArchVmError > {
131137 self . fd ( )
132138 . set_pit2 ( & state. pitstate )
133139 . map_err ( ArchVmError :: SetPit2 ) ?;
134- self . fd ( )
135- . set_clock ( & state. clock )
136- . map_err ( ArchVmError :: SetClock ) ?;
140+ let mut clock = state. clock ;
141+ clock. flags = if clock_realtime {
142+ // clock_realtime needs to be present in the snapshot
143+ if clock. flags & KVM_CLOCK_REALTIME == 0 {
144+ return Err ( ArchVmError :: ClockRealtimeNotInState ) ;
145+ }
146+ KVM_CLOCK_REALTIME
147+ } else {
148+ 0
149+ } ;
150+ self . fd ( ) . set_clock ( & clock) . map_err ( ArchVmError :: SetClock ) ?;
137151 self . fd ( )
138152 . set_irqchip ( & state. pic_master )
139153 . map_err ( ArchVmError :: SetIrqChipPicMaster ) ?;
@@ -167,9 +181,7 @@ impl ArchVm {
167181 pub fn save_state ( & self ) -> Result < VmState , ArchVmError > {
168182 let pitstate = self . fd ( ) . get_pit2 ( ) . map_err ( ArchVmError :: VmGetPit2 ) ?;
169183
170- let mut clock = self . fd ( ) . get_clock ( ) . map_err ( ArchVmError :: VmGetClock ) ?;
171- // This bit is not accepted in SET_CLOCK, clear it.
172- clock. flags &= !KVM_CLOCK_TSC_STABLE ;
184+ let clock = self . fd ( ) . get_clock ( ) . map_err ( ArchVmError :: VmGetClock ) ?;
173185
174186 let mut pic_master = kvm_irqchip {
175187 chip_id : KVM_IRQCHIP_PIC_MASTER ,
@@ -248,10 +260,13 @@ impl fmt::Debug for VmState {
248260#[ cfg( test) ]
249261mod tests {
250262 use kvm_bindings:: {
251- KVM_CLOCK_TSC_STABLE , KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE ,
263+ KVM_CLOCK_REALTIME , KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE ,
252264 KVM_PIT_SPEAKER_DUMMY ,
253265 } ;
266+ use kvm_ioctls:: Cap ;
267+ use std:: time:: SystemTime ;
254268
269+ use crate :: arch:: ArchVmError ;
255270 use crate :: vstate:: vm:: VmState ;
256271 use crate :: vstate:: vm:: tests:: { setup_vm, setup_vm_with_memory} ;
257272
@@ -270,15 +285,53 @@ mod tests {
270285 vm_state. pitstate. flags | KVM_PIT_SPEAKER_DUMMY ,
271286 KVM_PIT_SPEAKER_DUMMY
272287 ) ;
273- assert_eq ! ( vm_state. clock. flags & KVM_CLOCK_TSC_STABLE , 0 ) ;
274288 assert_eq ! ( vm_state. pic_master. chip_id, KVM_IRQCHIP_PIC_MASTER ) ;
275289 assert_eq ! ( vm_state. pic_slave. chip_id, KVM_IRQCHIP_PIC_SLAVE ) ;
276290 assert_eq ! ( vm_state. ioapic. chip_id, KVM_IRQCHIP_IOAPIC ) ;
277291
278292 let ( _, mut vm) = setup_vm_with_memory ( 0x1000 ) ;
279293 vm. setup_irqchip ( ) . unwrap ( ) ;
280294
281- vm. restore_state ( & vm_state) . unwrap ( ) ;
295+ vm. restore_state ( & vm_state, false ) . unwrap ( ) ;
296+ }
297+
298+ #[ cfg( target_arch = "x86_64" ) ]
299+ #[ test]
300+ fn test_vm_save_restore_state_kvm_clock_realtime ( ) {
301+ let ( kvm, vm) = setup_vm_with_memory ( 0x1000 ) ;
302+ vm. setup_irqchip ( ) . unwrap ( ) ;
303+
304+ let clock_realtime_supported =
305+ kvm. fd . check_extension_int ( Cap :: AdjustClock ) . cast_unsigned ( ) & KVM_CLOCK_REALTIME != 0 ;
306+
307+ // mock a state without realtime information
308+ let mut vm_state = vm. save_state ( ) . unwrap ( ) ;
309+ vm_state. clock . flags &= !KVM_CLOCK_REALTIME ;
310+
311+ let ( _, mut vm) = setup_vm_with_memory ( 0x1000 ) ;
312+ vm. setup_irqchip ( ) . unwrap ( ) ;
313+
314+ let res = vm. restore_state ( & vm_state, true ) ;
315+ assert ! ( res == Err ( ArchVmError :: ClockRealtimeNotInState ) ) ;
316+
317+ // mock a state with realtime information
318+ vm_state. clock . flags |= KVM_CLOCK_REALTIME ;
319+ vm_state. clock . realtime = SystemTime :: now ( )
320+ . duration_since ( SystemTime :: UNIX_EPOCH )
321+ . unwrap ( )
322+ . as_nanos ( )
323+ . try_into ( )
324+ . unwrap ( ) ;
325+
326+ let ( _, mut vm) = setup_vm_with_memory ( 0x1000 ) ;
327+ vm. setup_irqchip ( ) . unwrap ( ) ;
328+
329+ let res = vm. restore_state ( & vm_state, true ) ;
330+ if clock_realtime_supported {
331+ res. unwrap ( )
332+ } else {
333+ assert ! ( matches!( res, Err ( ArchVmError :: SetClock ( err) ) if err. errno( ) == libc:: EINVAL ) )
334+ }
282335 }
283336
284337 #[ cfg( target_arch = "x86_64" ) ]
@@ -296,18 +349,18 @@ mod tests {
296349 // Try to restore an invalid PIC Master chip ID
297350 let orig_master_chip_id = vm_state. pic_master . chip_id ;
298351 vm_state. pic_master . chip_id = KVM_NR_IRQCHIPS ;
299- vm. restore_state ( & vm_state) . unwrap_err ( ) ;
352+ vm. restore_state ( & vm_state, false ) . unwrap_err ( ) ;
300353 vm_state. pic_master . chip_id = orig_master_chip_id;
301354
302355 // Try to restore an invalid PIC Slave chip ID
303356 let orig_slave_chip_id = vm_state. pic_slave . chip_id ;
304357 vm_state. pic_slave . chip_id = KVM_NR_IRQCHIPS ;
305- vm. restore_state ( & vm_state) . unwrap_err ( ) ;
358+ vm. restore_state ( & vm_state, false ) . unwrap_err ( ) ;
306359 vm_state. pic_slave . chip_id = orig_slave_chip_id;
307360
308361 // Try to restore an invalid IOPIC chip ID
309362 vm_state. ioapic . chip_id = KVM_NR_IRQCHIPS ;
310- vm. restore_state ( & vm_state) . unwrap_err ( ) ;
363+ vm. restore_state ( & vm_state, false ) . unwrap_err ( ) ;
311364 }
312365
313366 #[ cfg( target_arch = "x86_64" ) ]
@@ -321,6 +374,6 @@ mod tests {
321374 let serialized_data = bitcode:: serialize ( & state) . unwrap ( ) ;
322375 let restored_state: VmState = bitcode:: deserialize ( & serialized_data) . unwrap ( ) ;
323376
324- vm. restore_state ( & restored_state) . unwrap ( ) ;
377+ vm. restore_state ( & restored_state, false ) . unwrap ( ) ;
325378 }
326379}
0 commit comments