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