1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2018 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryFrom;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::time::SystemTime;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::time::UNIX_EPOCH;
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
10*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
11*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
12*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
13*bb4ee6a4SAndroid Build Coastguard Worker
14*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::CrosvmDeviceId;
15*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusAccessInfo;
16*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusDevice;
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceId;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqEdgeEvent;
19*bb4ee6a4SAndroid Build Coastguard Worker use crate::Suspendable;
20*bb4ee6a4SAndroid Build Coastguard Worker
21*bb4ee6a4SAndroid Build Coastguard Worker // Register offsets
22*bb4ee6a4SAndroid Build Coastguard Worker // Data register
23*bb4ee6a4SAndroid Build Coastguard Worker const RTCDR: u64 = 0x0;
24*bb4ee6a4SAndroid Build Coastguard Worker // Match register
25*bb4ee6a4SAndroid Build Coastguard Worker const RTCMR: u64 = 0x4;
26*bb4ee6a4SAndroid Build Coastguard Worker // Interrupt status register
27*bb4ee6a4SAndroid Build Coastguard Worker const RTCSTAT: u64 = 0x8;
28*bb4ee6a4SAndroid Build Coastguard Worker // Interrupt clear register
29*bb4ee6a4SAndroid Build Coastguard Worker const RTCEOI: u64 = 0x8;
30*bb4ee6a4SAndroid Build Coastguard Worker // Counter load register
31*bb4ee6a4SAndroid Build Coastguard Worker const RTCLR: u64 = 0xC;
32*bb4ee6a4SAndroid Build Coastguard Worker // Counter register
33*bb4ee6a4SAndroid Build Coastguard Worker const RTCCR: u64 = 0x10;
34*bb4ee6a4SAndroid Build Coastguard Worker
35*bb4ee6a4SAndroid Build Coastguard Worker // A single 4K page is mapped for this device
36*bb4ee6a4SAndroid Build Coastguard Worker pub const PL030_AMBA_IOMEM_SIZE: u64 = 0x1000;
37*bb4ee6a4SAndroid Build Coastguard Worker
38*bb4ee6a4SAndroid Build Coastguard Worker // AMBA id registers are at the end of the allocated memory space
39*bb4ee6a4SAndroid Build Coastguard Worker const AMBA_ID_OFFSET: u64 = PL030_AMBA_IOMEM_SIZE - 0x20;
40*bb4ee6a4SAndroid Build Coastguard Worker const AMBA_MASK_OFFSET: u64 = PL030_AMBA_IOMEM_SIZE - 0x28;
41*bb4ee6a4SAndroid Build Coastguard Worker
42*bb4ee6a4SAndroid Build Coastguard Worker // This is the AMBA id for this device
43*bb4ee6a4SAndroid Build Coastguard Worker pub const PL030_AMBA_ID: u32 = 0x00041030;
44*bb4ee6a4SAndroid Build Coastguard Worker pub const PL030_AMBA_MASK: u32 = 0x000FFFFF;
45*bb4ee6a4SAndroid Build Coastguard Worker
46*bb4ee6a4SAndroid Build Coastguard Worker /// An emulated ARM pl030 RTC
47*bb4ee6a4SAndroid Build Coastguard Worker pub struct Pl030 {
48*bb4ee6a4SAndroid Build Coastguard Worker // Event to be used to interrupt the guest for an alarm event
49*bb4ee6a4SAndroid Build Coastguard Worker alarm_evt: IrqEdgeEvent,
50*bb4ee6a4SAndroid Build Coastguard Worker
51*bb4ee6a4SAndroid Build Coastguard Worker // This is the delta we subtract from current time to get the
52*bb4ee6a4SAndroid Build Coastguard Worker // counter value
53*bb4ee6a4SAndroid Build Coastguard Worker counter_delta_time: u32,
54*bb4ee6a4SAndroid Build Coastguard Worker
55*bb4ee6a4SAndroid Build Coastguard Worker // This is the value that triggers an alarm interrupt when it
56*bb4ee6a4SAndroid Build Coastguard Worker // matches with the rtc time
57*bb4ee6a4SAndroid Build Coastguard Worker match_value: u32,
58*bb4ee6a4SAndroid Build Coastguard Worker
59*bb4ee6a4SAndroid Build Coastguard Worker // status flag to keep track of whether the interrupt is cleared
60*bb4ee6a4SAndroid Build Coastguard Worker // or not
61*bb4ee6a4SAndroid Build Coastguard Worker interrupt_active: bool,
62*bb4ee6a4SAndroid Build Coastguard Worker }
63*bb4ee6a4SAndroid Build Coastguard Worker
64*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Serialize, Deserialize)]
65*bb4ee6a4SAndroid Build Coastguard Worker struct Pl030Snapshot {
66*bb4ee6a4SAndroid Build Coastguard Worker counter_delta_time: u32,
67*bb4ee6a4SAndroid Build Coastguard Worker match_value: u32,
68*bb4ee6a4SAndroid Build Coastguard Worker interrupt_active: bool,
69*bb4ee6a4SAndroid Build Coastguard Worker }
70*bb4ee6a4SAndroid Build Coastguard Worker
get_epoch_time() -> u3271*bb4ee6a4SAndroid Build Coastguard Worker fn get_epoch_time() -> u32 {
72*bb4ee6a4SAndroid Build Coastguard Worker let epoch_time = SystemTime::now()
73*bb4ee6a4SAndroid Build Coastguard Worker .duration_since(UNIX_EPOCH)
74*bb4ee6a4SAndroid Build Coastguard Worker .expect("SystemTime::duration_since failed");
75*bb4ee6a4SAndroid Build Coastguard Worker epoch_time.as_secs() as u32
76*bb4ee6a4SAndroid Build Coastguard Worker }
77*bb4ee6a4SAndroid Build Coastguard Worker
78*bb4ee6a4SAndroid Build Coastguard Worker impl Pl030 {
79*bb4ee6a4SAndroid Build Coastguard Worker /// Constructs a Pl030 device
new(evt: IrqEdgeEvent) -> Pl03080*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(evt: IrqEdgeEvent) -> Pl030 {
81*bb4ee6a4SAndroid Build Coastguard Worker Pl030 {
82*bb4ee6a4SAndroid Build Coastguard Worker alarm_evt: evt,
83*bb4ee6a4SAndroid Build Coastguard Worker counter_delta_time: get_epoch_time(),
84*bb4ee6a4SAndroid Build Coastguard Worker match_value: 0,
85*bb4ee6a4SAndroid Build Coastguard Worker interrupt_active: false,
86*bb4ee6a4SAndroid Build Coastguard Worker }
87*bb4ee6a4SAndroid Build Coastguard Worker }
88*bb4ee6a4SAndroid Build Coastguard Worker }
89*bb4ee6a4SAndroid Build Coastguard Worker
90*bb4ee6a4SAndroid Build Coastguard Worker impl BusDevice for Pl030 {
device_id(&self) -> DeviceId91*bb4ee6a4SAndroid Build Coastguard Worker fn device_id(&self) -> DeviceId {
92*bb4ee6a4SAndroid Build Coastguard Worker CrosvmDeviceId::Pl030.into()
93*bb4ee6a4SAndroid Build Coastguard Worker }
94*bb4ee6a4SAndroid Build Coastguard Worker
debug_label(&self) -> String95*bb4ee6a4SAndroid Build Coastguard Worker fn debug_label(&self) -> String {
96*bb4ee6a4SAndroid Build Coastguard Worker "Pl030".to_owned()
97*bb4ee6a4SAndroid Build Coastguard Worker }
98*bb4ee6a4SAndroid Build Coastguard Worker
write(&mut self, info: BusAccessInfo, data: &[u8])99*bb4ee6a4SAndroid Build Coastguard Worker fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
100*bb4ee6a4SAndroid Build Coastguard Worker let data_array = match <&[u8; 4]>::try_from(data) {
101*bb4ee6a4SAndroid Build Coastguard Worker Ok(array) => array,
102*bb4ee6a4SAndroid Build Coastguard Worker _ => {
103*bb4ee6a4SAndroid Build Coastguard Worker warn!("bad write size: {} for pl030", data.len());
104*bb4ee6a4SAndroid Build Coastguard Worker return;
105*bb4ee6a4SAndroid Build Coastguard Worker }
106*bb4ee6a4SAndroid Build Coastguard Worker };
107*bb4ee6a4SAndroid Build Coastguard Worker
108*bb4ee6a4SAndroid Build Coastguard Worker let reg_val = u32::from_ne_bytes(*data_array);
109*bb4ee6a4SAndroid Build Coastguard Worker match info.offset {
110*bb4ee6a4SAndroid Build Coastguard Worker RTCDR => {
111*bb4ee6a4SAndroid Build Coastguard Worker warn!("invalid write to read-only RTCDR register");
112*bb4ee6a4SAndroid Build Coastguard Worker }
113*bb4ee6a4SAndroid Build Coastguard Worker RTCMR => {
114*bb4ee6a4SAndroid Build Coastguard Worker self.match_value = reg_val;
115*bb4ee6a4SAndroid Build Coastguard Worker // TODO(sonnyrao): here we need to set up a timer for
116*bb4ee6a4SAndroid Build Coastguard Worker // when host time equals the value written here and
117*bb4ee6a4SAndroid Build Coastguard Worker // fire the interrupt
118*bb4ee6a4SAndroid Build Coastguard Worker warn!("Not implemented: VM tried to set an RTC alarm");
119*bb4ee6a4SAndroid Build Coastguard Worker }
120*bb4ee6a4SAndroid Build Coastguard Worker RTCEOI => {
121*bb4ee6a4SAndroid Build Coastguard Worker if reg_val == 0 {
122*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_active = false;
123*bb4ee6a4SAndroid Build Coastguard Worker } else {
124*bb4ee6a4SAndroid Build Coastguard Worker self.alarm_evt.trigger().unwrap();
125*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_active = true;
126*bb4ee6a4SAndroid Build Coastguard Worker }
127*bb4ee6a4SAndroid Build Coastguard Worker }
128*bb4ee6a4SAndroid Build Coastguard Worker RTCLR => {
129*bb4ee6a4SAndroid Build Coastguard Worker // TODO(sonnyrao): if we ever need to let the VM set it's own time
130*bb4ee6a4SAndroid Build Coastguard Worker // then we'll need to keep track of the delta between
131*bb4ee6a4SAndroid Build Coastguard Worker // the rtc time it sets and the host's rtc time and
132*bb4ee6a4SAndroid Build Coastguard Worker // record that here
133*bb4ee6a4SAndroid Build Coastguard Worker warn!("Not implemented: VM tried to set the RTC");
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker RTCCR => {
136*bb4ee6a4SAndroid Build Coastguard Worker self.counter_delta_time = get_epoch_time();
137*bb4ee6a4SAndroid Build Coastguard Worker }
138*bb4ee6a4SAndroid Build Coastguard Worker o => panic!("pl030: bad write {}", o),
139*bb4ee6a4SAndroid Build Coastguard Worker }
140*bb4ee6a4SAndroid Build Coastguard Worker }
141*bb4ee6a4SAndroid Build Coastguard Worker
read(&mut self, info: BusAccessInfo, data: &mut [u8])142*bb4ee6a4SAndroid Build Coastguard Worker fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
143*bb4ee6a4SAndroid Build Coastguard Worker let data_array = match <&mut [u8; 4]>::try_from(data) {
144*bb4ee6a4SAndroid Build Coastguard Worker Ok(array) => array,
145*bb4ee6a4SAndroid Build Coastguard Worker _ => {
146*bb4ee6a4SAndroid Build Coastguard Worker warn!("bad write size for pl030");
147*bb4ee6a4SAndroid Build Coastguard Worker return;
148*bb4ee6a4SAndroid Build Coastguard Worker }
149*bb4ee6a4SAndroid Build Coastguard Worker };
150*bb4ee6a4SAndroid Build Coastguard Worker
151*bb4ee6a4SAndroid Build Coastguard Worker let reg_content: u32 = match info.offset {
152*bb4ee6a4SAndroid Build Coastguard Worker RTCDR => get_epoch_time(),
153*bb4ee6a4SAndroid Build Coastguard Worker RTCMR => self.match_value,
154*bb4ee6a4SAndroid Build Coastguard Worker RTCSTAT => self.interrupt_active as u32,
155*bb4ee6a4SAndroid Build Coastguard Worker RTCLR => {
156*bb4ee6a4SAndroid Build Coastguard Worker warn!("invalid read of RTCLR register");
157*bb4ee6a4SAndroid Build Coastguard Worker 0
158*bb4ee6a4SAndroid Build Coastguard Worker }
159*bb4ee6a4SAndroid Build Coastguard Worker RTCCR => get_epoch_time() - self.counter_delta_time,
160*bb4ee6a4SAndroid Build Coastguard Worker AMBA_ID_OFFSET => PL030_AMBA_ID,
161*bb4ee6a4SAndroid Build Coastguard Worker AMBA_MASK_OFFSET => PL030_AMBA_MASK,
162*bb4ee6a4SAndroid Build Coastguard Worker
163*bb4ee6a4SAndroid Build Coastguard Worker o => panic!("pl030: bad read {}", o),
164*bb4ee6a4SAndroid Build Coastguard Worker };
165*bb4ee6a4SAndroid Build Coastguard Worker *data_array = reg_content.to_ne_bytes();
166*bb4ee6a4SAndroid Build Coastguard Worker }
167*bb4ee6a4SAndroid Build Coastguard Worker }
168*bb4ee6a4SAndroid Build Coastguard Worker
169*bb4ee6a4SAndroid Build Coastguard Worker impl Suspendable for Pl030 {
snapshot(&mut self) -> anyhow::Result<serde_json::Value>170*bb4ee6a4SAndroid Build Coastguard Worker fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
171*bb4ee6a4SAndroid Build Coastguard Worker serde_json::to_value(Pl030Snapshot {
172*bb4ee6a4SAndroid Build Coastguard Worker counter_delta_time: self.counter_delta_time,
173*bb4ee6a4SAndroid Build Coastguard Worker match_value: self.match_value,
174*bb4ee6a4SAndroid Build Coastguard Worker interrupt_active: self.interrupt_active,
175*bb4ee6a4SAndroid Build Coastguard Worker })
176*bb4ee6a4SAndroid Build Coastguard Worker .with_context(|| format!("error serializing {}", self.debug_label()))
177*bb4ee6a4SAndroid Build Coastguard Worker }
178*bb4ee6a4SAndroid Build Coastguard Worker
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>179*bb4ee6a4SAndroid Build Coastguard Worker fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
180*bb4ee6a4SAndroid Build Coastguard Worker let deser: Pl030Snapshot = serde_json::from_value(data)
181*bb4ee6a4SAndroid Build Coastguard Worker .with_context(|| format!("failed to deserialize {}", self.debug_label()))?;
182*bb4ee6a4SAndroid Build Coastguard Worker self.counter_delta_time = deser.counter_delta_time;
183*bb4ee6a4SAndroid Build Coastguard Worker self.match_value = deser.match_value;
184*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_active = deser.interrupt_active;
185*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
186*bb4ee6a4SAndroid Build Coastguard Worker }
187*bb4ee6a4SAndroid Build Coastguard Worker
sleep(&mut self) -> anyhow::Result<()>188*bb4ee6a4SAndroid Build Coastguard Worker fn sleep(&mut self) -> anyhow::Result<()> {
189*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
190*bb4ee6a4SAndroid Build Coastguard Worker }
191*bb4ee6a4SAndroid Build Coastguard Worker
wake(&mut self) -> anyhow::Result<()>192*bb4ee6a4SAndroid Build Coastguard Worker fn wake(&mut self) -> anyhow::Result<()> {
193*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
194*bb4ee6a4SAndroid Build Coastguard Worker }
195*bb4ee6a4SAndroid Build Coastguard Worker }
196*bb4ee6a4SAndroid Build Coastguard Worker
197*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
198*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
199*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
200*bb4ee6a4SAndroid Build Coastguard Worker
201*bb4ee6a4SAndroid Build Coastguard Worker // The RTC device is placed at page 2 in the mmio bus
202*bb4ee6a4SAndroid Build Coastguard Worker const AARCH64_RTC_ADDR: u64 = 0x2000;
203*bb4ee6a4SAndroid Build Coastguard Worker
pl030_bus_address(offset: u64) -> BusAccessInfo204*bb4ee6a4SAndroid Build Coastguard Worker fn pl030_bus_address(offset: u64) -> BusAccessInfo {
205*bb4ee6a4SAndroid Build Coastguard Worker BusAccessInfo {
206*bb4ee6a4SAndroid Build Coastguard Worker address: AARCH64_RTC_ADDR + offset,
207*bb4ee6a4SAndroid Build Coastguard Worker offset,
208*bb4ee6a4SAndroid Build Coastguard Worker id: 0,
209*bb4ee6a4SAndroid Build Coastguard Worker }
210*bb4ee6a4SAndroid Build Coastguard Worker }
211*bb4ee6a4SAndroid Build Coastguard Worker
212*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_interrupt_status_register()213*bb4ee6a4SAndroid Build Coastguard Worker fn test_interrupt_status_register() {
214*bb4ee6a4SAndroid Build Coastguard Worker let event = IrqEdgeEvent::new().unwrap();
215*bb4ee6a4SAndroid Build Coastguard Worker let mut device = Pl030::new(event.try_clone().unwrap());
216*bb4ee6a4SAndroid Build Coastguard Worker let mut register = [0, 0, 0, 0];
217*bb4ee6a4SAndroid Build Coastguard Worker
218*bb4ee6a4SAndroid Build Coastguard Worker // set interrupt
219*bb4ee6a4SAndroid Build Coastguard Worker device.write(pl030_bus_address(RTCEOI), &[1, 0, 0, 0]);
220*bb4ee6a4SAndroid Build Coastguard Worker device.read(pl030_bus_address(RTCSTAT), &mut register);
221*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(register, [1, 0, 0, 0]);
222*bb4ee6a4SAndroid Build Coastguard Worker event.get_trigger().wait().unwrap();
223*bb4ee6a4SAndroid Build Coastguard Worker
224*bb4ee6a4SAndroid Build Coastguard Worker // clear interrupt
225*bb4ee6a4SAndroid Build Coastguard Worker device.write(pl030_bus_address(RTCEOI), &[0, 0, 0, 0]);
226*bb4ee6a4SAndroid Build Coastguard Worker device.read(pl030_bus_address(RTCSTAT), &mut register);
227*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(register, [0, 0, 0, 0]);
228*bb4ee6a4SAndroid Build Coastguard Worker }
229*bb4ee6a4SAndroid Build Coastguard Worker
230*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_match_register()231*bb4ee6a4SAndroid Build Coastguard Worker fn test_match_register() {
232*bb4ee6a4SAndroid Build Coastguard Worker let mut device = Pl030::new(IrqEdgeEvent::new().unwrap());
233*bb4ee6a4SAndroid Build Coastguard Worker let mut register = [0, 0, 0, 0];
234*bb4ee6a4SAndroid Build Coastguard Worker
235*bb4ee6a4SAndroid Build Coastguard Worker device.write(pl030_bus_address(RTCMR), &[1, 2, 3, 4]);
236*bb4ee6a4SAndroid Build Coastguard Worker device.read(pl030_bus_address(RTCMR), &mut register);
237*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(register, [1, 2, 3, 4]);
238*bb4ee6a4SAndroid Build Coastguard Worker }
239*bb4ee6a4SAndroid Build Coastguard Worker }
240