Skip to content

Commit

Permalink
serial: implement receive FIFO flush via FCR
Browse files Browse the repository at this point in the history
The FIFO Control Register (FCR) controls the behavior of the receive
and transmit FIFO buffers of the device. The current implementation
does not emulate this register, as FIFO buffers are always enabled.
However, there are two bits in this register that control flushing of
said FIFOS. The transmission FIFO is already flushed by the current
implementation on every write, but the receive FIFO is not. This is
problematic, as some driver implementations (e.g. FreeBSD's) rely on
being able to clear this buffer via the corresponding bit.

Implement the correct behavior when a driver sets this bit by clearing
`in_buffer`. Since there is no more data in the receive FIFO, the
data-ready bit in the Line Status Register (LSR) must be cleared as
well, in case it was set.

Fixes: rust-vmm#83
Signed-off-by: Carlos López <[email protected]>
  • Loading branch information
00xc committed Nov 24, 2023
1 parent dd20c85 commit 004b807
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 1 deletion.
2 changes: 2 additions & 0 deletions vm-superio/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
reset event object.
- Added three methods to `Serial` to retrieve the `Write` output object.
- Derived the `Copy` trait for `RtcState` and other auxiliary types.
- Implemented receive FIFO flushing via the FCR register for the `Serial`
device ([#83](https://github.com/rust-vmm/vm-superio/issues/83)).

# v0.7.0

Expand Down
12 changes: 11 additions & 1 deletion vm-superio/src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::Trigger;
const DATA_OFFSET: u8 = 0;
const IER_OFFSET: u8 = 1;
const IIR_OFFSET: u8 = 2;
const FCR_OFFSET: u8 = IIR_OFFSET;
const LCR_OFFSET: u8 = 3;
const MCR_OFFSET: u8 = 4;
const LSR_OFFSET: u8 = 5;
Expand All @@ -48,6 +49,8 @@ const IIR_NONE_BIT: u8 = 0b0000_0001;
const IIR_THR_EMPTY_BIT: u8 = 0b0000_0010;
const IIR_RDA_BIT: u8 = 0b0000_0100;

const FCR_FLUSH_IN_BIT: u8 = 0b0000_0010;

const LCR_DLAB_BIT: u8 = 0b1000_0000;

const LSR_DATA_READY_BIT: u8 = 0b0000_0001;
Expand Down Expand Up @@ -611,7 +614,14 @@ impl<T: Trigger, EV: SerialEvents, W: Write> Serial<T, EV, W> {
LCR_OFFSET => self.line_control = value,
MCR_OFFSET => self.modem_control = value,
SCR_OFFSET => self.scratch = value,
// We are not interested in writing to other offsets (such as FCR offset).
FCR_OFFSET => {
// Clear the receive FIFO
if value & FCR_FLUSH_IN_BIT != 0 {
self.in_buffer.clear();
self.clear_lsr_rda_bit();
self.events.in_buffer_empty();
}
}
_ => {}
}
Ok(())
Expand Down

0 comments on commit 004b807

Please sign in to comment.