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