Skip to content

Commit 49d2309

Browse files
committed
define RtcState object
RtcState represents the state of the Rtc device, and is storing the state needed for restoring the device (no implementation detailis). The generic `events` object is not stored due to complexity reasons. More details in the design proposal: rust-vmm/community#118. Signed-off-by: Laura Loghin <lauralg@amazon.com>
1 parent 776b803 commit 49d2309

File tree

1 file changed

+111
-30
lines changed

1 file changed

+111
-30
lines changed

src/rtc_pl031.rs

Lines changed: 111 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
137152
fn 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-
163165
impl 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+
169179
impl<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

Comments
 (0)