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