• 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 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 /// A CMOS/RTC device commonly seen on x86 I/O port 0x70/0x71.
78 #[derive(Serialize)]
79 pub struct Cmos {
80     index: u8,
81     #[serde(serialize_with = "serialize_arr")]
82     data: [u8; DATA_LEN],
83     #[serde(skip_serializing)] // skip serializing time function.
84     now_fn: CmosNowFn,
85     #[serde(skip_serializing)] // skip serializing the timer
86     alarm: Arc<Mutex<Timer>>,
87     alarm_time: Option<DateTime<Utc>>,
88     #[serde(skip_serializing)] // skip serializing the alarm function
89     alarm_fn: Option<AlarmFn>,
90     #[serde(skip_serializing)] // skip serializing the worker thread
91     worker: Option<WorkerThread<AlarmFn>>,
92     #[serde(skip_serializing)] // skip serializing the armed time
93     armed_time: Option<Arc<Mutex<Instant>>>,
94 }
95 
96 struct AlarmFn {
97     irq: IrqEdgeEvent,
98     vm_control: Tube,
99     armed_time: Arc<Mutex<Instant>>,
100 }
101 
102 impl AlarmFn {
new(irq: IrqEdgeEvent, vm_control: Tube) -> Self103     fn new(irq: IrqEdgeEvent, vm_control: Tube) -> Self {
104         Self {
105             irq,
106             vm_control,
107             // Not actually armed, but simpler than wrapping with an Option.
108             armed_time: Arc::new(Mutex::new(Instant::now())),
109         }
110     }
111 
fire(&self) -> anyhow::Result<()>112     fn fire(&self) -> anyhow::Result<()> {
113         self.irq.trigger().context("failed to trigger irq")?;
114 
115         let elapsed = self.armed_time.lock().elapsed().as_millis();
116         log_metric(
117             MetricEventType::RtcWakeup,
118             elapsed.try_into().unwrap_or(i64::MAX),
119         );
120 
121         // The Linux kernel expects wakeups to come via ACPI when ACPI is enabled. There's
122         // no real way to determine that here, so just send this unconditionally.
123         self.vm_control
124             .send(&vm_control::VmRequest::Rtc)
125             .context("send failed")?;
126         match self.vm_control.recv().context("recv failed")? {
127             VmResponse::Ok => Ok(()),
128             resp => Err(anyhow!("unexpected rtc response: {:?}", resp)),
129         }
130     }
131 }
132 
133 impl Cmos {
134     /// Constructs a CMOS/RTC device with initial data.
135     /// `mem_below_4g` is the size of memory in bytes below the 32-bit gap.
136     /// `mem_above_4g` is the size of memory in bytes above the 32-bit gap.
137     /// `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>138     pub fn new(
139         mem_below_4g: u64,
140         mem_above_4g: u64,
141         now_fn: CmosNowFn,
142         vm_control: Tube,
143         irq: IrqEdgeEvent,
144     ) -> anyhow::Result<Cmos> {
145         Self::new_inner(
146             mem_below_4g,
147             mem_above_4g,
148             now_fn,
149             Some(AlarmFn::new(irq, vm_control)),
150         )
151     }
152 
new_inner( mem_below_4g: u64, mem_above_4g: u64, now_fn: CmosNowFn, alarm_fn: Option<AlarmFn>, ) -> anyhow::Result<Cmos>153     fn new_inner(
154         mem_below_4g: u64,
155         mem_above_4g: u64,
156         now_fn: CmosNowFn,
157         alarm_fn: Option<AlarmFn>,
158     ) -> anyhow::Result<Cmos> {
159         let mut data = [0u8; DATA_LEN];
160 
161         data[0x0B] = RTC_REG_B_24_HOUR_MODE; // Status Register B: 24-hour mode
162 
163         // Extended memory from 16 MB to 4 GB in units of 64 KB
164         let ext_mem = min(
165             0xFFFF,
166             mem_below_4g.saturating_sub(16 * 1024 * 1024) / (64 * 1024),
167         );
168         data[0x34] = ext_mem as u8;
169         data[0x35] = (ext_mem >> 8) as u8;
170 
171         // High memory (> 4GB) in units of 64 KB
172         let high_mem = min(0xFFFFFF, mem_above_4g / (64 * 1024));
173         data[0x5b] = high_mem as u8;
174         data[0x5c] = (high_mem >> 8) as u8;
175         data[0x5d] = (high_mem >> 16) as u8;
176 
177         let armed_time = alarm_fn.as_ref().map(|a| a.armed_time.clone());
178         Ok(Cmos {
179             index: 0,
180             data,
181             now_fn,
182             alarm: Arc::new(Mutex::new(Timer::new().context("cmos timer")?)),
183             alarm_time: None,
184             alarm_fn,
185             worker: None,
186             armed_time,
187         })
188     }
189 
spawn_worker(&mut self)190     fn spawn_worker(&mut self) {
191         let alarm = self.alarm.clone();
192         let alarm_fn = self.alarm_fn.take().expect("no alarm function");
193         self.worker = Some(WorkerThread::start("CMOS_alarm", move |kill_evt| {
194             if let Err(e) = run_cmos_worker(alarm, kill_evt, &alarm_fn) {
195                 error!("Failed to spawn worker {:?}", e);
196             }
197             alarm_fn
198         }));
199     }
200 
set_alarm(&mut self)201     fn set_alarm(&mut self) {
202         if self.data[RTC_REG_B as usize] & RTC_REG_B_ALARM_ENABLE != 0 {
203             let now = (self.now_fn)();
204             let target = alarm_from_registers(now.year(), &self.data).and_then(|this_year| {
205                 // There is no year register for the alarm. If the alarm target has
206                 // already passed this year, then the next time it will occur is next
207                 // year.
208                 //
209                 // Note that there is something of a race condition here. If |now|
210                 // advances while the driver is configuring the alarm, then an alarm that
211                 // should only be one second in the future could become one year in the
212                 // future. Unfortunately there isn't anything in the rtc-cmos hardware
213                 // specification that lets us handle this race condition in the device, so
214                 // we just have to rely on the driver to deal with it.
215                 if this_year < now {
216                     alarm_from_registers(now.year() + 1, &self.data)
217                 } else {
218                     Some(this_year)
219                 }
220             });
221             if let Some(target) = target {
222                 if Some(target) != self.alarm_time {
223                     self.alarm_time = Some(target);
224 
225                     if self.alarm_fn.is_some() {
226                         self.spawn_worker();
227                     }
228                     if let Some(armed_time) = self.armed_time.as_ref() {
229                         *armed_time.lock() = Instant::now();
230                     }
231 
232                     let duration = target
233                         .signed_duration_since(now)
234                         .to_std()
235                         .unwrap_or(Duration::new(0, 0));
236                     if let Err(e) = self.alarm.lock().reset(duration, None) {
237                         error!("Failed to set alarm {:?}", e);
238                     }
239                 }
240             }
241         } else if self.alarm_time.take().is_some() {
242             if let Err(e) = self.alarm.lock().clear() {
243                 error!("Failed to clear alarm {:?}", e);
244             }
245         }
246     }
247 }
248 
run_cmos_worker( alarm: Arc<Mutex<Timer>>, kill_evt: Event, alarm_fn: &AlarmFn, ) -> anyhow::Result<()>249 fn run_cmos_worker(
250     alarm: Arc<Mutex<Timer>>,
251     kill_evt: Event,
252     alarm_fn: &AlarmFn,
253 ) -> anyhow::Result<()> {
254     #[derive(EventToken)]
255     enum Token {
256         Alarm,
257         Kill,
258     }
259 
260     let wait_ctx: WaitContext<Token> =
261         WaitContext::build_with(&[(&*alarm.lock(), Token::Alarm), (&kill_evt, Token::Kill)])
262             .context("worker context failed")?;
263 
264     loop {
265         let events = wait_ctx.wait().context("wait failed")?;
266         for event in events.iter().filter(|e| e.is_readable) {
267             match event.token {
268                 Token::Alarm => {
269                     if alarm.lock().mark_waited().context("timer ack failed")? {
270                         continue;
271                     }
272                     alarm_fn.fire()?;
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
383                             .alarm_time
384                             .map_or(false, |alarm_time| alarm_time <= now)
385                         {
386                             // Reading from RTC_REG_C resets interrupts, so clear the
387                             // status bits. The IrqEdgeEvent is reset automatically.
388                             self.alarm_time.take();
389                             RTC_REG_C_IRQF | RTC_REG_C_AF
390                         } else {
391                             0
392                         }
393                     }
394                     RTC_REG_D => RTC_REG_D_VRT,
395                     _ => {
396                         // self.index is always guaranteed to be in range via INDEX_MASK.
397                         self.data[(self.index & INDEX_MASK) as usize]
398                     }
399                 }
400             }
401             o => panic!("bad read offset on CMOS device: {}", o),
402         }
403     }
404 }
405 
406 impl Suspendable for Cmos {
snapshot(&mut self) -> anyhow::Result<serde_json::Value>407     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
408         serde_json::to_value(self).context("failed to serialize Cmos")
409     }
410 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>411     fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
412         #[derive(Deserialize)]
413         struct CmosIndex {
414             index: u8,
415             #[serde(deserialize_with = "deserialize_seq_to_arr")]
416             data: [u8; DATA_LEN],
417         }
418 
419         let deser: CmosIndex =
420             serde_json::from_value(data).context("failed to deserialize Cmos")?;
421         self.index = deser.index;
422         self.data = deser.data;
423         self.set_alarm();
424 
425         Ok(())
426     }
427 
sleep(&mut self) -> anyhow::Result<()>428     fn sleep(&mut self) -> anyhow::Result<()> {
429         if let Some(worker) = self.worker.take() {
430             self.alarm_fn = Some(worker.stop());
431         }
432         Ok(())
433     }
434 
wake(&mut self) -> anyhow::Result<()>435     fn wake(&mut self) -> anyhow::Result<()> {
436         if self.alarm_time.is_some() {
437             self.spawn_worker();
438         }
439         Ok(())
440     }
441 }
442 
443 #[cfg(test)]
444 mod tests {
445     use super::*;
446     use crate::suspendable_tests;
447 
read_reg(cmos: &mut Cmos, reg: u8) -> u8448     fn read_reg(cmos: &mut Cmos, reg: u8) -> u8 {
449         // Write register number to INDEX_OFFSET (0).
450         cmos.write(
451             BusAccessInfo {
452                 offset: 0,
453                 address: 0x70,
454                 id: 0,
455             },
456             &[reg],
457         );
458 
459         // Read register value back from DATA_OFFSET (1).
460 
461         let mut data = [0u8];
462         cmos.read(
463             BusAccessInfo {
464                 offset: 1,
465                 address: 0x71,
466                 id: 0,
467             },
468             &mut data,
469         );
470         data[0]
471     }
472 
write_reg(cmos: &mut Cmos, reg: u8, val: u8)473     fn write_reg(cmos: &mut Cmos, reg: u8, val: u8) {
474         // Write register number to INDEX_OFFSET (0).
475         cmos.write(
476             BusAccessInfo {
477                 offset: 0,
478                 address: 0x70,
479                 id: 0,
480             },
481             &[reg],
482         );
483 
484         // Write register value to DATA_OFFSET (1).
485 
486         let data = [val];
487         cmos.write(
488             BusAccessInfo {
489                 offset: 1,
490                 address: 0x71,
491                 id: 0,
492             },
493             &data,
494         );
495     }
496 
timestamp_to_datetime(timestamp: i64) -> DateTime<Utc>497     fn timestamp_to_datetime(timestamp: i64) -> DateTime<Utc> {
498         DateTime::from_timestamp(timestamp, 0).unwrap()
499     }
500 
test_now_party_like_its_1999() -> DateTime<Utc>501     fn test_now_party_like_its_1999() -> DateTime<Utc> {
502         // 1999-12-31T23:59:59+00:00
503         timestamp_to_datetime(946684799)
504     }
505 
test_now_y2k_compliant() -> DateTime<Utc>506     fn test_now_y2k_compliant() -> DateTime<Utc> {
507         // 2000-01-01T00:00:00+00:00
508         timestamp_to_datetime(946684800)
509     }
510 
test_now_2016_before_leap_second() -> DateTime<Utc>511     fn test_now_2016_before_leap_second() -> DateTime<Utc> {
512         // 2016-12-31T23:59:59+00:00
513         timestamp_to_datetime(1483228799)
514     }
515 
test_now_2017_after_leap_second() -> DateTime<Utc>516     fn test_now_2017_after_leap_second() -> DateTime<Utc> {
517         // 2017-01-01T00:00:00+00:00
518         timestamp_to_datetime(1483228800)
519     }
520 
521     #[test]
cmos_write_index()522     fn cmos_write_index() {
523         let mut cmos = Cmos::new_inner(1024, 0, test_now_party_like_its_1999, None).unwrap();
524         // Write index.
525         cmos.write(
526             BusAccessInfo {
527                 offset: 0,
528                 address: 0x71,
529                 id: 0,
530             },
531             &[0x41],
532         );
533         assert_eq!(cmos.index, 0x41);
534     }
535 
536     #[test]
cmos_write_data()537     fn cmos_write_data() {
538         let mut cmos = Cmos::new_inner(1024, 0, test_now_party_like_its_1999, None).unwrap();
539         // Write data 0x01 at index 0x41.
540         cmos.write(
541             BusAccessInfo {
542                 offset: 0,
543                 address: 0x71,
544                 id: 0,
545             },
546             &[0x41],
547         );
548         cmos.write(
549             BusAccessInfo {
550                 offset: 1,
551                 address: 0x71,
552                 id: 0,
553             },
554             &[0x01],
555         );
556         assert_eq!(cmos.data[0x41], 0x01);
557     }
558 
modify_device(cmos: &mut Cmos)559     fn modify_device(cmos: &mut Cmos) {
560         let info_index = BusAccessInfo {
561             offset: 0,
562             address: 0x71,
563             id: 0,
564         };
565 
566         let info_data = BusAccessInfo {
567             offset: 1,
568             address: 0x71,
569             id: 0,
570         };
571         // change index to 0x42.
572         cmos.write(info_index, &[0x42]);
573         cmos.write(info_data, &[0x01]);
574     }
575 
576     #[test]
cmos_date_time_1999()577     fn cmos_date_time_1999() {
578         let mut cmos = Cmos::new_inner(1024, 0, test_now_party_like_its_1999, None).unwrap();
579         assert_eq!(read_reg(&mut cmos, 0x00), 0x59); // seconds
580         assert_eq!(read_reg(&mut cmos, 0x02), 0x59); // minutes
581         assert_eq!(read_reg(&mut cmos, 0x04), 0x23); // hours
582         assert_eq!(read_reg(&mut cmos, 0x06), 0x06); // day of week
583         assert_eq!(read_reg(&mut cmos, 0x07), 0x31); // day of month
584         assert_eq!(read_reg(&mut cmos, 0x08), 0x12); // month
585         assert_eq!(read_reg(&mut cmos, 0x09), 0x99); // year
586         assert_eq!(read_reg(&mut cmos, 0x32), 0x19); // century
587     }
588 
589     #[test]
cmos_date_time_2000()590     fn cmos_date_time_2000() {
591         let mut cmos = Cmos::new_inner(1024, 0, test_now_y2k_compliant, None).unwrap();
592         assert_eq!(read_reg(&mut cmos, 0x00), 0x00); // seconds
593         assert_eq!(read_reg(&mut cmos, 0x02), 0x00); // minutes
594         assert_eq!(read_reg(&mut cmos, 0x04), 0x00); // hours
595         assert_eq!(read_reg(&mut cmos, 0x06), 0x07); // day of week
596         assert_eq!(read_reg(&mut cmos, 0x07), 0x01); // day of month
597         assert_eq!(read_reg(&mut cmos, 0x08), 0x01); // month
598         assert_eq!(read_reg(&mut cmos, 0x09), 0x00); // year
599         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
600     }
601 
602     #[test]
cmos_date_time_before_leap_second()603     fn cmos_date_time_before_leap_second() {
604         let mut cmos = Cmos::new_inner(1024, 0, test_now_2016_before_leap_second, None).unwrap();
605         assert_eq!(read_reg(&mut cmos, 0x00), 0x59); // seconds
606         assert_eq!(read_reg(&mut cmos, 0x02), 0x59); // minutes
607         assert_eq!(read_reg(&mut cmos, 0x04), 0x23); // hours
608         assert_eq!(read_reg(&mut cmos, 0x06), 0x07); // day of week
609         assert_eq!(read_reg(&mut cmos, 0x07), 0x31); // day of month
610         assert_eq!(read_reg(&mut cmos, 0x08), 0x12); // month
611         assert_eq!(read_reg(&mut cmos, 0x09), 0x16); // year
612         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
613     }
614 
615     #[test]
cmos_date_time_after_leap_second()616     fn cmos_date_time_after_leap_second() {
617         let mut cmos = Cmos::new_inner(1024, 0, test_now_2017_after_leap_second, None).unwrap();
618         assert_eq!(read_reg(&mut cmos, 0x00), 0x00); // seconds
619         assert_eq!(read_reg(&mut cmos, 0x02), 0x00); // minutes
620         assert_eq!(read_reg(&mut cmos, 0x04), 0x00); // hours
621         assert_eq!(read_reg(&mut cmos, 0x06), 0x01); // day of week
622         assert_eq!(read_reg(&mut cmos, 0x07), 0x01); // day of month
623         assert_eq!(read_reg(&mut cmos, 0x08), 0x01); // month
624         assert_eq!(read_reg(&mut cmos, 0x09), 0x17); // year
625         assert_eq!(read_reg(&mut cmos, 0x32), 0x20); // century
626     }
627 
628     #[test]
cmos_alarm()629     fn cmos_alarm() {
630         // 2000-01-02T03:04:05+00:00
631         let now_fn = || timestamp_to_datetime(946782245);
632         let mut cmos = Cmos::new_inner(1024, 0, now_fn, None).unwrap();
633 
634         // A date later this year
635         write_reg(&mut cmos, 0x01, 0x06); // seconds
636         write_reg(&mut cmos, 0x03, 0x05); // minutes
637         write_reg(&mut cmos, 0x05, 0x04); // hours
638         write_reg(&mut cmos, 0x33, 0x03); // day of month
639         write_reg(&mut cmos, 0x34, 0x02); // month
640         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
641                                           // 2000-02-03T04:05:06+00:00
642         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(949550706)));
643 
644         // A date (one year - one second) in the future
645         write_reg(&mut cmos, 0x01, 0x04); // seconds
646         write_reg(&mut cmos, 0x03, 0x04); // minutes
647         write_reg(&mut cmos, 0x05, 0x03); // hours
648         write_reg(&mut cmos, 0x33, 0x02); // day of month
649         write_reg(&mut cmos, 0x34, 0x01); // month
650         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
651                                           // 2001-01-02T03:04:04+00:00
652         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(978404644)));
653 
654         // The current time
655         write_reg(&mut cmos, 0x01, 0x05); // seconds
656         write_reg(&mut cmos, 0x03, 0x04); // minutes
657         write_reg(&mut cmos, 0x05, 0x03); // hours
658         write_reg(&mut cmos, 0x33, 0x02); // day of month
659         write_reg(&mut cmos, 0x34, 0x01); // month
660         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
661         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(946782245)));
662         assert_eq!(read_reg(&mut cmos, 0x0c), 0xa0); // RTC_REG_C_IRQF | RTC_REG_C_AF
663         assert_eq!(cmos.alarm_time, None);
664         assert_eq!(read_reg(&mut cmos, 0x0c), 0);
665 
666         // Invalid BCD
667         write_reg(&mut cmos, 0x01, 0xa0); // seconds
668         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
669         assert_eq!(cmos.alarm_time, None);
670     }
671 
672     #[test]
cmos_reg_d()673     fn cmos_reg_d() {
674         let mut cmos = Cmos::new_inner(1024, 0, test_now_party_like_its_1999, None).unwrap();
675         assert_eq!(read_reg(&mut cmos, 0x0d), 0x80) // RAM and time are valid
676     }
677 
678     #[test]
cmos_snapshot_restore() -> anyhow::Result<()>679     fn cmos_snapshot_restore() -> anyhow::Result<()> {
680         // time function doesn't matter in this case.
681         let mut cmos = Cmos::new_inner(1024, 0, test_now_party_like_its_1999, None).unwrap();
682 
683         let info_index = BusAccessInfo {
684             offset: 0,
685             address: 0x71,
686             id: 0,
687         };
688 
689         let info_data = BusAccessInfo {
690             offset: 1,
691             address: 0x71,
692             id: 0,
693         };
694 
695         // change index to 0x41.
696         cmos.write(info_index, &[0x41]);
697         cmos.write(info_data, &[0x01]);
698 
699         let snap = cmos.snapshot().context("failed to snapshot Cmos")?;
700 
701         // change index to 0x42.
702         cmos.write(info_index, &[0x42]);
703         cmos.write(info_data, &[0x01]);
704 
705         // Restore Cmos.
706         cmos.restore(snap).context("failed to restore Cmos")?;
707 
708         // after restore, the index should be 0x41, which was the index before snapshot was taken.
709         assert_eq!(cmos.index, 0x41);
710         assert_eq!(cmos.data[0x41], 0x01);
711         assert_ne!(cmos.data[0x42], 0x01);
712         Ok(())
713     }
714 
715     #[test]
cmos_sleep_wake()716     fn cmos_sleep_wake() {
717         // 2000-01-02T03:04:05+00:00
718         let now_fn = || timestamp_to_datetime(946782245);
719         let alarm_fn = AlarmFn::new(IrqEdgeEvent::new().unwrap(), Tube::pair().unwrap().0);
720         let mut cmos = Cmos::new_inner(1024, 0, now_fn, Some(alarm_fn)).unwrap();
721 
722         // A date later this year
723         write_reg(&mut cmos, 0x01, 0x06); // seconds
724         write_reg(&mut cmos, 0x03, 0x05); // minutes
725         write_reg(&mut cmos, 0x05, 0x04); // hours
726         write_reg(&mut cmos, 0x33, 0x03); // day of month
727         write_reg(&mut cmos, 0x34, 0x02); // month
728         write_reg(&mut cmos, 0x0b, 0x20); // RTC_REG_B_ALARM_ENABLE
729                                           // 2000-02-03T04:05:06+00:00
730         assert_eq!(cmos.alarm_time, Some(timestamp_to_datetime(949550706)));
731         assert!(cmos.worker.is_some());
732 
733         cmos.sleep().unwrap();
734         assert!(cmos.worker.is_none());
735 
736         cmos.wake().unwrap();
737         assert!(cmos.worker.is_some());
738     }
739 
740     suspendable_tests!(
741         cmos1999,
742         Cmos::new_inner(1024, 0, test_now_party_like_its_1999, None).unwrap(),
743         modify_device
744     );
745     suspendable_tests!(
746         cmos2k,
747         Cmos::new_inner(1024, 0, test_now_y2k_compliant, None).unwrap(),
748         modify_device
749     );
750     suspendable_tests!(
751         cmos2016,
752         Cmos::new_inner(1024, 0, test_now_2016_before_leap_second, None).unwrap(),
753         modify_device
754     );
755     suspendable_tests!(
756         cmos2017,
757         Cmos::new_inner(1024, 0, test_now_2017_after_leap_second, None).unwrap(),
758         modify_device
759     );
760 }
761