pl031.rs87.93%
1
// Copyright 2025 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
//! Emulated PL031 Real Time Clock (RTC) device.16
//! See: https://developer.arm.com/documentation/ddi0224/c17
18
use parking_lot::Mutex;19
20
use crate::device::clock::Clock;21
use crate::device::{MmioDev, Pause, Result};22
use crate::mem::emulated::{Action, Mmio};23
use crate::{bitflags, mem};24
25
const RTC_DR: u64 = 0x000;26
const RTC_MR: u64 = 0x004;27
const RTC_LR: u64 = 0x008;28
const RTC_CR: u64 = 0x00C;29
const RTC_IMSC: u64 = 0x010;30
const RTC_RIS: u64 = 0x014;31
const RTC_MIS: u64 = 0x018;32
const RTC_ICR: u64 = 0x01C;33
34
const RTC_PERIPH_ID0: u64 = 0xFE0;35
const RTC_PERIPH_ID1: u64 = 0xFE4;36
const RTC_PERIPH_ID2: u64 = 0xFE8;37
const RTC_PERIPH_ID3: u64 = 0xFEC;38
const RTC_PCELL_ID0: u64 = 0xFF0;39
const RTC_PCELL_ID1: u64 = 0xFF4;40
const RTC_PCELL_ID2: u64 = 0xFF8;41
const RTC_PCELL_ID3: u64 = 0xFFC;42
43
const PERIPH_ID: [u8; 4] = [0x31, 0x10, 0x04, 0x00];44
const PCELL_ID: [u8; 4] = [0x0d, 0xf0, 0x05, 0xb1];45
46
bitflags! {47
#[derive(Default)]48
struct Interrupt(u32) {49
RTCINTR = 1 << 0;50
}51
}52
53
#[derive(Debug, Default)]54
struct Pl031Reg {55
mr: u32,56
lr: u32,57
offset: u32,58
}59
60
#[derive(Debug)]61
pub struct Pl031<C> {62
name: Box<str>,63
reg: Mutex<Pl031Reg>,64
clock: C,65
}66
67
impl<C> Pl031<C> {68
pub fn new(base_addr: u64, clock: C) -> Self {2x69
Self {2x70
name: Box::from(format!("pl031@{base_addr:x}")),2x71
reg: Mutex::new(Pl031Reg::default()),2x72
clock,2x73
}2x74
}2x75
}76
77
impl<C: Clock> Pl031<C> {78
fn now(&self) -> u32 {6x79
self.clock.now().as_secs() as u326x80
}6x81
}82
83
impl<C: Clock> Mmio for Pl031<C> {84
fn size(&self) -> u64 {2x85
0x10002x86
}2x87
88
fn read(&self, offset: u64, _size: u8) -> mem::Result<u64> {34x89
let reg = self.reg.lock();34x90
let val = match offset {34x91
RTC_DR => reg.offset.wrapping_add(self.now()),4x92
RTC_MR => reg.mr,2x93
RTC_LR => reg.lr,2x94
RTC_CR => 1, // RTC is always enabled2x95
RTC_IMSC | RTC_RIS | RTC_MIS => 0, // Interrupts are not supported6x96
RTC_PERIPH_ID0 => PERIPH_ID[0] as u32,2x97
RTC_PERIPH_ID1 => PERIPH_ID[1] as u32,2x98
RTC_PERIPH_ID2 => PERIPH_ID[2] as u32,2x99
RTC_PERIPH_ID3 => PERIPH_ID[3] as u32,2x100
RTC_PCELL_ID0 => PCELL_ID[0] as u32,2x101
RTC_PCELL_ID1 => PCELL_ID[1] as u32,2x102
RTC_PCELL_ID2 => PCELL_ID[2] as u32,2x103
RTC_PCELL_ID3 => PCELL_ID[3] as u32,2x104
_ => {105
log::warn!("{}: read from unknown offset {offset:#x}", self.name);2x106
02x107
}108
};109
log::trace!("{}: read {val:#x} from offset {offset:#x}", self.name);34x110
Ok(val as u64)34x111
}34x112
113
fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {12x114
let mut reg = self.reg.lock();12x115
let val = val as u32;12x116
match offset {12x117
RTC_MR => reg.mr = val,2x118
RTC_LR => {2x119
reg.offset = val.wrapping_sub(self.now());2x120
reg.lr = val;2x121
}2x122
RTC_CR => {} // RTC is always enabled2x123
RTC_IMSC => {124
// Interrupt is alwasy masked125
if Interrupt::from_bits_retain(val).contains(Interrupt::RTCINTR) {2x126
log::warn!("{}: guest tries to unmask interrupt", self.name);2x127
}128
}129
RTC_ICR => {} // Interrupts are not supported2x130
_ => {131
log::warn!(2x132
"{}: write {val:#x} to unknown offset {offset:#x}",133
self.name,134
);135
}136
};137
log::trace!("{}: write {val:#x} to offset {offset:#x}", self.name);12x138
Ok(Action::None)12x139
}12x140
}141
142
impl<C: Clock> Pause for Pl031<C> {143
fn pause(&self) -> Result<()> {144
Ok(())145
}146
147
fn resume(&self) -> Result<()> {148
Ok(())149
}150
}151
152
impl<C: Clock> MmioDev for Pl031<C> {}153
154
#[cfg(test)]155
#[path = "pl031_test.rs"]156
mod tests;157