@@ -87,7 +87,7 @@ impl<EV: RtcEvents> RtcEvents for Arc<EV> {
8787/// # use vm_superio::Rtc;
8888///
8989/// let mut data = [0; 4];
90- /// let mut rtc = Rtc::new ();
90+ /// let mut rtc = Rtc::default ();
9191/// const RTCDR: u16 = 0x0; // Data Register.
9292/// const RTCLR: u16 = 0x8; // Load Register.
9393///
@@ -134,6 +134,21 @@ pub struct Rtc<EV: RtcEvents> {
134134 events : EV ,
135135}
136136
137+ /// RTC State.
138+ #[ derive( Default ) ]
139+ pub struct RtcState {
140+ /// The load register.
141+ pub lr : u32 ,
142+ /// The offset applied to the counter to get the RTC value.
143+ pub offset : i64 ,
144+ /// The MR register.
145+ pub mr : u32 ,
146+ /// The interrupt mask.
147+ pub imsc : u32 ,
148+ /// The raw interrupt value.
149+ pub ris : u32 ,
150+ }
151+
137152fn get_current_time ( ) -> u32 {
138153 let epoch_time = SystemTime :: now ( )
139154 . duration_since ( UNIX_EPOCH )
@@ -147,52 +162,69 @@ fn get_current_time() -> u32 {
147162 epoch_time. as_secs ( ) as u32
148163}
149164
150- impl Rtc < NoEvents > {
151- /// Creates a new `AMBA PL031 RTC` instance without any metric
152- /// capabilities.
153- ///
154- /// # Example
155- ///
156- /// You can see an example of how to use this function in the
157- /// [`Example` section from `Rtc`](struct.Rtc.html#example).
158- pub fn new ( ) -> Rtc < NoEvents > {
159- Self :: with_events ( NoEvents )
160- }
161- }
162-
163165impl Default for Rtc < NoEvents > {
164166 fn default ( ) -> Self {
165167 Self :: new ( )
166168 }
167169}
168170
171+ impl Rtc < NoEvents > {
172+ /// Creates a new `AMBA PL031 RTC` instance without any metric
173+ /// capabilities.
174+ pub fn new ( ) -> Self {
175+ Self :: from_state ( & RtcState :: default ( ) , NoEvents )
176+ }
177+ }
178+
169179impl < EV : RtcEvents > Rtc < EV > {
170- /// Creates a new `AMBA PL031 RTC` instance and invokes the `rtc_events`
180+ /// Creates a new `AMBA PL031 RTC` instance from a given `state` and invokes the `rtc_events`
171181 /// implementation of `RtcEvents` during operation.
172182 ///
173183 /// # Arguments
184+ /// * `state` - A reference to the state from which the `Rtc` is constructed.
174185 /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
175186 /// of failure or missed events in the RTC operation.
176- pub fn with_events ( rtc_events : EV ) -> Self {
187+ pub fn from_state ( state : & RtcState , events : EV ) -> Self {
177188 Rtc {
178189 // The load register is initialized to 0.
179- lr : 0 ,
190+ lr : state . lr ,
180191
181- offset : 0 ,
192+ offset : state . offset ,
182193
183194 // The match register is initialised to zero (not currently used).
184195 // TODO: Implement the match register functionality.
185- mr : 0 ,
196+ mr : state . mr ,
186197
187198 // The interrupt mask is initialised as not set.
188- imsc : 0 ,
199+ imsc : state . imsc ,
189200
190201 // The raw interrupt is initialised as not asserted.
191- ris : 0 ,
202+ ris : state . ris ,
192203
193204 // A struct implementing RtcEvents for tracking the occurrence of
194205 // significant events.
195- events : rtc_events,
206+ events,
207+ }
208+ }
209+
210+ /// Creates a new `AMBA PL031 RTC` instance and invokes the `rtc_events`
211+ /// implementation of `RtcEvents` during operation.
212+ ///
213+ /// # Arguments
214+ /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
215+ /// of failure or missed events in the RTC operation.
216+ pub fn with_events ( rtc_events : EV ) -> Self {
217+ Self :: from_state ( & RtcState :: default ( ) , rtc_events)
218+ }
219+
220+ /// Returns the state of the RTC.
221+ pub fn state ( & self ) -> RtcState {
222+ RtcState {
223+ lr : self . lr ,
224+ offset : self . offset ,
225+ mr : self . mr ,
226+ imsc : self . imsc ,
227+ ris : self . ris ,
196228 }
197229 }
198230
@@ -345,7 +377,7 @@ mod tests {
345377 fn test_regression_year_1970 ( ) {
346378 // This is a regression test for: https://github.com/rust-vmm/vm-superio/issues/47.
347379 // The problem is that the time in the guest would show up as in the 1970s.
348- let mut rtc = Rtc :: new ( ) ;
380+ let mut rtc = Rtc :: default ( ) ;
349381 let expected_time = get_current_time ( ) ;
350382
351383 let mut actual_time = [ 0u8 ; 4 ] ;
@@ -414,7 +446,7 @@ mod tests {
414446 // Test reading and writing to the match register.
415447 // TODO: Implement the alarm functionality and confirm an interrupt
416448 // is raised when the match register is set.
417- let mut rtc = Rtc :: new ( ) ;
449+ let mut rtc = Rtc :: default ( ) ;
418450 let mut data: [ u8 ; 4 ] ;
419451
420452 // Write to the match register.
@@ -492,7 +524,7 @@ mod tests {
492524 #[ test]
493525 fn test_rtc_value_overflow ( ) {
494526 // Verify that the RTC value will wrap on overflow instead of panic.
495- let mut rtc = Rtc :: new ( ) ;
527+ let mut rtc = Rtc :: default ( ) ;
496528 let mut data: [ u8 ; 4 ] ;
497529
498530 // Write u32::MAX to the load register
@@ -524,7 +556,7 @@ mod tests {
524556 #[ test]
525557 fn test_interrupt_mask_set_clear_register ( ) {
526558 // Test setting and clearing the interrupt mask bit.
527- let mut rtc = Rtc :: new ( ) ;
559+ let mut rtc = Rtc :: default ( ) ;
528560 let mut data: [ u8 ; 4 ] ;
529561
530562 // Manually set the raw interrupt.
@@ -611,7 +643,7 @@ mod tests {
611643 fn test_control_register ( ) {
612644 // Writing 1 to the Control Register should reset the RTC value.
613645 // Writing 0 should have no effect.
614- let mut rtc = Rtc :: new ( ) ;
646+ let mut rtc = Rtc :: default ( ) ;
615647 let mut data: [ u8 ; 4 ] ;
616648
617649 // Let's move the guest time in the future.
@@ -659,7 +691,7 @@ mod tests {
659691 fn test_raw_interrupt_status_register ( ) {
660692 // Writing to the Raw Interrupt Status Register should have no effect,
661693 // and reading should return the value of RTCRIS.
662- let mut rtc = Rtc :: new ( ) ;
694+ let mut rtc = Rtc :: default ( ) ;
663695 let mut data = [ 0 ; 4 ] ;
664696
665697 // Set the raw interrupt for testing.
@@ -682,7 +714,7 @@ mod tests {
682714 fn test_mask_interrupt_status_register ( ) {
683715 // Writing to the Masked Interrupt Status Register should have no effect,
684716 // and reading should return the value of RTCRIS & RTCIMSC.
685- let mut rtc = Rtc :: new ( ) ;
717+ let mut rtc = Rtc :: default ( ) ;
686718 let mut data = [ 0 ; 4 ] ;
687719
688720 // Set the raw interrupt for testing.
@@ -718,7 +750,7 @@ mod tests {
718750
719751 #[ test]
720752 fn test_read_only_register_addresses ( ) {
721- let mut rtc = Rtc :: new ( ) ;
753+ let mut rtc = Rtc :: default ( ) ;
722754 let mut data = [ 0 ; 4 ] ;
723755
724756 // Read the current value of AMBA_ID_LOW.
@@ -854,4 +886,53 @@ mod tests {
854886 assert_eq ! ( rtc. events. invalid_read_count. count( ) , 2 ) ;
855887 assert_eq ! ( rtc. events. invalid_write_count. count( ) , 0 ) ;
856888 }
889+
890+ #[ test]
891+ fn test_state ( ) {
892+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
893+ let mut rtc = Rtc :: with_events ( metrics) ;
894+ let mut data = [ 0 ; 4 ] ;
895+
896+ // Get the RTC value with a load register of 0 (the initial value).
897+ rtc. read ( RTCDR , & mut data) ;
898+ let first_read = u32:: from_le_bytes ( data) ;
899+
900+ // Increment LR and verify that the value was updated.
901+ let lr = get_current_time ( ) + 100 ;
902+ data = lr. to_le_bytes ( ) ;
903+ rtc. write ( RTCLR , & data) ;
904+
905+ let state = rtc. state ( ) ;
906+ rtc. read ( RTCLR , & mut data) ;
907+ assert_eq ! ( state. lr. to_le_bytes( ) , data) ;
908+
909+ // Do an invalid `write` in order to increment a metric.
910+ let mut data2 = 123u32 . to_le_bytes ( ) ;
911+ rtc. write ( AMBA_ID_HIGH + 4 , & data2) ;
912+ assert_eq ! ( rtc. events. invalid_write_count. count( ) , 1 ) ;
913+
914+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
915+ let mut rtc_from_state = Rtc :: from_state ( & state, metrics) ;
916+ let state_after_restore = rtc_from_state. state ( ) ;
917+
918+ // Check that the old and the new state are identical.
919+ assert_eq ! ( state. lr, state_after_restore. lr) ;
920+ assert_eq ! ( state. ris, state_after_restore. ris) ;
921+ assert_eq ! ( state. imsc, state_after_restore. imsc) ;
922+ assert_eq ! ( state. offset, state_after_restore. offset) ;
923+ assert_eq ! ( state. mr, state_after_restore. mr) ;
924+
925+ // Read the data register again.
926+ rtc. read ( RTCDR , & mut data) ;
927+ let second_read = u32:: from_le_bytes ( data) ;
928+ // The RTC values should be different.
929+ assert ! ( second_read > first_read) ;
930+
931+ // Reading from the LR register should return the same value as before saving the state.
932+ rtc_from_state. read ( RTCLR , & mut data2) ;
933+ assert_eq ! ( data, data2) ;
934+
935+ // Check that the restored `Rtc` doesn't keep the state of the old `metrics` object.
936+ assert_eq ! ( rtc_from_state. events. invalid_write_count. count( ) , 0 ) ;
937+ }
857938}
0 commit comments