xref: /cloud-hypervisor/devices/src/legacy/rtc_pl031.rs (revision 08cf983d420af7bce0cd67f34e660324ef219de6)
1 // Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
2 // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 //! ARM PL031 Real Time Clock
6 //!
7 //! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
8 //! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
9 //! a real-time clock input.
10 //!
11 use crate::{read_le_u32, write_le_u32};
12 use std::sync::{Arc, Barrier};
13 use std::time::Instant;
14 use std::{io, result};
15 use thiserror::Error;
16 use vm_device::interrupt::InterruptSourceGroup;
17 use vm_device::BusDevice;
18 
19 // As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf
20 // at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000.
21 // From 0x0 to 0x1C we have following registers:
22 const RTCDR: u64 = 0x0; // Data Register.
23 const RTCMR: u64 = 0x4; // Match Register.
24 const RTCLR: u64 = 0x8; // Load Register.
25 const RTCCR: u64 = 0xc; // Control Register.
26 const RTCIMSC: u64 = 0x10; // Interrupt Mask Set or Clear Register.
27 const RTCRIS: u64 = 0x14; // Raw Interrupt Status.
28 const RTCMIS: u64 = 0x18; // Masked Interrupt Status.
29 const RTCICR: u64 = 0x1c; // Interrupt Clear Register.
30                           // From 0x020 to 0xFDC => reserved space.
31                           // From 0xFE0 to 0x1000 => Peripheral and PrimeCell Identification Registers which are Read Only registers.
32                           // AMBA standard devices have CIDs (Cell IDs) and PIDs (Peripheral IDs). The linux kernel will look for these in order to assert the identity
33                           // of these devices (i.e look at the `amba_device_try_add` function).
34                           // We are putting the expected values (look at 'Reset value' column from above mentioned document) in an array.
35 const PL031_ID: [u8; 8] = [0x31, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
36 // We are only interested in the margins.
37 const AMBA_ID_LOW: u64 = 0xFE0;
38 const AMBA_ID_HIGH: u64 = 0x1000;
39 /// Constant to convert seconds to nanoseconds.
40 pub const NANOS_PER_SECOND: u64 = 1_000_000_000;
41 
42 #[derive(Debug, Error)]
43 pub enum Error {
44     #[error("Bad Write Offset: {0}")]
45     BadWriteOffset(u64),
46     #[error("Failed to trigger interrupt: {0}")]
47     InterruptFailure(io::Error),
48 }
49 
50 type Result<T> = result::Result<T, Error>;
51 
52 /// Wrapper over `libc::clockid_t` to specify Linux Kernel clock source.
53 pub enum ClockType {
54     /// Equivalent to `libc::CLOCK_MONOTONIC`.
55     Monotonic,
56     /// Equivalent to `libc::CLOCK_REALTIME`.
57     Real,
58     /// Equivalent to `libc::CLOCK_PROCESS_CPUTIME_ID`.
59     ProcessCpu,
60     /// Equivalent to `libc::CLOCK_THREAD_CPUTIME_ID`.
61     ThreadCpu,
62 }
63 
64 impl From<ClockType> for libc::clockid_t {
65     fn from(ct: ClockType) -> libc::clockid_t {
66         match ct {
67             ClockType::Monotonic => libc::CLOCK_MONOTONIC,
68             ClockType::Real => libc::CLOCK_REALTIME,
69             ClockType::ProcessCpu => libc::CLOCK_PROCESS_CPUTIME_ID,
70             ClockType::ThreadCpu => libc::CLOCK_THREAD_CPUTIME_ID,
71         }
72     }
73 }
74 
75 /// Returns a timestamp in nanoseconds based on the provided clock type.
76 ///
77 /// # Arguments
78 ///
79 /// * `clock_type` - Identifier of the Linux Kernel clock on which to act.
80 pub fn get_time(clock_type: ClockType) -> u64 {
81     let mut time_struct = libc::timespec {
82         tv_sec: 0,
83         tv_nsec: 0,
84     };
85     // SAFETY: the parameters are valid.
86     unsafe { libc::clock_gettime(clock_type.into(), &mut time_struct) };
87     seconds_to_nanoseconds(time_struct.tv_sec).unwrap() as u64 + (time_struct.tv_nsec as u64)
88 }
89 
90 /// Converts a timestamp in seconds to an equivalent one in nanoseconds.
91 /// Returns `None` if the conversion overflows.
92 ///
93 /// # Arguments
94 ///
95 /// * `value` - Timestamp in seconds.
96 pub fn seconds_to_nanoseconds(value: i64) -> Option<i64> {
97     value.checked_mul(NANOS_PER_SECOND as i64)
98 }
99 
100 /// A RTC device following the PL031 specification..
101 pub struct Rtc {
102     previous_now: Instant,
103     tick_offset: i64,
104     // This is used for implementing the RTC alarm. However, in Firecracker we do not need it.
105     match_value: u32,
106     // Writes to this register load an update value into the RTC.
107     load: u32,
108     imsc: u32,
109     ris: u32,
110     interrupt: Arc<dyn InterruptSourceGroup>,
111 }
112 
113 impl Rtc {
114     /// Constructs an AMBA PL031 RTC device.
115     pub fn new(interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
116         Self {
117             // This is used only for duration measuring purposes.
118             previous_now: Instant::now(),
119             tick_offset: get_time(ClockType::Real) as i64,
120             match_value: 0,
121             load: 0,
122             imsc: 0,
123             ris: 0,
124             interrupt,
125         }
126     }
127 
128     fn trigger_interrupt(&mut self) -> Result<()> {
129         self.interrupt.trigger(0).map_err(Error::InterruptFailure)?;
130         Ok(())
131     }
132 
133     fn get_time(&self) -> u32 {
134         let ts = (self.tick_offset as i128)
135             + (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
136         (ts / NANOS_PER_SECOND as i128) as u32
137     }
138 
139     fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
140         match offset {
141             RTCMR => {
142                 // The MR register is used for implementing the RTC alarm. A real time clock alarm is
143                 // a feature that can be used to allow a computer to 'wake up' after shut down to execute
144                 // tasks every day or on a certain day. It can sometimes be found in the 'Power Management'
145                 // section of a motherboard's BIOS setup. This is functionality that extends beyond
146                 // Firecracker intended use. However, we increment a metric just in case.
147                 self.match_value = val;
148             }
149             RTCLR => {
150                 self.load = val;
151                 self.previous_now = Instant::now();
152                 // If the unwrap fails, then the internal value of the clock has been corrupted and
153                 // we want to terminate the execution of the process.
154                 self.tick_offset = seconds_to_nanoseconds(i64::from(val)).unwrap();
155             }
156             RTCIMSC => {
157                 self.imsc = val & 1;
158                 self.trigger_interrupt()?;
159             }
160             RTCICR => {
161                 // As per above mentioned doc, the interrupt is cleared by writing any data value to
162                 // the Interrupt Clear Register.
163                 self.ris = 0;
164                 self.trigger_interrupt()?;
165             }
166             RTCCR => (), // ignore attempts to turn off the timer.
167             o => {
168                 return Err(Error::BadWriteOffset(o));
169             }
170         }
171         Ok(())
172     }
173 }
174 
175 impl BusDevice for Rtc {
176     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
177         let mut read_ok = true;
178 
179         let v = if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&offset) {
180             let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
181             u32::from(PL031_ID[index])
182         } else {
183             match offset {
184                 RTCDR => self.get_time(),
185                 RTCMR => {
186                     // Even though we are not implementing RTC alarm we return the last value
187                     self.match_value
188                 }
189                 RTCLR => self.load,
190                 RTCCR => 1, // RTC is always enabled.
191                 RTCIMSC => self.imsc,
192                 RTCRIS => self.ris,
193                 RTCMIS => self.ris & self.imsc,
194                 _ => {
195                     read_ok = false;
196                     0
197                 }
198             }
199         };
200         if read_ok && data.len() <= 4 {
201             write_le_u32(data, v);
202         } else {
203             warn!(
204                 "Invalid RTC PL031 read: offset {}, data length {}",
205                 offset,
206                 data.len()
207             );
208         }
209     }
210 
211     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
212         if data.len() <= 4 {
213             let v = read_le_u32(data);
214             if let Err(e) = self.handle_write(offset, v) {
215                 warn!("Failed to write to RTC PL031 device: {}", e);
216             }
217         } else {
218             warn!(
219                 "Invalid RTC PL031 write: offset {}, data length {}",
220                 offset,
221                 data.len()
222             );
223         }
224 
225         None
226     }
227 }
228 
229 #[cfg(test)]
230 mod tests {
231     use super::*;
232     use crate::{
233         read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u64, write_be_u16,
234         write_be_u32, write_le_i32, write_le_u16, write_le_u64,
235     };
236     use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
237     use vmm_sys_util::eventfd::EventFd;
238 
239     const LEGACY_RTC_MAPPED_IO_START: u64 = 0x0901_0000;
240 
241     struct LocalTime {
242         sec: i32,
243         min: i32,
244         hour: i32,
245         mday: i32,
246         mon: i32,
247         year: i32,
248         nsec: i64,
249     }
250 
251     impl LocalTime {
252         fn now() -> LocalTime {
253             let mut timespec = libc::timespec {
254                 tv_sec: 0,
255                 tv_nsec: 0,
256             };
257             let mut tm: libc::tm = libc::tm {
258                 tm_sec: 0,
259                 tm_min: 0,
260                 tm_hour: 0,
261                 tm_mday: 0,
262                 tm_mon: 0,
263                 tm_year: 0,
264                 tm_wday: 0,
265                 tm_yday: 0,
266                 tm_isdst: 0,
267                 tm_gmtoff: 0,
268                 tm_zone: std::ptr::null(),
269             };
270 
271             // SAFETY: the parameters are valid.
272             unsafe {
273                 libc::clock_gettime(libc::CLOCK_REALTIME, &mut timespec);
274                 libc::localtime_r(&timespec.tv_sec, &mut tm);
275             }
276 
277             LocalTime {
278                 sec: tm.tm_sec,
279                 min: tm.tm_min,
280                 hour: tm.tm_hour,
281                 mday: tm.tm_mday,
282                 mon: tm.tm_mon,
283                 year: tm.tm_year,
284                 nsec: timespec.tv_nsec,
285             }
286         }
287     }
288 
289     impl std::fmt::Display for LocalTime {
290         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
291             write!(
292                 f,
293                 "{}-{:02}-{:02}T{:02}:{:02}:{:02}.{:09}",
294                 self.year + 1900,
295                 self.mon + 1,
296                 self.mday,
297                 self.hour,
298                 self.min,
299                 self.sec,
300                 self.nsec
301             )
302         }
303     }
304 
305     #[test]
306     fn test_get_time() {
307         for _ in 0..1000 {
308             assert!(get_time(ClockType::Monotonic) <= get_time(ClockType::Monotonic));
309         }
310 
311         for _ in 0..1000 {
312             assert!(get_time(ClockType::ProcessCpu) <= get_time(ClockType::ProcessCpu));
313         }
314 
315         for _ in 0..1000 {
316             assert!(get_time(ClockType::ThreadCpu) <= get_time(ClockType::ThreadCpu));
317         }
318 
319         assert_ne!(get_time(ClockType::Real), 0);
320     }
321 
322     #[test]
323     fn test_local_time_display() {
324         let local_time = LocalTime {
325             sec: 30,
326             min: 15,
327             hour: 10,
328             mday: 4,
329             mon: 6,
330             year: 119,
331             nsec: 123_456_789,
332         };
333         assert_eq!(
334             String::from("2019-07-04T10:15:30.123456789"),
335             local_time.to_string()
336         );
337 
338         let local_time = LocalTime {
339             sec: 5,
340             min: 5,
341             hour: 5,
342             mday: 23,
343             mon: 7,
344             year: 44,
345             nsec: 123,
346         };
347         assert_eq!(
348             String::from("1944-08-23T05:05:05.000000123"),
349             local_time.to_string()
350         );
351 
352         let local_time = LocalTime::now();
353         assert!(local_time.mon >= 0 && local_time.mon <= 11);
354     }
355 
356     #[test]
357     fn test_seconds_to_nanoseconds() {
358         assert_eq!(
359             seconds_to_nanoseconds(100).unwrap() as u64,
360             100 * NANOS_PER_SECOND
361         );
362 
363         assert!(seconds_to_nanoseconds(9_223_372_037).is_none());
364     }
365 
366     struct TestInterrupt {
367         event_fd: EventFd,
368     }
369 
370     impl InterruptSourceGroup for TestInterrupt {
371         fn trigger(&self, _index: InterruptIndex) -> result::Result<(), std::io::Error> {
372             self.event_fd.write(1)
373         }
374 
375         fn update(
376             &self,
377             _index: InterruptIndex,
378             _config: InterruptSourceConfig,
379             _masked: bool,
380             _set_gsi: bool,
381         ) -> result::Result<(), std::io::Error> {
382             Ok(())
383         }
384 
385         fn set_gsi(&self) -> result::Result<(), std::io::Error> {
386             Ok(())
387         }
388 
389         fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
390             Some(self.event_fd.try_clone().unwrap())
391         }
392     }
393 
394     impl TestInterrupt {
395         fn new(event_fd: EventFd) -> Self {
396             TestInterrupt { event_fd }
397         }
398     }
399 
400     #[test]
401     fn test_rtc_read_write_and_event() {
402         let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
403 
404         let mut rtc = Rtc::new(Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())));
405         let mut data = [0; 4];
406 
407         // Read and write to the MR register.
408         write_le_u32(&mut data, 123);
409         rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCMR, &data);
410         rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCMR, &mut data);
411         let v = read_le_u32(&data);
412         assert_eq!(v, 123);
413 
414         // Read and write to the LR register.
415         let v = get_time(ClockType::Real);
416         write_le_u32(&mut data, (v / NANOS_PER_SECOND) as u32);
417         let previous_now_before = rtc.previous_now;
418         rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCLR, &data);
419 
420         assert!(rtc.previous_now > previous_now_before);
421 
422         rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCLR, &mut data);
423         let v_read = read_le_u32(&data);
424         assert_eq!((v / NANOS_PER_SECOND) as u32, v_read);
425 
426         // Read and write to IMSC register.
427         // Test with non zero value.
428         let non_zero = 1;
429         write_le_u32(&mut data, non_zero);
430         rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
431         // The interrupt line should be on.
432         assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() == 1);
433         rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
434         let v = read_le_u32(&data);
435         assert_eq!(non_zero & 1, v);
436 
437         // Now test with 0.
438         write_le_u32(&mut data, 0);
439         rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
440         rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
441         let v = read_le_u32(&data);
442         assert_eq!(0, v);
443 
444         // Read and write to the ICR register.
445         write_le_u32(&mut data, 1);
446         rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCICR, &data);
447         // The interrupt line should be on.
448         assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() > 1);
449         let v_before = read_le_u32(&data);
450 
451         rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCICR, &mut data);
452         let v = read_le_u32(&data);
453         // ICR is a  write only register. Data received should stay equal to data sent.
454         assert_eq!(v, v_before);
455 
456         // Attempts to turn off the RTC should not go through.
457         write_le_u32(&mut data, 0);
458         rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCCR, &data);
459         rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCCR, &mut data);
460         let v = read_le_u32(&data);
461         assert_eq!(v, 1);
462 
463         // Attempts to write beyond the writable space. Using here the space used to read
464         // the CID and PID from.
465         write_le_u32(&mut data, 0);
466         rtc.write(LEGACY_RTC_MAPPED_IO_START, AMBA_ID_LOW, &data);
467         // However, reading from the AMBA_ID_LOW should succeed upon read.
468 
469         let mut data = [0; 4];
470         rtc.read(LEGACY_RTC_MAPPED_IO_START, AMBA_ID_LOW, &mut data);
471         let index = AMBA_ID_LOW + 3;
472         assert_eq!(data[0], PL031_ID[((index - AMBA_ID_LOW) >> 2) as usize]);
473     }
474 
475     macro_rules! byte_order_test_read_write {
476         ($test_name: ident, $write_fn_name: ident, $read_fn_name: ident, $is_be: expr, $data_type: ty) => {
477             #[test]
478             fn $test_name() {
479                 let test_cases = [
480                     (
481                         0x0123_4567_89AB_CDEF as u64,
482                         [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
483                     ),
484                     (
485                         0x0000_0000_0000_0000 as u64,
486                         [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
487                     ),
488                     (
489                         0x1923_2345_ABF3_CCD4 as u64,
490                         [0x19, 0x23, 0x23, 0x45, 0xAB, 0xF3, 0xCC, 0xD4],
491                     ),
492                     (
493                         0x0FF0_0FF0_0FF0_0FF0 as u64,
494                         [0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0],
495                     ),
496                     (
497                         0xFFFF_FFFF_FFFF_FFFF as u64,
498                         [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
499                     ),
500                     (
501                         0x89AB_12D4_C2D2_09BB as u64,
502                         [0x89, 0xAB, 0x12, 0xD4, 0xC2, 0xD2, 0x09, 0xBB],
503                     ),
504                 ];
505 
506                 let type_size = std::mem::size_of::<$data_type>();
507                 for (test_val, v_arr) in &test_cases {
508                     let v = *test_val as $data_type;
509                     let cmp_iter: Box<dyn Iterator<Item = _>> = if $is_be {
510                         Box::new(v_arr[(8 - type_size)..].iter())
511                     } else {
512                         Box::new(v_arr.iter().rev())
513                     };
514                     // test write
515                     let mut write_arr = vec![Default::default(); type_size];
516                     $write_fn_name(&mut write_arr, v);
517                     for (cmp, cur) in cmp_iter.zip(write_arr.iter()) {
518                         assert_eq!(*cmp, *cur as u8)
519                     }
520                     // test read
521                     let read_val = $read_fn_name(&write_arr);
522                     assert_eq!(v, read_val);
523                 }
524             }
525         };
526     }
527 
528     byte_order_test_read_write!(test_le_u16, write_le_u16, read_le_u16, false, u16);
529     byte_order_test_read_write!(test_le_u32, write_le_u32, read_le_u32, false, u32);
530     byte_order_test_read_write!(test_le_u64, write_le_u64, read_le_u64, false, u64);
531     byte_order_test_read_write!(test_le_i32, write_le_i32, read_le_i32, false, i32);
532     byte_order_test_read_write!(test_be_u16, write_be_u16, read_be_u16, true, u16);
533     byte_order_test_read_write!(test_be_u32, write_be_u32, read_be_u32, true, u32);
534 }
535