@@ -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 ;
@@ -29,7 +29,13 @@ pub enum ArchVmError {
2929 /// Set PIT2 error: {0}
3030 SetPit2 ( kvm_ioctls:: Error ) ,
3131 /// Set clock error: {0}
32+ GetClock ( kvm_ioctls:: Error ) ,
33+ /// Set clock error: {0}
3234 SetClock ( kvm_ioctls:: Error ) ,
35+ /// KVM_CLOCK_REALTIME is unsupported by the current kernel
36+ UnsupportedClockRealtime ,
37+ /// clock_realtime requested but not present in the snapshot state
38+ ClockRealtimeNotInState ,
3339 /// Set IrqChipPicMaster error: {0}
3440 SetIrqChipPicMaster ( kvm_ioctls:: Error ) ,
3541 /// Set IrqChipPicSlave error: {0}
@@ -117,6 +123,14 @@ impl ArchVm {
117123 Ok ( ( ) )
118124 }
119125
126+ fn check_kvm_clock_realtime_supported ( & self ) -> Result < ( ) , ArchVmError > {
127+ let clock = self . fd ( ) . get_clock ( ) . map_err ( ArchVmError :: GetClock ) ?;
128+ if clock. flags & KVM_CLOCK_REALTIME == 0 {
129+ return Err ( ArchVmError :: UnsupportedClockRealtime ) ;
130+ }
131+ Ok ( ( ) )
132+ }
133+
120134 /// Restores the KVM VM state.
121135 ///
122136 /// # Errors
@@ -127,13 +141,27 @@ impl ArchVm {
127141 /// - [`kvm_ioctls::VmFd::set_irqchip`] errors.
128142 /// - [`kvm_ioctls::VmFd::set_irqchip`] errors.
129143 /// - [`kvm_ioctls::VmFd::set_irqchip`] errors.
130- pub fn restore_state ( & mut self , state : & VmState ) -> Result < ( ) , ArchVmError > {
144+ pub fn restore_state (
145+ & mut self ,
146+ state : & VmState ,
147+ clock_realtime : bool ,
148+ ) -> Result < ( ) , ArchVmError > {
131149 self . fd ( )
132150 . set_pit2 ( & state. pitstate )
133151 . map_err ( ArchVmError :: SetPit2 ) ?;
134- self . fd ( )
135- . set_clock ( & state. clock )
136- . map_err ( ArchVmError :: SetClock ) ?;
152+ let mut clock = state. clock ;
153+ clock. flags = if clock_realtime {
154+ // clock_realtime requires a host Linux >=5.16
155+ self . check_kvm_clock_realtime_supported ( ) ?;
156+ // clock_realtime needs to be present in the snapshot
157+ if clock. flags & KVM_CLOCK_REALTIME == 0 {
158+ return Err ( ArchVmError :: ClockRealtimeNotInState ) ;
159+ }
160+ KVM_CLOCK_REALTIME
161+ } else {
162+ 0
163+ } ;
164+ self . fd ( ) . set_clock ( & clock) . map_err ( ArchVmError :: SetClock ) ?;
137165 self . fd ( )
138166 . set_irqchip ( & state. pic_master )
139167 . map_err ( ArchVmError :: SetIrqChipPicMaster ) ?;
@@ -167,9 +195,7 @@ impl ArchVm {
167195 pub fn save_state ( & self ) -> Result < VmState , ArchVmError > {
168196 let pitstate = self . fd ( ) . get_pit2 ( ) . map_err ( ArchVmError :: VmGetPit2 ) ?;
169197
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 ;
198+ let clock = self . fd ( ) . get_clock ( ) . map_err ( ArchVmError :: VmGetClock ) ?;
173199
174200 let mut pic_master = kvm_irqchip {
175201 chip_id : KVM_IRQCHIP_PIC_MASTER ,
@@ -248,8 +274,7 @@ impl fmt::Debug for VmState {
248274#[ cfg( test) ]
249275mod tests {
250276 use kvm_bindings:: {
251- KVM_CLOCK_TSC_STABLE , KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE ,
252- KVM_PIT_SPEAKER_DUMMY ,
277+ KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE , KVM_PIT_SPEAKER_DUMMY ,
253278 } ;
254279
255280 use crate :: vstate:: vm:: VmState ;
@@ -270,15 +295,46 @@ mod tests {
270295 vm_state. pitstate. flags | KVM_PIT_SPEAKER_DUMMY ,
271296 KVM_PIT_SPEAKER_DUMMY
272297 ) ;
273- assert_eq ! ( vm_state. clock. flags & KVM_CLOCK_TSC_STABLE , 0 ) ;
274298 assert_eq ! ( vm_state. pic_master. chip_id, KVM_IRQCHIP_PIC_MASTER ) ;
275299 assert_eq ! ( vm_state. pic_slave. chip_id, KVM_IRQCHIP_PIC_SLAVE ) ;
276300 assert_eq ! ( vm_state. ioapic. chip_id, KVM_IRQCHIP_IOAPIC ) ;
277301
278302 let ( _, mut vm) = setup_vm_with_memory ( 0x1000 ) ;
279303 vm. setup_irqchip ( ) . unwrap ( ) ;
280304
281- vm. restore_state ( & vm_state) . unwrap ( ) ;
305+ vm. restore_state ( & vm_state, false ) . unwrap ( ) ;
306+ }
307+
308+ #[ cfg( target_arch = "x86_64" ) ]
309+ #[ test]
310+ fn test_vm_save_restore_state_kvm_clock_realtime ( ) {
311+ let ( _, vm) = setup_vm_with_memory ( 0x1000 ) ;
312+ vm. setup_irqchip ( ) . unwrap ( ) ;
313+ let vm_state = vm. save_state ( ) . unwrap ( ) ;
314+
315+ let ( _, mut vm) = setup_vm_with_memory ( 0x1000 ) ;
316+ vm. setup_irqchip ( ) . unwrap ( ) ;
317+
318+ let res = vm. restore_state ( & vm_state, true ) ;
319+ if vm. check_kvm_clock_realtime_supported ( ) . is_err ( ) {
320+ assert ! ( res == Err ( crate :: arch:: ArchVmError :: UnsupportedClockRealtime ) )
321+ } else {
322+ res. unwrap ( )
323+ }
324+
325+ // mock a state without realtime information
326+ let mut vm_state = vm_state;
327+ vm_state. clock . flags &= !kvm_bindings:: KVM_CLOCK_REALTIME ;
328+
329+ let ( _, mut vm) = setup_vm_with_memory ( 0x1000 ) ;
330+ vm. setup_irqchip ( ) . unwrap ( ) ;
331+
332+ let res = vm. restore_state ( & vm_state, true ) ;
333+ if vm. check_kvm_clock_realtime_supported ( ) . is_err ( ) {
334+ assert ! ( res == Err ( crate :: arch:: ArchVmError :: UnsupportedClockRealtime ) )
335+ } else {
336+ assert ! ( res == Err ( crate :: arch:: ArchVmError :: ClockRealtimeNotInState ) )
337+ }
282338 }
283339
284340 #[ cfg( target_arch = "x86_64" ) ]
@@ -296,18 +352,18 @@ mod tests {
296352 // Try to restore an invalid PIC Master chip ID
297353 let orig_master_chip_id = vm_state. pic_master . chip_id ;
298354 vm_state. pic_master . chip_id = KVM_NR_IRQCHIPS ;
299- vm. restore_state ( & vm_state) . unwrap_err ( ) ;
355+ vm. restore_state ( & vm_state, false ) . unwrap_err ( ) ;
300356 vm_state. pic_master . chip_id = orig_master_chip_id;
301357
302358 // Try to restore an invalid PIC Slave chip ID
303359 let orig_slave_chip_id = vm_state. pic_slave . chip_id ;
304360 vm_state. pic_slave . chip_id = KVM_NR_IRQCHIPS ;
305- vm. restore_state ( & vm_state) . unwrap_err ( ) ;
361+ vm. restore_state ( & vm_state, false ) . unwrap_err ( ) ;
306362 vm_state. pic_slave . chip_id = orig_slave_chip_id;
307363
308364 // Try to restore an invalid IOPIC chip ID
309365 vm_state. ioapic . chip_id = KVM_NR_IRQCHIPS ;
310- vm. restore_state ( & vm_state) . unwrap_err ( ) ;
366+ vm. restore_state ( & vm_state, false ) . unwrap_err ( ) ;
311367 }
312368
313369 #[ cfg( target_arch = "x86_64" ) ]
@@ -321,6 +377,6 @@ mod tests {
321377 let serialized_data = bitcode:: serialize ( & state) . unwrap ( ) ;
322378 let restored_state: VmState = bitcode:: deserialize ( & serialized_data) . unwrap ( ) ;
323379
324- vm. restore_state ( & restored_state) . unwrap ( ) ;
380+ vm. restore_state ( & restored_state, false ) . unwrap ( ) ;
325381 }
326382}
0 commit comments