use std::collections::VecDeque;
use std::io::{Read, Write};
use std::sync::Arc;
use parking_lot::Mutex;
use crate::device::console::{Console, ConsoleThread, UartRecv};
use crate::device::{MmioDev, Pause, Result};
use crate::hv::IrqSender;
use crate::mem::emulated::{Action, Mmio};
use crate::{bitflags, hv, mem};
const UART_DR: u64 = 0x0;
const UART_RSR: u64 = 0x4;
const UART_ECR: u64 = 0x4;
const UART_FR: u64 = 0x18;
const UART_ILPR: u64 = 0x20;
const UART_IBRD: u64 = 0x24;
const UART_FBRD: u64 = 0x28;
const UART_LCR_H: u64 = 0x2C;
const UART_CR: u64 = 0x30;
const UART_IFLS: u64 = 0x34;
const UART_IMSC: u64 = 0x38;
const UART_RIS: u64 = 0x3C;
const UART_MIS: u64 = 0x40;
const UART_ICR: u64 = 0x44;
const UART_DMACR: u64 = 0x48;
const UART_PERIPH_ID0: u64 = 0xFE0;
const UART_PERIPH_ID1: u64 = 0xFE4;
const UART_PERIPH_ID2: u64 = 0xFE8;
const UART_PERIPH_ID3: u64 = 0xFEC;
const UART_PCELL_ID0: u64 = 0xFF0;
const UART_PCELL_ID1: u64 = 0xFF4;
const UART_PCELL_ID2: u64 = 0xFF8;
const UART_PCELL_ID3: u64 = 0xFFC;
const PERIPH_ID: [u32; 4] = [0x11, 0x10, 0x14, 0x00];
const PCELL_ID: [u32; 4] = [0x0d, 0xf0, 0x05, 0xb1];
bitflags! {
#[derive(Default)]
pub struct Flag(u16) {
RI = 1 << 8;
TXFE = 1 << 7;
RXFF = 1 << 6;
TXFF = 1 << 5;
RXFE = 1 << 4;
BUSY = 1 << 3;
DCD = 1 << 2;
DSR = 1 << 1;
CTS = 1 << 0;
}
}
bitflags! {
#[derive(Default)]
pub struct Interrupt(u16) {
OERIS = 1 << 10;
BERIS = 1 << 9;
PERIS = 1 << 8;
FERIS = 1 << 7;
RTRIS = 1 << 6;
TXRIS = 1 << 5;
RXRIS = 1 << 4;
DSRRMIS = 1 << 3;
DCDRMIS = 1 << 2;
CTSRMIS = 1 << 1;
RIRMIS = 1 << 0;
}
}
#[derive(Debug, Default)]
struct Pl011Reg {
data: VecDeque<u8>,
flag: Flag,
lcr: u32,
rsr: u32,
cr: u32,
dmacr: u32,
ilpr: u32,
ibrd: u32,
fbrd: u32,
ifl: u32,
interrupt_mask: Interrupt,
interrupt_status: Interrupt,
}
#[derive(Debug)]
pub struct Pl011<I, C> {
name: Arc<str>,
irq_line: Arc<I>,
reg: Arc<Mutex<Pl011Reg>>,
console: Arc<C>,
_thread: ConsoleThread,
}
impl<I, C> Pl011<I, C>
where
I: IrqSender,
C: Console,
for<'a> &'a C: Read + Write,
{
pub fn new(base_addr: u64, irq_line: I, console: C) -> Result<Self> {
let irq_line = Arc::new(irq_line);
let console = Arc::new(console);
let mut reg = Pl011Reg::default();
reg.flag |= Flag::RXFE | Flag::TXFE;
let reg = Arc::new(Mutex::new(reg));
let name: Arc<str> = Arc::from(format!("pl011@{base_addr:#x}"));
let pl011_recv = Pl011Recv {
irq_line: irq_line.clone(),
reg: reg.clone(),
};
let thread = ConsoleThread::new(name.clone(), pl011_recv, console.clone())?;
let pl011 = Pl011 {
name,
irq_line,
reg,
console,
_thread: thread,
};
Ok(pl011)
}
fn update_interrupt(&self, reg: &Pl011Reg) -> Result<(), hv::Error> {
if (reg.interrupt_status & reg.interrupt_mask).bits() != 0 {
self.irq_line.send().unwrap();
}
Ok(())
}
}
impl<I, C> Mmio for Pl011<I, C>
where
I: IrqSender,
C: Console,
for<'a> &'a C: Read + Write,
{
fn size(&self) -> u64 {
0x1000
}
fn read(&self, offset: u64, _size: u8) -> mem::Result<u64> {
let mut reg = self.reg.lock();
let ret = match offset {
UART_DR => {
let byte = reg.data.pop_front().unwrap_or(0);
if reg.data.is_empty() {
reg.flag.insert(Flag::RXFE);
reg.interrupt_status.remove(Interrupt::RXRIS);
}
self.update_interrupt(®)?;
byte as u32
}
UART_RSR => reg.rsr,
UART_FR => reg.flag.bits() as u32,
UART_ILPR => reg.ilpr,
UART_IBRD => reg.ibrd,
UART_FBRD => reg.fbrd,
UART_LCR_H => reg.lcr,
UART_CR => reg.cr,
UART_IFLS => reg.ifl,
UART_IMSC => reg.interrupt_mask.bits() as u32,
UART_RIS => reg.interrupt_status.bits() as u32,
UART_MIS => (reg.interrupt_mask & reg.interrupt_status).bits() as u32,
UART_ICR => {
log::error!("{}: UART_ICR is write only", self.name);
0
}
UART_DMACR => reg.dmacr,
UART_PERIPH_ID0 => PERIPH_ID[0],
UART_PERIPH_ID1 => PERIPH_ID[1],
UART_PERIPH_ID2 => PERIPH_ID[2],
UART_PERIPH_ID3 => PERIPH_ID[3],
UART_PCELL_ID0 => PCELL_ID[0],
UART_PCELL_ID1 => PCELL_ID[1],
UART_PCELL_ID2 => PCELL_ID[2],
UART_PCELL_ID3 => PCELL_ID[3],
_ => 0,
};
Ok(ret as u64)
}
fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {
let mut reg = self.reg.lock();
match offset {
UART_DR => {
let _ = self.console.as_ref().write(&[val as u8]);
reg.interrupt_status.insert(Interrupt::TXRIS);
reg.flag.insert(Flag::TXFE);
self.update_interrupt(®)?;
}
UART_ECR => reg.rsr = 0,
UART_FR => log::error!("{}: UART_FR is read only", self.name),
UART_ILPR => reg.ilpr = val as u32,
UART_IBRD => reg.ibrd = val as u32,
UART_FBRD => reg.fbrd = val as u32,
UART_LCR_H => reg.lcr = val as u32,
UART_CR => reg.cr = val as u32,
UART_IFLS => reg.ifl = val as u32,
UART_IMSC => {
reg.interrupt_mask = Interrupt::from_bits_truncate(val as u16);
}
UART_RIS => log::error!("{}, UART_RIS is read only", self.name),
UART_MIS => log::error!("{}, UART_MIS is read only", self.name),
UART_ICR => reg.interrupt_status &= !Interrupt::from_bits_truncate(val as u16),
UART_DMACR => reg.dmacr = val as u32,
_ => {}
}
Ok(Action::None)
}
}
impl<I, C> Pause for Pl011<I, C>
where
I: IrqSender,
C: Console,
for<'a> &'a C: Read + Write,
{
fn pause(&self) -> Result<()> {
Ok(())
}
fn resume(&self) -> Result<()> {
Ok(())
}
}
impl<I, C> MmioDev for Pl011<I, C>
where
I: IrqSender,
C: Console,
for<'a> &'a C: Read + Write,
{
}
struct Pl011Recv<I: IrqSender> {
irq_line: Arc<I>,
reg: Arc<Mutex<Pl011Reg>>,
}
impl<I: IrqSender> UartRecv for Pl011Recv<I> {
fn receive(&self, bytes: &[u8]) {
let mut reg = self.reg.lock();
reg.data.extend(bytes);
reg.interrupt_status.insert(Interrupt::RXRIS);
reg.flag.remove(Flag::RXFE);
if (reg.interrupt_status & reg.interrupt_mask).bits() != 0 {
self.irq_line.send().unwrap();
}
}
}
#[cfg(test)]
#[path = "pl011_test.rs"]
mod tests;