pl011.rs0.00%
1
// Copyright 2024 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
use std::collections::VecDeque;16
use std::io;17
use std::sync::Arc;18
19
use parking_lot::Mutex;20
21
use crate::device::console::{Console, UartRecv};22
use crate::device::{self, MmioDev, Pause};23
use crate::hv::IrqSender;24
use crate::mem::emulated::{Action, Mmio};25
use crate::{bitflags, hv, mem};26
27
/// RW width 12/8 Data Register28
const UART_DR: u64 = 0x0;29
/// RO width 4 Receive Status Register30
const UART_RSR: u64 = 0x4;31
/// WO width 0  Error Clear Register32
const UART_ECR: u64 = 0x4;33
/// RO width 9 Flag Register34
const UART_FR: u64 = 0x18;35
/// RW width 8 IrDA Low-Power Counter Register36
const UART_ILPR: u64 = 0x20;37
/// RW width 16 Integer Baud Rate Register38
const UART_IBRD: u64 = 0x24;39
/// RW width 6 Fractional Baud Rate Register40
const UART_FBRD: u64 = 0x28;41
/// RW width 8 Line Control Register42
const UART_LCR_H: u64 = 0x2C;43
/// RW width 16 Control Register44
const UART_CR: u64 = 0x30;45
/// RW width 6 Interrupt FIFO Level Select Register46
const UART_IFLS: u64 = 0x34;47
/// RW width 11 Interrupt Mask Set/Clear Register48
const UART_IMSC: u64 = 0x38;49
/// RO width 11 Raw Interrupt Status Register50
const UART_RIS: u64 = 0x3C;51
/// RO width 11 Masked Interrupt Status Register52
const UART_MIS: u64 = 0x40;53
/// WO width 11 Interrupt Clear Register54
const UART_ICR: u64 = 0x44;55
/// RW width 3 DMA Control Register56
const UART_DMACR: u64 = 0x48;57
/// RO width 8 UARTPeriphID0 Register58
const UART_PERIPH_ID0: u64 = 0xFE0;59
/// RO width 8 UARTPeriphID1 Register60
const UART_PERIPH_ID1: u64 = 0xFE4;61
/// RO width 8 UARTPeriphID2 Register62
const UART_PERIPH_ID2: u64 = 0xFE8;63
/// RO width 8 UARTPeriphID3 Register64
const UART_PERIPH_ID3: u64 = 0xFEC;65
/// RO width 8 UARTPCellID0 Register66
const UART_PCELL_ID0: u64 = 0xFF0;67
/// RO width 8 UARTPCellID1 Register68
const UART_PCELL_ID1: u64 = 0xFF4;69
/// RO width 8 UARTPCellID2 Register70
const UART_PCELL_ID2: u64 = 0xFF8;71
/// RO width 8 UARTPCellID3 Register72
const UART_PCELL_ID3: u64 = 0xFFC;73
74
// https://developer.arm.com/documentation/ddi0183/g/programmers-model/register-descriptions/peripheral-identification-registers--uartperiphid0-375
const PERIPH_ID: [u32; 4] = [0x11, 0x10, 0x14, 0x00];76
77
// https://developer.arm.com/documentation/ddi0183/g/programmers-model/register-descriptions/primecell-identification-registers--uartpcellid0-378
const PCELL_ID: [u32; 4] = [0x0d, 0xf0, 0x05, 0xb1];79
80
bitflags! {81
#[derive(Default)]82
pub struct Flag(u16) {83
RI = 1 << 8;84
/// Transmit FIFO empty85
TXFE = 1 << 7;86
/// Receive FIFO full87
RXFF = 1 << 6;88
/// Transmit FIFO full.89
TXFF = 1 << 5;90
/// Receive FIFO empty91
RXFE = 1 << 4;92
BUSY = 1 << 3;93
DCD = 1 << 2;94
DSR = 1 << 1;95
CTS = 1 << 0;96
}97
}98
99
bitflags! {100
#[derive(Default)]101
pub struct Interrupt(u16) {102
/// Overrun error interrupt status.103
OERIS = 1 << 10;104
/// Break error interrupt status.105
BERIS = 1 << 9;106
/// Parity error interrupt status.107
PERIS = 1 << 8;108
/// Framing error interrupt status.109
FERIS = 1 << 7;110
/// Receive timeout interrupt status.111
RTRIS = 1 << 6;112
/// Transmit interrupt status.113
TXRIS = 1 << 5;114
/// Receive interrupt status.115
RXRIS = 1 << 4;116
/// nUARTDSR modem interrupt status.117
DSRRMIS = 1 << 3;118
/// nUARTDCD modem interrupt status.119
DCDRMIS = 1 << 2;120
/// nUARTCTS modem interrupt status.121
CTSRMIS = 1 << 1;122
/// nUARTRI modem interrupt status.123
RIRMIS = 1 << 0;124
}125
}126
127
#[derive(Debug, Default)]128
struct Pl011Reg {129
data: VecDeque<u8>,130
flag: Flag,131
lcr: u32,132
rsr: u32,133
cr: u32,134
dmacr: u32,135
ilpr: u32,136
ibrd: u32,137
fbrd: u32,138
ifl: u32,139
interrupt_mask: Interrupt,140
interrupt_status: Interrupt,141
}142
143
/// https://developer.arm.com/documentation/ddi0183/g144
#[derive(Debug)]145
pub struct Pl011<I> {146
name: Arc<str>,147
irq_line: Arc<I>,148
reg: Arc<Mutex<Pl011Reg>>,149
console: Console,150
}151
152
impl<I> Pl011<I>153
where154
I: IrqSender,155
{156
pub fn new(base_addr: u64, irq_line: I) -> io::Result<Self> {157
let irq_line = Arc::new(irq_line);158
let reg = Arc::new(Mutex::new(Pl011Reg::default()));159
let name: Arc<str> = Arc::from(format!("pl011@{base_addr:#x}"));160
let pl011_recv = Pl011Recv {161
irq_line: irq_line.clone(),162
reg: reg.clone(),163
};164
let console = Console::new(name.clone(), pl011_recv)?;165
let pl011 = Pl011 {166
name,167
irq_line,168
reg,169
console,170
};171
Ok(pl011)172
}173
174
fn update_interrupt(&self, reg: &Pl011Reg) -> Result<(), hv::Error> {175
if (reg.interrupt_status & reg.interrupt_mask).bits() != 0 {176
self.irq_line.send().unwrap();177
}178
Ok(())179
}180
}181
182
impl<I> Mmio for Pl011<I>183
where184
I: IrqSender,185
{186
fn size(&self) -> u64 {187
0x1000188
}189
190
fn read(&self, offset: u64, _size: u8) -> mem::Result<u64> {191
let mut reg = self.reg.lock();192
let ret = match offset {193
UART_DR => {194
let byte = reg.data.pop_front().unwrap_or(0);195
if reg.data.is_empty() {196
reg.flag.insert(Flag::RXFE);197
reg.interrupt_status.remove(Interrupt::RXRIS);198
}199
self.update_interrupt(®)?;200
byte as u32201
}202
UART_RSR => reg.rsr,203
UART_FR => reg.flag.bits() as u32,204
UART_ILPR => reg.ilpr,205
UART_IBRD => reg.ibrd,206
UART_FBRD => reg.fbrd,207
UART_LCR_H => reg.lcr,208
UART_CR => reg.cr,209
UART_IFLS => reg.ifl,210
UART_IMSC => reg.interrupt_mask.bits() as u32,211
UART_RIS => reg.interrupt_status.bits() as u32,212
UART_MIS => (reg.interrupt_mask & reg.interrupt_status).bits() as u32,213
UART_ICR => {214
log::error!("{}: UART_ICR is write only", self.name);215
0216
}217
UART_DMACR => reg.dmacr,218
UART_PERIPH_ID0 => PERIPH_ID[0],219
UART_PERIPH_ID1 => PERIPH_ID[1],220
UART_PERIPH_ID2 => PERIPH_ID[2],221
UART_PERIPH_ID3 => PERIPH_ID[3],222
UART_PCELL_ID0 => PCELL_ID[0],223
UART_PCELL_ID1 => PCELL_ID[1],224
UART_PCELL_ID2 => PCELL_ID[2],225
UART_PCELL_ID3 => PCELL_ID[3],226
_ => 0,227
};228
Ok(ret as u64)229
}230
231
fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {232
let mut reg = self.reg.lock();233
match offset {234
UART_DR => {235
self.console.transmit(&[val as u8]);236
reg.interrupt_status.insert(Interrupt::TXRIS);237
reg.flag.insert(Flag::TXFE);238
self.update_interrupt(®)?;239
}240
UART_ECR => reg.rsr = 0,241
UART_FR => log::error!("{}: UART_FR is read only", self.name),242
UART_ILPR => reg.ilpr = val as u32,243
UART_IBRD => reg.ibrd = val as u32,244
UART_FBRD => reg.fbrd = val as u32,245
UART_LCR_H => reg.lcr = val as u32,246
UART_CR => reg.cr = val as u32,247
UART_IFLS => reg.ifl = val as u32,248
UART_IMSC => {249
reg.interrupt_mask = Interrupt::from_bits_truncate(val as u16);250
}251
UART_RIS => log::error!("{}, UART_RIS is read only", self.name),252
UART_MIS => log::error!("{}, UART_MIS is read only", self.name),253
UART_ICR => reg.interrupt_status &= !Interrupt::from_bits_truncate(val as u16),254
UART_DMACR => reg.dmacr = val as u32,255
_ => {}256
}257
Ok(Action::None)258
}259
}260
261
impl<I> Pause for Pl011<I>262
where263
I: IrqSender,264
{265
fn pause(&self) -> device::Result<()> {266
Ok(())267
}268
269
fn resume(&self) -> device::Result<()> {270
Ok(())271
}272
}273
274
impl<I> MmioDev for Pl011<I> where I: IrqSender {}275
276
struct Pl011Recv<I: IrqSender> {277
irq_line: Arc<I>,278
reg: Arc<Mutex<Pl011Reg>>,279
}280
281
impl<I: IrqSender> UartRecv for Pl011Recv<I> {282
fn receive(&self, bytes: &[u8]) {283
let mut reg = self.reg.lock();284
reg.data.extend(bytes);285
reg.interrupt_status.insert(Interrupt::RXRIS);286
reg.flag.remove(Flag::RXFE);287
288
if (reg.interrupt_status & reg.interrupt_mask).bits() != 0 {289
self.irq_line.send().unwrap();290
}291
}292
}293