pl011.rs70.48%
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::{Read, Write};17
use std::sync::Arc;18
19
use parking_lot::Mutex;20
21
use crate::device::console::{Console, ConsoleThread, UartRecv};22
use crate::device::{MmioDev, Pause, Result};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, C> {146
name: Arc<str>,147
irq_line: Arc<I>,148
reg: Arc<Mutex<Pl011Reg>>,149
console: Arc<C>,150
_thread: ConsoleThread,151
}152
153
impl<I, C> Pl011<I, C>154
where155
I: IrqSender,156
C: Console,157
for<'a> &'a C: Read + Write,158
{159
pub fn new(base_addr: u64, irq_line: I, console: C) -> Result<Self> {12x160
let irq_line = Arc::new(irq_line);12x161
let console = Arc::new(console);12x162
let mut reg = Pl011Reg::default();12x163
reg.flag |= Flag::RXFE | Flag::TXFE;12x164
let reg = Arc::new(Mutex::new(reg));12x165
let name: Arc<str> = Arc::from(format!("pl011@{base_addr:#x}"));12x166
let pl011_recv = Pl011Recv {12x167
irq_line: irq_line.clone(),12x168
reg: reg.clone(),12x169
};12x170
let thread = ConsoleThread::new(name.clone(), pl011_recv, console.clone())?;12x171
let pl011 = Pl011 {12x172
name,12x173
irq_line,12x174
reg,12x175
console,12x176
_thread: thread,12x177
};12x178
Ok(pl011)12x179
}12x180
181
fn update_interrupt(&self, reg: &Pl011Reg) -> Result<(), hv::Error> {21x182
if (reg.interrupt_status & reg.interrupt_mask).bits() != 0 {21x183
self.irq_line.send().unwrap();184
}21x185
Ok(())21x186
}21x187
}188
189
impl<I, C> Mmio for Pl011<I, C>190
where191
I: IrqSender,192
C: Console,193
for<'a> &'a C: Read + Write,194
{195
fn size(&self) -> u64 {3x196
0x10003x197
}3x198
199
fn read(&self, offset: u64, _size: u8) -> mem::Result<u64> {78x200
let mut reg = self.reg.lock();78x201
let ret = match offset {78x202
UART_DR => {203
let byte = reg.data.pop_front().unwrap_or(0);18x204
if reg.data.is_empty() {18x205
reg.flag.insert(Flag::RXFE);12x206
reg.interrupt_status.remove(Interrupt::RXRIS);12x207
}12x208
self.update_interrupt(®)?;18x209
byte as u3218x210
}211
UART_RSR => reg.rsr,212
UART_FR => reg.flag.bits() as u32,15x213
UART_ILPR => reg.ilpr,214
UART_IBRD => reg.ibrd,215
UART_FBRD => reg.fbrd,216
UART_LCR_H => reg.lcr,217
UART_CR => reg.cr,218
UART_IFLS => reg.ifl,219
UART_IMSC => reg.interrupt_mask.bits() as u32,220
UART_RIS => reg.interrupt_status.bits() as u32,12x221
UART_MIS => (reg.interrupt_mask & reg.interrupt_status).bits() as u32,9x222
UART_ICR => {223
log::error!("{}: UART_ICR is write only", self.name);224
0225
}226
UART_DMACR => reg.dmacr,227
UART_PERIPH_ID0 => PERIPH_ID[0],3x228
UART_PERIPH_ID1 => PERIPH_ID[1],3x229
UART_PERIPH_ID2 => PERIPH_ID[2],3x230
UART_PERIPH_ID3 => PERIPH_ID[3],3x231
UART_PCELL_ID0 => PCELL_ID[0],3x232
UART_PCELL_ID1 => PCELL_ID[1],3x233
UART_PCELL_ID2 => PCELL_ID[2],3x234
UART_PCELL_ID3 => PCELL_ID[3],3x235
_ => 0,236
};237
Ok(ret as u64)78x238
}78x239
240
fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {12x241
let mut reg = self.reg.lock();12x242
match offset {12x243
UART_DR => {244
let _ = self.console.as_ref().write(&[val as u8]);3x245
reg.interrupt_status.insert(Interrupt::TXRIS);3x246
reg.flag.insert(Flag::TXFE);3x247
self.update_interrupt(®)?;3x248
}249
UART_ECR => reg.rsr = 0,250
UART_FR => log::error!("{}: UART_FR is read only", self.name),3x251
UART_ILPR => reg.ilpr = val as u32,252
UART_IBRD => reg.ibrd = val as u32,253
UART_FBRD => reg.fbrd = val as u32,254
UART_LCR_H => reg.lcr = val as u32,255
UART_CR => reg.cr = val as u32,256
UART_IFLS => reg.ifl = val as u32,257
UART_IMSC => {6x258
reg.interrupt_mask = Interrupt::from_bits_truncate(val as u16);6x259
}6x260
UART_RIS => log::error!("{}, UART_RIS is read only", self.name),261
UART_MIS => log::error!("{}, UART_MIS is read only", self.name),262
UART_ICR => reg.interrupt_status &= !Interrupt::from_bits_truncate(val as u16),263
UART_DMACR => reg.dmacr = val as u32,264
_ => {}265
}266
Ok(Action::None)12x267
}12x268
}269
270
impl<I, C> Pause for Pl011<I, C>271
where272
I: IrqSender,273
C: Console,274
for<'a> &'a C: Read + Write,275
{276
fn pause(&self) -> Result<()> {277
Ok(())278
}279
280
fn resume(&self) -> Result<()> {281
Ok(())282
}283
}284
285
impl<I, C> MmioDev for Pl011<I, C>286
where287
I: IrqSender,288
C: Console,289
for<'a> &'a C: Read + Write,290
{291
}292
293
struct Pl011Recv<I: IrqSender> {294
irq_line: Arc<I>,295
reg: Arc<Mutex<Pl011Reg>>,296
}297
298
impl<I: IrqSender> UartRecv for Pl011Recv<I> {299
fn receive(&self, bytes: &[u8]) {6x300
let mut reg = self.reg.lock();6x301
reg.data.extend(bytes);6x302
reg.interrupt_status.insert(Interrupt::RXRIS);6x303
reg.flag.remove(Flag::RXFE);6x304
305
if (reg.interrupt_status & reg.interrupt_mask).bits() != 0 {6x306
self.irq_line.send().unwrap();3x307
}3x308
}6x309
}310
311
#[cfg(test)]312
#[path = "pl011_test.rs"]313
mod tests;314