xref: /aosp_15_r20/external/crosvm/devices/src/cmos.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2017 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::cmp::min;
6 use std::sync::Arc;
7 use std::time::Duration;
8 use std::time::Instant;
9 
10 use anyhow::anyhow;
11 use anyhow::Context;
12 use base::custom_serde::deserialize_seq_to_arr;
13 use base::custom_serde::serialize_arr;
14 use base::error;
15 use base::info;
16 use base::Event;
17 use base::EventToken;
18 use base::Timer;
19 use base::TimerTrait;
20 use base::Tube;
21 use base::WaitContext;
22 use base::WorkerThread;
23 use chrono::DateTime;
24 use chrono::Datelike;
25 use chrono::TimeZone;
26 use chrono::Timelike;
27 use chrono::Utc;
28 use metrics::log_metric;
29 use metrics::MetricEventType;
30 use serde::Deserialize;
31 use serde::Serialize;
32 use sync::Mutex;
33 use vm_control::VmResponse;
34 
35 use crate::pci::CrosvmDeviceId;
36 use crate::BusAccessInfo;
37 use crate::BusDevice;
38 use crate::DeviceId;
39 use crate::IrqEdgeEvent;
40 use crate::Suspendable;
41 
42 pub const RTC_IRQ: u8 = 8;
43 
44 const INDEX_MASK: u8 = 0x7f;
45 const INDEX_OFFSET: u64 = 0x0;
46 const DATA_OFFSET: u64 = 0x1;
47 const DATA_LEN: usize = 128;
48 
49 const RTC_REG_SEC: u8 = 0x0;
50 const RTC_REG_ALARM_SEC: u8 = 0x1;
51 const RTC_REG_MIN: u8 = 0x2;
52 const RTC_REG_ALARM_MIN: u8 = 0x3;
53 const RTC_REG_HOUR: u8 = 0x4;
54 const RTC_REG_ALARM_HOUR: u8 = 0x5;
55 const RTC_REG_WEEK_DAY: u8 = 0x6;
56 const RTC_REG_DAY: u8 = 0x7;
57 const RTC_REG_MONTH: u8 = 0x8;
58 const RTC_REG_YEAR: u8 = 0x9;
59 pub const RTC_REG_CENTURY: u8 = 0x32;
60 pub const RTC_REG_ALARM_DAY: u8 = 0x33;
61 pub const RTC_REG_ALARM_MONTH: u8 = 0x34;
62 
63 const RTC_REG_B: u8 = 0x0b;
64 const RTC_REG_B_UNSUPPORTED: u8 = 0xdd;
65 const RTC_REG_B_24_HOUR_MODE: u8 = 0x02;
66 const RTC_REG_B_ALARM_ENABLE: u8 = 0x20;
67 
68 const RTC_REG_C: u8 = 0x0c;
69 const RTC_REG_C_IRQF: u8 = 0x80;
70 const RTC_REG_C_AF: u8 = 0x20;
71 
72 const RTC_REG_D: u8 = 0x0d;
73 const RTC_REG_D_VRT: u8 = 0x80; // RAM and time valid
74 
75 pub type CmosNowFn = fn() -> DateTime<Utc>;
76 
77 // Alarm state shared between Cmos and the alarm worker thread.
78 struct AlarmState {
79     alarm: Timer,
80     vm_control: Tube,
81     irq: IrqEdgeEvent,
82     armed_time: Instant,
83     clear_evt: Option<Event>,
84 }
85 
86 impl AlarmState {
trigger_rtc_interrupt(&self) -> anyhow::Result<Event>87     fn trigger_rtc_interrupt(&self) -> anyhow::Result<Event> {
88         self.irq.trigger().context("failed to trigger irq")?;
89 
90         let elapsed = self.armed_time.elapsed().as_millis();
91         log_metric(
92             MetricEventType::RtcWakeup,
93             elapsed.try_into().unwrap_or(i64::MAX),
94         );
95 
96         let msg = vm_control::VmRequest::Rtc {
97             clear_evt: Event::new().context("failed to create clear event")?,
98         };
99 
100         // The Linux kernel expects wakeups to come via ACPI when ACPI is enabled. There's
101         // no real way to determine that here, so just send this unconditionally.
102         self.vm_control.send(&msg).context("send failed")?;
103 
104         let vm_control::VmRequest::Rtc { clear_evt } = msg else {
105             unreachable!("message type failure");
106         };
107 
108         match self.vm_control.recv().context("recv failed")? {
109             VmResponse::Ok => Ok(clear_evt),
110             resp => Err(anyhow!("unexpected rtc response: {:?}", resp)),
111         }
112     }
113 }
114 
115 /// A CMOS/RTC device commonly seen on x86 I/O port 0x70/0x71.
116 #[derive(Serialize)]
117 pub struct Cmos {
118     index: u8,
119     #[serde(serialize_with = "serialize_arr")]
120     data: [u8; DATA_LEN],
121     #[serde(skip_serializing)] // skip serializing time function.
122     now_fn: CmosNowFn,
123     // alarm_time is re-loaded from data on deserialization, so there's
124     // no need to explicitly serialize it.
125     #[serde(skip_serializing)]
126     alarm_time: Option<DateTime<Utc>>,
127     // alarm_state fields are either constant across snapshotting or
128     // reloaded from |data| on restore, so no need to serialize.
129     #[serde(skip_serializing)]
130     alarm_state: Arc<Mutex<AlarmState>>,
131     #[serde(skip_serializing)] // skip serializing the worker thread
132     worker: Option<WorkerThread<()>>,
133 }
134 
135 impl Cmos {
136     /// Constructs a CMOS/RTC device with initial data.
137     /// `mem_below_4g` is the size of memory in bytes below the 32-bit gap.
138     /// `mem_above_4g` is the size of memory in bytes above the 32-bit gap.
139     /// `now_fn` is a function that returns the current date and time.
new( mem_below_4g: u64, mem_above_4g: u64, now_fn: CmosNowFn, vm_control: Tube, irq: IrqEdgeEvent, ) -> anyhow::Result<Cmos>140     pub fn new(
141         mem_below_4g: u64,
142         mem_above_4g: u64,
143         now_fn: CmosNowFn,
144         vm_control: Tube,
145         irq: IrqEdgeEvent,
146     ) -> anyhow::Result<Cmos> {
147         let mut data = [0u8; DATA_LEN];
148 
149         data[0x0B] = RTC_REG_B_24_HOUR_MODE; // Status Register B: 24-hour mode
150 
151         // Extended memory from 16 MB to 4 GB in units of 64 KB
152         let ext_mem = min(
153             0xFFFF,
154             mem_below_4g.saturating_sub(16 * 1024 * 1024) / (64 * 1024),
155         );
156         data[0x34] = ext_mem as u8;
157         data[0x35] = (ext_mem >> 8) as u8;
158 
159         // High memory (> 4GB) in units of 64 KB
160         let high_mem = min(0xFFFFFF, mem_above_4g / (64 * 1024));
161         data[0x5b] = high_mem as u8;
162         data[0x5c] = (high_mem >> 8) as u8;
163         data[0x5d] = (high_mem >> 16) as u8;
164 
165         Ok(Cmos {
166             index: 0,
167             data,
168             now_fn,
169             alarm_time: None,
170             alarm_state: Arc::new(Mutex::new(AlarmState {
171                 alarm: Timer::new().context("cmos timer")?,
172                 irq,
173                 vm_control,
174                 // Not actually armed, but simpler than wrapping with an Option.
175                 armed_time: Instant::now(),
176                 clear_evt: None,
177             })),
178             worker: None,
179         })
180     }
181 
spawn_worker(&mut self, alarm_state: Arc<Mutex<AlarmState>>)182     fn spawn_worker(&mut self, alarm_state: Arc<Mutex<AlarmState>>) {
183         self.worker = Some(WorkerThread::start("CMOS_alarm", move |kill_evt| {
184             if let Err(e) = run_cmos_worker(alarm_state, kill_evt) {
185                 error!("Failed to spawn worker {:?}", e);
186             }
187         }));
188     }
189 
set_alarm(&mut self)190     fn set_alarm(&mut self) {
191         let mut state = self.alarm_state.lock();
192         if self.data[RTC_REG_B as usize] & RTC_REG_B_ALARM_ENABLE != 0 {
193             let now = (self.now_fn)();
194             let target = alarm_from_registers(now.year(), &self.data).and_then(|this_year| {
195                 // There is no year register for the alarm. If the alarm target has
196                 // already passed this year, then the next time it will occur is next
197                 // year.
198                 //
199                 // Note that there is something of a race condition here. If |now|
200                 // advances while the driver is configuring the alarm, then an alarm that
201                 // should only be one second in the future could become one year in the
202                 // future. Unfortunately there isn't anything in the rtc-cmos hardware
203                 // specification that lets us handle this race condition in the device, so
204                 // we just have to rely on the driver to deal with it.
205                 if this_year < now {
206                     alarm_from_registers(now.year() + 1, &self.data)
207                 } else {
208                     Some(this_year)
209                 }
210             });
211             if let Some(target) = target {
212                 if Some(target) != self.alarm_time {
213                     self.alarm_time = Some(target);
214                     state.armed_time = Instant::now();
215 
216                     let duration = target
217                         .signed_duration_since(now)
218                         .to_std()
219                         .unwrap_or(Duration::new(0, 0));
220                     if let Err(e) = state.alarm.reset_oneshot(duration) {
221                         error!("Failed to set alarm {:?}", e);
222                     }
223                 }
224             }
225         } else if self.alarm_time.take().is_some() {
226             if let Err(e) = state.alarm.clear() {
227                 error!("Failed to clear alarm {:?}", e);
228             }
229             if let Some(clear_evt) = state.clear_evt.take() {
230                 if let Err(e) = clear_evt.signal() {
231                     error!("failed to clear rtc pm signal {:?}", e);
232                 }
233             }
234         }
235 
236         let needs_worker = self.alarm_time.is_some();
237         drop(state);
238 
239         if needs_worker && self.worker.is_none() {
240             self.spawn_worker(self.alarm_state.clone());
241         }
242     }
243 }
244 
run_cmos_worker(alarm_state: Arc<Mutex<AlarmState>>, kill_evt: Event) -> anyhow::Result<()>245 fn run_cmos_worker(alarm_state: Arc<Mutex<AlarmState>>, kill_evt: Event) -> anyhow::Result<()> {
246     #[derive(EventToken)]
247     enum Token {
248         Alarm,
249         Kill,
250     }
251 
252     let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
253         (&alarm_state.lock().alarm, Token::Alarm),
254         (&kill_evt, Token::Kill),
255     ])
256     .context("worker context failed")?;
257 
258     loop {
259         let events = wait_ctx.wait().context("wait failed")?;
260         let mut state = alarm_state.lock();
261         for event in events.iter().filter(|e| e.is_readable) {
262             match event.token {
263                 Token::Alarm => {
264                     if state.alarm.mark_waited().context("timer ack failed")? {
265                         continue;
266                     }
267 
268                     match state.trigger_rtc_interrupt() {
269                         Ok(clear_evt) => state.clear_evt = Some(clear_evt),
270                         Err(e) => error!("Failed to send rtc {:?}", e),
271                     }
272                 }
273                 Token::Kill => return Ok(()),
274             }
275         }
276     }
277 }
278 
from_bcd(v: u8) -> Option<u32>279 fn from_bcd(v: u8) -> Option<u32> {
280     let ones = (v & 0xf) as u32;
281     let tens = (v >> 4) as u32;
282     if ones < 10 && tens < 10 {
283         Some(10 * tens + ones)
284     } else {
285         None
286     }
287 }
288 
alarm_from_registers(year: i32, data: &[u8; DATA_LEN]) -> Option<DateTime<Utc>>289 fn alarm_from_registers(year: i32, data: &[u8; DATA_LEN]) -> Option<DateTime<Utc>> {
290     Utc.with_ymd_and_hms(
291         year,
292         from_bcd(data[RTC_REG_ALARM_MONTH as usize])?,
293         from_bcd(data[RTC_REG_ALARM_DAY as usize])?,
294         from_bcd(data[RTC_REG_ALARM_HOUR as usize])?,
295         from_bcd(data[RTC_REG_ALARM_MIN as usize])?,
296         from_bcd(data[RTC_REG_ALARM_SEC as usize])?,
297     )
298     .single()
299 }
300 
301 impl BusDevice for Cmos {
device_id(&self) -> DeviceId302     fn device_id(&self) -> DeviceId {
303         CrosvmDeviceId::Cmos.into()
304     }
305 
debug_label(&self) -> String306     fn debug_label(&self) -> String {
307         "cmos".to_owned()
308     }
309 
write(&mut self, info: BusAccessInfo, data: &[u8])310     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
311         if data.len() != 1 {
312             return;
313         }
314 
315         match info.offset {
316             INDEX_OFFSET => self.index = data[0] & INDEX_MASK,
317             DATA_OFFSET => {
318                 let mut data = data[0];
319                 if self.index == RTC_REG_B {
320                     // The features which we don't support are:
321                     //   0x80 (SET)  - disable clock updates (i.e. let guest configure the clock)
322                     //   0x40 (PIE)  - enable periodic interrupts
323                     //   0x10 (IUE)  - enable interrupts after clock updates
324                     //   0x08 (SQWE) - enable square wave generation
325                     //   0x04 (DM)   - use binary data format (instead of BCD)
326                     //   0x01 (DSE)  - control daylight savings (we just do what the host does)
327                     if data & RTC_REG_B_UNSUPPORTED != 0 {
328                         info!(
329                             "Ignoring unsupported bits: {:x}",
330                             data & RTC_REG_B_UNSUPPORTED
331                         );
332                         data &= !RTC_REG_B_UNSUPPORTED;
333                     }
334                     if data & RTC_REG_B_24_HOUR_MODE == 0 {
335                         info!("12-hour mode unsupported");
336                         data |= RTC_REG_B_24_HOUR_MODE;
337                     }
338                 }
339 
340                 self.data[self.index as usize] = data;
341 
342                 if self.index == RTC_REG_B {
343                     self.set_alarm();
344                 }
345             }
346             o => panic!("bad write offset on CMOS device: {}", o),
347         }
348     }
349 
read(&mut self, info: BusAccessInfo, data: &mut [u8])350     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
351         fn to_bcd(v: u8) -> u8 {
352             assert!(v < 100);
353             ((v / 10) << 4) | (v % 10)
354         }
355 
356         if data.len() != 1 {
357             return;
358         }
359 
360         data[0] = match info.offset {
361             INDEX_OFFSET => self.index,
362             DATA_OFFSET => {
363                 let now = (self.now_fn)();
364                 let seconds = now.second(); // 0..=59
365                 let minutes = now.minute(); // 0..=59
366                 let hours = now.hour(); // 0..=23 (24-hour mode only)
367                 let week_day = now.weekday().number_from_sunday(); // 1 (Sun) ..= 7 (Sat)
368                 let day = now.day(); // 1..=31
369                 let month = now.month(); // 1..=12
370                 let year = now.year();
371                 match self.index {
372                     RTC_REG_SEC => to_bcd(seconds as u8),
373                     RTC_REG_MIN => to_bcd(minutes as u8),
374                     RTC_REG_HOUR => to_bcd(hours as u8),
375                     RTC_REG_WEEK_DAY => to_bcd(week_day as u8),
376                     RTC_REG_DAY => to_bcd(day as u8),
377                     RTC_REG_MONTH => to_bcd(month as u8),
378                     RTC_REG_YEAR => to_bcd((year % 100) as u8),
379                     RTC_REG_CENTURY => to_bcd((year / 100) as u8),
380                     RTC_REG_C => {
381                         if self
382                             .alarm_time
383                             .map_or(false, |alarm_time| alarm_time <= now)
384                         {
385                             // Reading from RTC_REG_C resets interrupts, so clear the
386                             // status bits. The IrqEdgeEvent is reset automatically.
387                             self.alarm_time.take();
388                             RTC_REG_C_IRQF | RTC_REG_C_AF
389                         } else {
390                             0
391                         }
392                     }
393                     RTC_REG_D => RTC_REG_D_VRT,
394                     _ => {
395                         // self.index is always guaranteed to be in range via INDEX_MASK.
396                         self.data[(self.index & INDEX_MASK) as usize]
397                     }
398                 }
399             }
400             o => panic!("bad read offset on CMOS device: {}", o),
401         }
402     }
403 }
404 
405 impl Suspendable for Cmos {
snapshot(&mut self) -> anyhow::Result<serde_json::Value>406     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
407         serde_json::to_value(self).context("failed to serialize Cmos")
408     }
409 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>410     fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
411         #[derive(Deserialize)]
412         struct CmosIndex {
413             index: u8,
414             #[serde(deserialize_with = "deserialize_seq_to_arr")]
415             data: [u8; DATA_LEN],
416         }
417 
418         let deser: CmosIndex =
419             serde_json::from_value(data).context("failed to deserialize Cmos")?;
420         self.index = deser.index;
421         self.data = deser.data;
422         self.set_alarm();
423 
424         Ok(())
425     }
426 
sleep(&mut self) -> anyhow::Result<()>427     fn sleep(&mut self) -> anyhow::Result<()> {
428         if let Some(worker) = self.worker.take() {
429             worker.stop();
430         }
431         Ok(())
432     }
433 
wake(&mut self) -> anyhow::Result<()>434     fn wake(&mut self) -> anyhow::Result<()> {
435         self.spawn_worker(self.alarm_state.clone());
436         Ok(())
437     }
438 }
439 
440 #[cfg(test)]
441 mod tests {
442     use super::*;
443     use crate::suspendable_tests;
444 
read_reg(cmos: &mut Cmos, reg: u8) -> u8445     fn read_reg(cmos: &mut Cmos, reg: u8) -> u8 {
446         // Write register number to INDEX_OFFSET (0).
447         cmos.write(
448             BusAccessInfo {
449                 offset: 0,
450                 address: 0x70,
451                 id: 0,
452             },
453             &[reg],
454         );
455 
456         // Read register value back from DATA_OFFSET (1).
457 
458         let mut data = [0u8];
459         cmos.read(
460             BusAccessInfo {
461                 offset: 1,
462                 address: 0x71,
463                 id: 0,
464             },
465             &mut data,
466         );
467         data[0]
468     }
469 
write_reg(cmos: &mut Cmos, reg: u8, val: u8)470     fn write_reg(cmos: &mut Cmos, reg: u8, val: u8) {
471         // Write register number to INDEX_OFFSET (0).
472         cmos.write(
473             BusAccessInfo {
474                 offset: 0,
475                 address: 0x70,
476                 id: 0,
477             },
478             &[reg],
479         );
480 
481         // Write register value to DATA_OFFSET (1).
482 
483         let data = [val];
484         cmos.write(
485             BusAccessInfo {
486                 offset: 1,
487                 address: 0x71,
488                 id: 0,
489             },
490             &data,
491         );
492     }
493 
timestamp_to_datetime(timestamp: i64) -> DateTime<Utc>494     fn timestamp_to_datetime(timestamp: i64) -> DateTime<Utc> {
495         DateTime::from_timestamp(timestamp, 0).unwrap()
496     }
497 
test_now_party_like_its_1999() -> DateTime<Utc>498     fn test_now_party_like_its_1999() -> DateTime<Utc> {
499         // 1999-12-31T23:59:59+00:00
500         timestamp_to_datetime(946684799)
501     }
502 
test_now_y2k_compliant() -> DateTime<Utc>503     fn test_now_y2k_compliant() -> DateTime<Utc> {
504         // 2000-01-01T00:00:00+00:00
505         timestamp_to_datetime(946684800)
506     }
507 
test_now_2016_before_leap_second() -> DateTime<Utc>508     fn test_now_2016_before_leap_second() -> DateTime<Utc> {
509         // 2016-12-31T23:59:59+00:00
510         timestamp_to_datetime(1483228799)
511     }
512 
test_now_2017_after_leap_second() -> DateTime<Utc>513     fn test_now_2017_after_leap_second() -> DateTime<Utc> {
514         // 2017-01-01T00:00:00+00:00
515         timestamp_to_datetime(1483228800)
516     }
517 
new_cmos_for_test(now_fn: CmosNowFn) -> Cmos518     fn new_cmos_for_test(now_fn: CmosNowFn) -> Cmos {
519         let irq = IrqEdgeEvent::new().unwrap();
520         Cmos::new(1024, 0, now_fn, Tube::pair().unwrap().0, irq).unwrap()
521     }
522 
523     #[test]
cmos_write_index()524     fn cmos_write_index() {
525         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
526         // Write index.
527         cmos.write(
528             BusAccessInfo {
529                 offset: 0,
530                 address: 0x71,
531                 id: 0,
532             },
533             &[0x41],
534         );
535         assert_eq!(cmos.index, 0x41);
536     }
537 
538     #[test]
cmos_write_data()539     fn cmos_write_data() {
540         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
541         // Write data 0x01 at index 0x41.
542         cmos.write(
543             BusAccessInfo {
544                 offset: 0,
545                 address: 0x71,
546                 id: 0,
547             },
548             &[0x41],
549         );
550         cmos.write(
551             BusAccessInfo {
552                 offset: 1,
553                 address: 0x71,
554                 id: 0,
555             },
556             &[0x01],
557         );
558         assert_eq!(cmos.data[0x41], 0x01);
559     }
560 
modify_device(cmos: &mut Cmos)561     fn modify_device(cmos: &mut Cmos) {
562         let info_index = BusAccessInfo {
563             offset: 0,
564             address: 0x71,
565             id: 0,
566         };
567 
568         let info_data = BusAccessInfo {
569             offset: 1,
570             address: 0x71,
571             id: 0,
572         };
573         // change index to 0x42.
574         cmos.write(info_index, &[0x42]);
575         cmos.write(info_data, &[0x01]);
576     }
577 
578     #[test]
cmos_date_time_1999()579     fn cmos_date_time_1999() {
580         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
581         assert_eq!(read_reg(&mut cmos, 0x00), 0x59); // seconds
582         assert_eq!(read_reg(&mut cmos, 0x02), 0x59); // minutes
583         assert_eq!(read_reg(&mut cmos, 0x04), 0x23); // hours
584         assert_eq!(read_reg(&mut cmos, 0x06), 0x06); // day of week
585         assert_eq!(read_reg(&mut cmos, 0x07), 0x31); // day of month
586         assert_eq!(read_reg(&mut cmos, 0x08), 0x12); // month
587         assert_eq!(read_reg(&mut cmos, 0x09), 0x99); // year
588         assert_eq!(read_reg(&mut cmos, 0x32), 0x19); // century
589     }
590 
591     #[test]
cmos_date_time_2000()592     fn cmos_date_time_2000() {
593         let mut cmos = new_cmos_for_test(test_now_y2k_compliant);
594         assert_eq!(read_reg(&mut cmos, 0x00), 0x00); // seconds
595         assert_eq!(read_reg(&mut cmos, 0x02), 0x00); // minutes
596         assert_eq!(read_reg(&mut cmos, 0x04), 0x00); // hours
597         assert_eq!(read_reg(&mut cmos, 0x06), 0x07); // day of week
598         assert_eq!(read_reg(&mut cmos, 0x07), 0x01); // day of month
599         assert_eq!(read_reg(&mut cmos, 0x08), 0x01); // month
600         assert_eq!(read_reg(&mut cmos, 0x09), 0x00); // year
601         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
602     }
603 
604     #[test]
cmos_date_time_before_leap_second()605     fn cmos_date_time_before_leap_second() {
606         let mut cmos = new_cmos_for_test(test_now_2016_before_leap_second);
607         assert_eq!(read_reg(&mut cmos, 0x00), 0x59); // seconds
608         assert_eq!(read_reg(&mut cmos, 0x02), 0x59); // minutes
609         assert_eq!(read_reg(&mut cmos, 0x04), 0x23); // hours
610         assert_eq!(read_reg(&mut cmos, 0x06), 0x07); // day of week
611         assert_eq!(read_reg(&mut cmos, 0x07), 0x31); // day of month
612         assert_eq!(read_reg(&mut cmos, 0x08), 0x12); // month
613         assert_eq!(read_reg(&mut cmos, 0x09), 0x16); // year
614         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
615     }
616 
617     #[test]
cmos_date_time_after_leap_second()618     fn cmos_date_time_after_leap_second() {
619         let mut cmos = new_cmos_for_test(test_now_2017_after_leap_second);
620         assert_eq!(read_reg(&mut cmos, 0x00), 0x00); // seconds
621         assert_eq!(read_reg(&mut cmos, 0x02), 0x00); // minutes
622         assert_eq!(read_reg(&mut cmos, 0x04), 0x00); // hours
623         assert_eq!(read_reg(&mut cmos, 0x06), 0x01); // day of week
624         assert_eq!(read_reg(&mut cmos, 0x07), 0x01); // day of month
625         assert_eq!(read_reg(&mut cmos, 0x08), 0x01); // month
626         assert_eq!(read_reg(&mut cmos, 0x09), 0x17); // year
627         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
628     }
629 
630     #[test]
cmos_alarm()631     fn cmos_alarm() {
632         // 2000-01-02T03:04:05+00:00
633         let now_fn = || timestamp_to_datetime(946782245);
634         let mut cmos = new_cmos_for_test(now_fn);
635 
636         // A date later this year
637         write_reg(&mut cmos, 0x01, 0x06); // seconds
638         write_reg(&mut cmos, 0x03, 0x05); // minutes
639         write_reg(&mut cmos, 0x05, 0x04); // hours
640         write_reg(&mut cmos, 0x33, 0x03); // day of month
641         write_reg(&mut cmos, 0x34, 0x02); // month
642         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
643                                           // 2000-02-03T04:05:06+00:00
644         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(949550706)));
645 
646         // A date (one year - one second) in the future
647         write_reg(&mut cmos, 0x01, 0x04); // seconds
648         write_reg(&mut cmos, 0x03, 0x04); // minutes
649         write_reg(&mut cmos, 0x05, 0x03); // hours
650         write_reg(&mut cmos, 0x33, 0x02); // day of month
651         write_reg(&mut cmos, 0x34, 0x01); // month
652         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
653                                           // 2001-01-02T03:04:04+00:00
654         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(978404644)));
655 
656         // The current time
657         write_reg(&mut cmos, 0x01, 0x05); // seconds
658         write_reg(&mut cmos, 0x03, 0x04); // minutes
659         write_reg(&mut cmos, 0x05, 0x03); // hours
660         write_reg(&mut cmos, 0x33, 0x02); // day of month
661         write_reg(&mut cmos, 0x34, 0x01); // month
662         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
663         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(946782245)));
664         assert_eq!(read_reg(&mut cmos, 0x0c), 0xa0); // RTC_REG_C_IRQF | RTC_REG_C_AF
665         assert_eq!(cmos.alarm_time, None);
666         assert_eq!(read_reg(&mut cmos, 0x0c), 0);
667 
668         // Invalid BCD
669         write_reg(&mut cmos, 0x01, 0xa0); // seconds
670         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
671         assert_eq!(cmos.alarm_time, None);
672     }
673 
674     #[test]
cmos_reg_d()675     fn cmos_reg_d() {
676         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
677         assert_eq!(read_reg(&mut cmos, 0x0d), 0x80) // RAM and time are valid
678     }
679 
680     #[test]
cmos_snapshot_restore() -> anyhow::Result<()>681     fn cmos_snapshot_restore() -> anyhow::Result<()> {
682         // time function doesn't matter in this case.
683         let mut cmos = new_cmos_for_test(test_now_party_like_its_1999);
684 
685         let info_index = BusAccessInfo {
686             offset: 0,
687             address: 0x71,
688             id: 0,
689         };
690 
691         let info_data = BusAccessInfo {
692             offset: 1,
693             address: 0x71,
694             id: 0,
695         };
696 
697         // change index to 0x41.
698         cmos.write(info_index, &[0x41]);
699         cmos.write(info_data, &[0x01]);
700 
701         let snap = cmos.snapshot().context("failed to snapshot Cmos")?;
702 
703         // change index to 0x42.
704         cmos.write(info_index, &[0x42]);
705         cmos.write(info_data, &[0x01]);
706 
707         // Restore Cmos.
708         cmos.restore(snap).context("failed to restore Cmos")?;
709 
710         // after restore, the index should be 0x41, which was the index before snapshot was taken.
711         assert_eq!(cmos.index, 0x41);
712         assert_eq!(cmos.data[0x41], 0x01);
713         assert_ne!(cmos.data[0x42], 0x01);
714         Ok(())
715     }
716 
717     #[test]
cmos_sleep_wake()718     fn cmos_sleep_wake() {
719         // 2000-01-02T03:04:05+00:00
720         let irq = IrqEdgeEvent::new().unwrap();
721         let now_fn = || timestamp_to_datetime(946782245);
722         let mut cmos = Cmos::new(1024, 0, now_fn, Tube::pair().unwrap().0, irq).unwrap();
723 
724         // A date later this year
725         write_reg(&mut cmos, 0x01, 0x06); // seconds
726         write_reg(&mut cmos, 0x03, 0x05); // minutes
727         write_reg(&mut cmos, 0x05, 0x04); // hours
728         write_reg(&mut cmos, 0x33, 0x03); // day of month
729         write_reg(&mut cmos, 0x34, 0x02); // month
730         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
731                                           // 2000-02-03T04:05:06+00:00
732         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(949550706)));
733         assert!(cmos.worker.is_some());
734 
735         cmos.sleep().unwrap();
736         assert!(cmos.worker.is_none());
737 
738         cmos.wake().unwrap();
739         assert!(cmos.worker.is_some());
740     }
741 
742     suspendable_tests!(
743         cmos1999,
744         new_cmos_for_test(test_now_party_like_its_1999),
745         modify_device
746     );
747     suspendable_tests!(
748         cmos2k,
749         new_cmos_for_test(test_now_y2k_compliant),
750         modify_device
751     );
752     suspendable_tests!(
753         cmos2016,
754         new_cmos_for_test(test_now_2016_before_leap_second),
755         modify_device
756     );
757     suspendable_tests!(
758         cmos2017,
759         new_cmos_for_test(test_now_2017_after_leap_second),
760         modify_device
761     );
762 }
763