Skip to content

Commit f8adb93

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 <[email protected]>
1 parent 6f7e471 commit f8adb93

File tree

1 file changed

+131
-27
lines changed

1 file changed

+131
-27
lines changed

src/rtc_pl031.rs

Lines changed: 131 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,20 @@ pub struct Rtc<EV: RtcEvents> {
134134
events: EV,
135135
}
136136

137+
/// The state of the Rtc device.
138+
pub struct RtcState {
139+
/// The load register.
140+
pub lr: u32,
141+
/// The offset applied to the counter to get the RTC value.
142+
pub offset: i64,
143+
/// The MR register.
144+
pub mr: u32,
145+
/// The interrupt mask.
146+
pub imsc: u32,
147+
/// The raw interrupt value.
148+
pub ris: u32,
149+
}
150+
137151
fn get_current_time() -> u32 {
138152
let epoch_time = SystemTime::now()
139153
.duration_since(UNIX_EPOCH)
@@ -147,55 +161,82 @@ fn get_current_time() -> u32 {
147161
epoch_time.as_secs() as u32
148162
}
149163

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-
163164
impl Default for Rtc<NoEvents> {
164165
fn default() -> Self {
165166
Self::new()
166167
}
167168
}
168169

169-
impl<EV: RtcEvents> Rtc<EV> {
170-
/// Creates a new `AMBA PL031 RTC` instance and invokes the `rtc_events`
171-
/// implementation of `RtcEvents` during operation.
172-
///
173-
/// # Arguments
174-
/// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
175-
/// of failure or missed events in the RTC operation.
176-
pub fn with_events(rtc_events: EV) -> Self {
177-
Rtc {
170+
// This is the state from which a fresh Rtc can be created.
171+
impl Default for RtcState {
172+
fn default() -> Self {
173+
RtcState {
178174
// The load register is initialized to 0.
179175
lr: 0,
180-
181176
offset: 0,
182-
183177
// The match register is initialised to zero (not currently used).
184178
// TODO: Implement the match register functionality.
185179
mr: 0,
186-
187180
// The interrupt mask is initialised as not set.
188181
imsc: 0,
189-
190182
// The raw interrupt is initialised as not asserted.
191183
ris: 0,
184+
}
185+
}
186+
}
187+
188+
impl Rtc<NoEvents> {
189+
/// Creates a new `AMBA PL031 RTC` instance without any metric capabilities. The instance is
190+
/// created from the default state.
191+
pub fn new() -> Self {
192+
Self::from_state(&RtcState::default(), NoEvents)
193+
}
194+
}
192195

193-
// A struct implementing RtcEvents for tracking the occurrence of
196+
impl<EV: RtcEvents> Rtc<EV> {
197+
/// Creates a new `AMBA PL031 RTC` instance from a given `state` and that is able to track
198+
/// events during operation using the passed `rtc_events` object.
199+
/// For creating the instance from a fresh state, [`with_events`](#method.with_events) or
200+
/// [`new`](#method.new) methods can be used.
201+
///
202+
/// # Arguments
203+
/// * `state` - A reference to the state from which the `Rtc` is constructed.
204+
/// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
205+
/// of failure or missed events in the RTC operation.
206+
pub fn from_state(state: &RtcState, rtc_events: EV) -> Self {
207+
Rtc {
208+
lr: state.lr,
209+
offset: state.offset,
210+
mr: state.mr,
211+
imsc: state.imsc,
212+
ris: state.ris,
213+
// A struct implementing `RtcEvents` for tracking the occurrence of
194214
// significant events.
195215
events: rtc_events,
196216
}
197217
}
198218

219+
/// Creates a new `AMBA PL031 RTC` instance that is able to track events during operation using
220+
/// the passed `rtc_events` object. The instance is created from the default state.
221+
///
222+
/// # Arguments
223+
/// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
224+
/// of failure or missed events in the RTC operation.
225+
pub fn with_events(rtc_events: EV) -> Self {
226+
Self::from_state(&RtcState::default(), rtc_events)
227+
}
228+
229+
/// Returns the state of the RTC.
230+
pub fn state(&self) -> RtcState {
231+
RtcState {
232+
lr: self.lr,
233+
offset: self.offset,
234+
mr: self.mr,
235+
imsc: self.imsc,
236+
ris: self.ris,
237+
}
238+
}
239+
199240
/// Provides a reference to the RTC events object.
200241
pub fn events(&self) -> &EV {
201242
&self.events
@@ -854,4 +895,67 @@ mod tests {
854895
assert_eq!(rtc.events.invalid_read_count.count(), 2);
855896
assert_eq!(rtc.events.invalid_write_count.count(), 0);
856897
}
898+
899+
#[test]
900+
fn test_state() {
901+
let metrics = Arc::new(ExampleRtcMetrics::default());
902+
let mut rtc = Rtc::with_events(metrics);
903+
let mut data = [0; 4];
904+
905+
// Get the RTC value with a load register of 0 (the initial value).
906+
rtc.read(RTCDR, &mut data);
907+
let first_read = u32::from_le_bytes(data);
908+
909+
// Increment LR and verify that the value was updated.
910+
let lr = get_current_time() + 100;
911+
data = lr.to_le_bytes();
912+
rtc.write(RTCLR, &data);
913+
914+
let state = rtc.state();
915+
rtc.read(RTCLR, &mut data);
916+
assert_eq!(state.lr.to_le_bytes(), data);
917+
918+
// Do an invalid `write` in order to increment a metric.
919+
let mut data2 = 123u32.to_le_bytes();
920+
rtc.write(AMBA_ID_HIGH + 4, &data2);
921+
assert_eq!(rtc.events.invalid_write_count.count(), 1);
922+
923+
let metrics = Arc::new(ExampleRtcMetrics::default());
924+
let mut rtc_from_state = Rtc::from_state(&state, metrics.clone());
925+
let state_after_restore = rtc_from_state.state();
926+
927+
// Check that the old and the new state are identical.
928+
assert_eq!(state.lr, state_after_restore.lr);
929+
assert_eq!(state.ris, state_after_restore.ris);
930+
assert_eq!(state.imsc, state_after_restore.imsc);
931+
assert_eq!(state.offset, state_after_restore.offset);
932+
assert_eq!(state.mr, state_after_restore.mr);
933+
934+
// Read the data register again.
935+
rtc.read(RTCDR, &mut data);
936+
let second_read = u32::from_le_bytes(data);
937+
// The RTC values should be different.
938+
assert!(second_read > first_read);
939+
940+
// Reading from the LR register should return the same value as before saving the state.
941+
rtc_from_state.read(RTCLR, &mut data2);
942+
assert_eq!(data, data2);
943+
944+
// Check that the restored `Rtc` doesn't keep the state of the old `metrics` object.
945+
assert_eq!(rtc_from_state.events.invalid_write_count.count(), 0);
946+
947+
// Let's increment again a metric, and this time save the state of events as well (separate
948+
// from the base state).
949+
// Do an invalid `write` in order to increment a metric.
950+
let data3 = 123u32.to_le_bytes();
951+
rtc_from_state.write(AMBA_ID_HIGH + 4, &data3);
952+
assert_eq!(rtc_from_state.events.invalid_write_count.count(), 1);
953+
954+
let state2 = rtc_from_state.state();
955+
let metrics2 = metrics;
956+
let rtc = Rtc::from_state(&state2, metrics2);
957+
958+
// Check that the restored `Rtc` keeps the state of the old `metrics` object.
959+
assert_eq!(rtc.events.invalid_write_count.count(), 1);
960+
}
857961
}

0 commit comments

Comments
 (0)