use std::collections::VecDeque;
use std::io::{Read, Write};
use std::sync::Arc;
use bitfield::bitfield;
use parking_lot::Mutex;
use crate::device::console::{Console, ConsoleThread, UartRecv};
use crate::device::ioapic::IoApic;
use crate::device::{self, MmioDev, Pause, Result};
use crate::hv::MsiSender;
use crate::mem::emulated::{Action, Mmio};
use crate::{bitflags, mem};
const TX_HOLDING_REGISTER: u16 = 0x0;
const RX_BUFFER_REGISTER: u16 = 0x0;
const DIVISOR_LATCH_LSB: u16 = 0x0;
const DIVISOR_LATCH_MSB: u16 = 0x1;
const INTERRUPT_ENABLE_REGISTER: u16 = 0x1;
const FIFO_CONTROL_REGISTER: u16 = 0x2;
const INTERRUPT_IDENTIFICATION_REGISTER: u16 = 0x2;
const LINE_CONTROL_REGISTER: u16 = 0x3;
const MODEM_CONTROL_REGISTER: u16 = 0x4;
const LINE_STATUS_REGISTER: u16 = 0x5;
const MODEM_STATUS_REGISTER: u16 = 0x6;
const SCRATCH_REGISTER: u16 = 0x7;
bitflags! {
#[derive(Default)]
pub struct InterruptEnable(u8) {
MODEM_STATUS = 1 << 3;
RECEIVER_LINE_STATUS = 1 << 2;
TX_HOLDING_REGISTER_EMPTY = 1 << 1;
RECEIVED_DATA_AVAILABLE = 1 << 0;
}
}
bitfield! {
#[derive(Copy, Clone, Default)]
pub struct FifoControl(u8);
impl Debug;
rx_trigger_size_bits, _: 7, 6;
dma_mode, _: 3;
tx_reset, _: 2;
rx_reset, _: 1;
fifo_enabled, _: 0;
}
impl FifoControl {
pub fn rx_trigger_size(&self) -> usize {
match self.rx_trigger_size_bits() {
0b00 => 1,
0b01 => 4,
0b10 => 8,
0b11 => 14,
_ => unreachable!(),
}
}
}
bitfield! {
#[derive(Copy, Clone)]
pub struct InterruptIdentification(u8);
impl Debug;
fifo_enabled, _: 7, 6;
interrupt_id, set_interrupt_id: 3,1;
no_pending, set_no_pending: 0; }
impl InterruptIdentification {
pub fn set_fifo_enabled(&mut self) {
self.0 |= 0b11 << 6;
}
pub fn clear_fifi_enabled(&mut self) {
self.0 &= !(0b11 << 6);
}
pub fn set_rx_data_available(&mut self) {
self.0 = (self.0 & !0b1111) | 0b0100;
}
pub fn set_tx_room_empty(&mut self) {
self.0 = (self.0 & !0b1111) | 0b0010;
}
pub fn clear_interrupt(&mut self) {
self.0 = (self.0 & !0b1111) | 1;
}
}
impl Default for InterruptIdentification {
fn default() -> Self {
let mut val = InterruptIdentification(0);
val.clear_interrupt();
val
}
}
bitfield! {
#[derive(Copy, Clone)]
pub struct LineControl(u8);
impl Debug;
divisor_latch_access, _: 7;
break_, _: 6;
stick_parity, _: 5;
even_parity, _: 4;
parity_enabled, _: 3;
step_bits, _: 2;
word_length, _: 1, 0;
}
impl Default for LineControl {
fn default() -> Self {
LineControl(0b00000011) }
}
bitfield! {
#[derive(Copy, Clone, Default)]
pub struct ModemControl(u8);
impl Debug;
loop_back, _: 4;
out_2, _: 3;
out_1, _: 2;
request_to_send, _: 1;
data_terminal_ready, _: 0; }
bitflags! {
pub struct LineStatus(u8) {
ERROR_IN_RX_FIFO = 1 << 7;
TX_EMPTY = 1 << 6;
TX_HOLDING_REGISTER_EMPTY = 1 << 5;
BREAK_INTERRUPT = 1 << 4;
FRAMING_ERROR = 1 << 3;
PARITY_ERROR = 1 << 2;
OVERRUN_ERROR = 1 << 1;
DATA_READY = 1 << 0;
}
}
impl Default for LineStatus {
fn default() -> Self {
LineStatus::TX_EMPTY | LineStatus::TX_HOLDING_REGISTER_EMPTY
}
}
#[derive(Default, Debug)]
struct SerialReg {
interrupt_enable: InterruptEnable, #[allow(dead_code)]
fifo_control: FifoControl, interrupt_identification: InterruptIdentification, line_control: LineControl, modem_control: ModemControl, line_status: LineStatus,
modem_status: u8, scratch: u8, divisor: u16,
data: VecDeque<u8>,
}
#[derive(Debug)]
pub struct Serial<M: MsiSender, C> {
name: Arc<str>,
io_apci: Arc<IoApic<M>>,
pin: u8,
reg: Arc<Mutex<SerialReg>>,
console: Arc<C>,
_thread: ConsoleThread,
}
impl<M, C> Mmio for Serial<M, C>
where
M: MsiSender,
C: Console,
for<'a> &'a C: Read + Write,
{
fn size(&self) -> u64 {
8
}
fn read(&self, offset: u64, _size: u8) -> Result<u64, mem::Error> {
let mut reg = self.reg.lock();
let ret = match offset as u16 {
DIVISOR_LATCH_LSB if reg.line_control.divisor_latch_access() => reg.divisor as u8,
DIVISOR_LATCH_MSB if reg.line_control.divisor_latch_access() => {
(reg.divisor >> 8) as u8
}
RX_BUFFER_REGISTER => {
if reg.data.len() <= 1 {
reg.line_status &= !LineStatus::DATA_READY;
}
reg.data.pop_front().unwrap_or(0xff)
}
INTERRUPT_ENABLE_REGISTER => reg.interrupt_enable.bits(),
INTERRUPT_IDENTIFICATION_REGISTER => {
let ret = reg.interrupt_identification.0;
reg.interrupt_identification.clear_interrupt();
ret
}
LINE_CONTROL_REGISTER => reg.line_control.0,
MODEM_CONTROL_REGISTER => reg.modem_control.0,
LINE_STATUS_REGISTER => reg.line_status.bits(),
MODEM_STATUS_REGISTER => reg.modem_status,
SCRATCH_REGISTER => reg.scratch,
_ => {
log::error!("{}: read unreachable offset {offset:#x}", self.name,);
0x0
}
};
Ok(ret as u64)
}
fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {
let byte = val as u8;
let mut reg = self.reg.lock();
match offset as u16 {
DIVISOR_LATCH_LSB if reg.line_control.divisor_latch_access() => {
reg.divisor = (reg.divisor & 0xff00) | byte as u16;
}
DIVISOR_LATCH_MSB if reg.line_control.divisor_latch_access() => {
reg.divisor = (reg.divisor & 0x00ff) | ((byte as u16) << 8);
}
TX_HOLDING_REGISTER => {
if reg.modem_control.loop_back() {
reg.data.push_back(byte);
if reg
.interrupt_enable
.contains(InterruptEnable::RECEIVED_DATA_AVAILABLE)
{
reg.interrupt_identification.set_rx_data_available();
self.send_irq();
}
reg.line_status |= LineStatus::DATA_READY;
} else {
let _ = self.console.as_ref().write(&[byte]);
if reg
.interrupt_enable
.contains(InterruptEnable::TX_HOLDING_REGISTER_EMPTY)
{
reg.interrupt_identification.set_tx_room_empty();
self.send_irq()
}
}
}
INTERRUPT_ENABLE_REGISTER => {
reg.interrupt_enable = InterruptEnable::from_bits_truncate(byte);
}
FIFO_CONTROL_REGISTER => {}
LINE_CONTROL_REGISTER => {
reg.line_control = LineControl(byte);
}
MODEM_CONTROL_REGISTER => {
reg.modem_control = ModemControl(byte);
}
LINE_STATUS_REGISTER => {}
MODEM_STATUS_REGISTER => {}
SCRATCH_REGISTER => {
reg.scratch = byte;
}
_ => log::error!("{}: write unreachable offset {:#x}", self.name, offset),
}
Ok(Action::None)
}
}
impl<M, C> Pause for Serial<M, C>
where
M: MsiSender,
{
fn pause(&self) -> device::Result<()> {
Ok(())
}
fn resume(&self) -> device::Result<()> {
Ok(())
}
}
impl<M, C> MmioDev for Serial<M, C>
where
M: MsiSender,
C: Console,
for<'a> &'a C: Read + Write,
{
}
struct SerialRecv<M: MsiSender> {
pub name: Arc<str>,
pub io_apci: Arc<IoApic<M>>,
pub pin: u8,
pub reg: Arc<Mutex<SerialReg>>,
}
impl<M: MsiSender> UartRecv for SerialRecv<M> {
fn receive(&self, bytes: &[u8]) {
let mut reg = self.reg.lock();
reg.data.extend(bytes);
if reg
.interrupt_enable
.contains(InterruptEnable::RECEIVED_DATA_AVAILABLE)
{
reg.interrupt_identification.set_rx_data_available();
if let Err(e) = self.io_apci.service_pin(self.pin) {
log::error!("{}: sending interrupt: {e:?}", self.name);
}
}
reg.line_status |= LineStatus::DATA_READY;
}
}
impl<M, C> Serial<M, C>
where
M: MsiSender,
C: Console,
for<'a> &'a C: Read + Write,
{
pub fn new(base_port: u16, io_apci: Arc<IoApic<M>>, pin: u8, console: C) -> Result<Self> {
let reg = Arc::new(Mutex::new(SerialReg::default()));
let console = Arc::new(console);
let name: Arc<str> = Arc::from(format!("serial_{base_port:#x}"));
let uart_recv = SerialRecv {
io_apci: io_apci.clone(),
pin,
name: name.clone(),
reg: reg.clone(),
};
let thread = ConsoleThread::new(name.clone(), uart_recv, console.clone())?;
let serial = Serial {
name,
reg,
pin,
io_apci,
console,
_thread: thread,
};
Ok(serial)
}
fn send_irq(&self) {
if let Err(e) = self.io_apci.service_pin(self.pin) {
log::error!("{}: sending interrupt: {e:?}", self.name);
}
}
}