Skip to content

Commit 082aef9

Browse files
Iulian Barbusandreim
authored andcommitted
serial: buffer limit fix with kick stdin evt
Signed-off-by: Iulian Barbu <[email protected]> Suggested-by: Andreea Florescu <[email protected]>
1 parent d506f57 commit 082aef9

File tree

6 files changed

+285
-63
lines changed

6 files changed

+285
-63
lines changed

src/devices/src/bus.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ pub trait RawIOHandler {
3636
fn raw_input(&mut self, _data: &[u8]) -> io::Result<()> {
3737
Ok(())
3838
}
39+
/// Query the device buffer, if any.
40+
fn avail_buffer_capacity(&mut self) -> usize {
41+
0
42+
}
3943
/// Receive raw output from this emulated device.
4044
fn raw_output(&mut self, _data: &mut [u8]) -> io::Result<()> {
4145
Ok(())

src/devices/src/legacy/serial.rs

Lines changed: 110 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use utils::eventfd::EventFd;
1313

1414
use crate::bus::{BusDevice, RawIOHandler};
1515

16-
const LOOP_SIZE: usize = 0x40;
16+
const FIFO_SIZE: usize = 64;
1717

1818
const DATA: u8 = 0;
1919
const IER: u8 = 1;
@@ -59,6 +59,7 @@ pub struct Serial {
5959
interrupt_enable: u8,
6060
interrupt_identification: u8,
6161
interrupt_evt: EventFd,
62+
buffer_ready_evt: Option<EventFd>,
6263
line_control: u8,
6364
line_status: u8,
6465
modem_control: u8,
@@ -70,11 +71,16 @@ pub struct Serial {
7071
}
7172

7273
impl Serial {
73-
fn new(interrupt_evt: EventFd, out: Option<Box<dyn io::Write + Send>>) -> Serial {
74+
fn new(
75+
interrupt_evt: EventFd,
76+
buffer_ready_evt: Option<EventFd>,
77+
out: Option<Box<dyn io::Write + Send>>,
78+
) -> Serial {
7479
Serial {
7580
interrupt_enable: 0,
7681
interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
7782
interrupt_evt,
83+
buffer_ready_evt,
7884
line_control: DEFAULT_LINE_CONTROL,
7985
line_status: DEFAULT_LINE_STATUS,
8086
modem_control: DEFAULT_MODEM_CONTROL,
@@ -87,13 +93,17 @@ impl Serial {
8793
}
8894

8995
/// Constructs a Serial port ready for output.
90-
pub fn new_out(interrupt_evt: EventFd, out: Box<dyn io::Write + Send>) -> Serial {
91-
Self::new(interrupt_evt, Some(out))
96+
pub fn new_out(
97+
interrupt_evt: EventFd,
98+
buffer_ready_evt: Option<EventFd>,
99+
out: Box<dyn io::Write + Send>,
100+
) -> Serial {
101+
Self::new(interrupt_evt, buffer_ready_evt, Some(out))
92102
}
93103

94104
/// Constructs a Serial port with no connected output.
95-
pub fn new_sink(interrupt_evt: EventFd) -> Serial {
96-
Self::new(interrupt_evt, None)
105+
pub fn new_sink(interrupt_evt: EventFd, buffer_ready_evt: Option<EventFd>) -> Serial {
106+
Self::new(interrupt_evt, buffer_ready_evt, None)
97107
}
98108

99109
fn is_dlab_set(&self) -> bool {
@@ -160,7 +170,7 @@ impl Serial {
160170
}
161171
DATA => {
162172
if self.is_loop() {
163-
if self.in_buffer.len() < LOOP_SIZE {
173+
if self.in_buffer.len() < FIFO_SIZE {
164174
self.in_buffer.push_back(value);
165175
self.recv_data()?;
166176
}
@@ -192,6 +202,12 @@ impl Serial {
192202
self.del_intr_bit(IIR_RECV_BIT);
193203
if self.in_buffer.len() <= 1 {
194204
self.line_status &= !LSR_DATA_BIT;
205+
if !self.is_loop() && self.in_buffer.len() == 1 {
206+
if let Some(evt) = self.buffer_ready_evt.as_ref() {
207+
evt.write(1)
208+
.expect("Couldn't signal that the serial device buffer is ready.");
209+
}
210+
}
195211
}
196212
METRICS.uart.read_count.inc();
197213
self.in_buffer.pop_front().unwrap_or_default()
@@ -214,12 +230,27 @@ impl Serial {
214230

215231
impl RawIOHandler for Serial {
216232
fn raw_input(&mut self, data: &[u8]) -> io::Result<()> {
233+
// Fail fast if the serial is serviced with more data than it can buffer.
234+
if data.len() > self.avail_buffer_capacity() {
235+
return Err(io::Error::from_raw_os_error(libc::ENOBUFS));
236+
}
237+
217238
if !self.is_loop() {
218239
self.in_buffer.extend(data);
219240
self.recv_data()?;
220241
}
221242
Ok(())
222243
}
244+
245+
fn avail_buffer_capacity(&mut self) -> usize {
246+
FIFO_SIZE.checked_sub(self.in_buffer.len()).unwrap_or_else(||
247+
panic!(
248+
"Errored out due to serial device buffer size greater than the maximum expected size: {} > {}.",
249+
self.in_buffer.len(),
250+
FIFO_SIZE
251+
)
252+
)
253+
}
223254
}
224255

225256
impl BusDevice for Serial {
@@ -277,7 +308,7 @@ mod tests {
277308
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
278309
let serial_out = SharedBuffer::new();
279310

280-
let mut serial = Serial::new_out(intr_evt, Box::new(serial_out.clone()));
311+
let mut serial = Serial::new_out(intr_evt, None, Box::new(serial_out.clone()));
281312

282313
serial.write(u64::from(DATA), &[b'x', b'y']);
283314
serial.write(u64::from(DATA), &[b'a']);
@@ -289,14 +320,47 @@ mod tests {
289320
);
290321
}
291322

323+
#[test]
324+
fn test_serial_buffer_ready() {
325+
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
326+
let buffer_ready_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
327+
let serial_out = SharedBuffer::new();
328+
329+
let mut serial = Serial::new_out(
330+
intr_evt,
331+
Some(buffer_ready_evt.try_clone().unwrap()),
332+
Box::new(serial_out.clone()),
333+
);
334+
335+
let byte = 5u8;
336+
serial.in_buffer.push_back(byte);
337+
let mut _dummy = [0u8; 1];
338+
serial.read(DATA as u64, &mut _dummy);
339+
assert_eq!(serial.buffer_ready_evt.as_ref().unwrap().read().unwrap(), 1);
340+
341+
let byte = 5u8;
342+
serial.in_buffer.push_back(byte);
343+
serial.in_buffer.push_back(byte);
344+
serial.in_buffer.push_back(byte);
345+
serial.read(DATA as u64, &mut _dummy);
346+
assert!(serial.buffer_ready_evt.as_ref().unwrap().read().is_err());
347+
serial.read(DATA as u64, &mut _dummy);
348+
assert!(serial.buffer_ready_evt.as_ref().unwrap().read().is_err());
349+
serial.read(DATA as u64, &mut _dummy);
350+
assert_eq!(serial.buffer_ready_evt.as_ref().unwrap().read().unwrap(), 1);
351+
}
352+
292353
#[test]
293354
fn serial_input() {
294355
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
295356
let serial_out = SharedBuffer::new();
296357
let mut buffer: Vec<u8> = Vec::with_capacity(16);
297358

298-
let mut serial =
299-
Serial::new_out(intr_evt.try_clone().unwrap(), Box::new(serial_out.clone()));
359+
let mut serial = Serial::new_out(
360+
intr_evt.try_clone().unwrap(),
361+
None,
362+
Box::new(serial_out.clone()),
363+
);
300364

301365
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
302366
// counter doesn't change (for 0 it blocks)
@@ -325,12 +389,16 @@ mod tests {
325389
// check if reading from the largest u8 offset returns 0
326390
serial.read(0xff, &mut data[..]);
327391
assert_eq!(data[0], 0);
392+
393+
// Check if the serial buffer can hold more than FIFO_SIZE bytes.
394+
let bytes = vec![0u8; FIFO_SIZE + 1];
395+
serial.raw_input(bytes.as_slice()).unwrap_err();
328396
}
329397

330398
#[test]
331399
fn serial_thr() {
332400
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
333-
let mut serial = Serial::new_sink(intr_evt.try_clone().unwrap());
401+
let mut serial = Serial::new_sink(intr_evt.try_clone().unwrap(), None);
334402

335403
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
336404
// counter doesn't change (for 0 it blocks)
@@ -348,7 +416,7 @@ mod tests {
348416

349417
#[test]
350418
fn serial_dlab() {
351-
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap());
419+
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap(), None);
352420

353421
serial.write(u64::from(LCR), &[LCR_DLAB_BIT as u8]);
354422
serial.write(u64::from(DLAB_LOW), &[0x12 as u8]);
@@ -365,7 +433,7 @@ mod tests {
365433

366434
#[test]
367435
fn serial_modem() {
368-
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap());
436+
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap(), None);
369437

370438
serial.write(u64::from(MCR), &[MCR_LOOP_BIT as u8]);
371439
serial.write(u64::from(DATA), &[b'a']);
@@ -387,7 +455,7 @@ mod tests {
387455

388456
#[test]
389457
fn serial_scratch() {
390-
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap());
458+
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap(), None);
391459

392460
serial.write(u64::from(SCR), &[0x12 as u8]);
393461

@@ -399,7 +467,7 @@ mod tests {
399467
#[test]
400468
fn test_serial_data_len() {
401469
const LEN: usize = 1;
402-
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap());
470+
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap(), None);
403471

404472
let missed_writes_before = METRICS.uart.missed_write_count.count();
405473
// Trying to write data of length different than the one that we initialized the device with
@@ -414,4 +482,31 @@ mod tests {
414482
// metric stays the same.
415483
assert_eq!(missed_writes_before, missed_writes_after - 1);
416484
}
485+
486+
#[test]
487+
fn test_serial_avail_buffer_capacity() {
488+
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap(), None);
489+
490+
let bytes = vec![0u8; FIFO_SIZE];
491+
serial.in_buffer.extend(bytes.clone());
492+
assert_eq!(serial.avail_buffer_capacity(), 0);
493+
494+
let mut data = [0u8; 1];
495+
for i in 0..FIFO_SIZE {
496+
assert_eq!(serial.avail_buffer_capacity(), i);
497+
serial.read(DATA as u64, &mut data);
498+
}
499+
assert_eq!(serial.avail_buffer_capacity(), FIFO_SIZE);
500+
}
501+
502+
#[test]
503+
#[should_panic]
504+
fn test_serial_avail_buffer_capacity_overflow() {
505+
let mut serial = Serial::new_sink(EventFd::new(libc::EFD_NONBLOCK).unwrap(), None);
506+
507+
let bytes = vec![0u8; FIFO_SIZE + 1];
508+
serial.in_buffer.extend(bytes);
509+
// Panic since serial device buffer size its greater than what is expected.
510+
serial.avail_buffer_capacity();
511+
}
417512
}

src/vmm/src/device_manager/legacy.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,22 @@ pub struct PortIODeviceManager {
4242
pub io_bus: devices::Bus,
4343
pub stdio_serial: Arc<Mutex<devices::legacy::Serial>>,
4444
pub i8042: Arc<Mutex<devices::legacy::I8042Device>>,
45-
4645
pub com_evt_1_3: EventFd,
4746
pub com_evt_2_4: EventFd,
4847
pub kbd_evt: EventFd,
4948
}
5049

5150
impl PortIODeviceManager {
5251
/// Create a new DeviceManager handling legacy devices (uart, i8042).
53-
pub fn new() -> Result<Self> {
52+
pub fn new(kick_stdin_read_evt: EventFd) -> Result<Self> {
5453
let io_bus = devices::Bus::new();
5554
let com_evt_1_3 = EventFd::new(libc::EFD_NONBLOCK).map_err(Error::EventFd)?;
5655
let com_evt_2_4 = EventFd::new(libc::EFD_NONBLOCK).map_err(Error::EventFd)?;
5756
let kbd_evt = EventFd::new(libc::EFD_NONBLOCK).map_err(Error::EventFd)?;
57+
5858
let stdio_serial = Arc::new(Mutex::new(devices::legacy::Serial::new_out(
5959
com_evt_1_3.try_clone().map_err(Error::EventFd)?,
60+
Some(kick_stdin_read_evt),
6061
Box::new(stdout()),
6162
)));
6263

@@ -87,6 +88,7 @@ impl PortIODeviceManager {
8788
.insert(
8889
Arc::new(Mutex::new(devices::legacy::Serial::new_sink(
8990
self.com_evt_2_4.try_clone().map_err(Error::EventFd)?,
91+
None,
9092
))),
9193
0x2f8,
9294
0x8,
@@ -96,6 +98,7 @@ impl PortIODeviceManager {
9698
.insert(
9799
Arc::new(Mutex::new(devices::legacy::Serial::new_sink(
98100
self.com_evt_1_3.try_clone().map_err(Error::EventFd)?,
101+
None,
99102
))),
100103
0x3e8,
101104
0x8,
@@ -105,6 +108,7 @@ impl PortIODeviceManager {
105108
.insert(
106109
Arc::new(Mutex::new(devices::legacy::Serial::new_sink(
107110
self.com_evt_2_4.try_clone().map_err(Error::EventFd)?,
111+
None,
108112
))),
109113
0x2e8,
110114
0x8,
@@ -124,7 +128,7 @@ mod tests {
124128
#[test]
125129
#[cfg(target_arch = "x86_64")]
126130
fn test_register_legacy_devices() {
127-
let ldm = PortIODeviceManager::new();
131+
let ldm = PortIODeviceManager::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
128132
assert!(ldm.is_ok());
129133
assert!(&ldm.unwrap().register_devices().is_ok());
130134
}

src/vmm/src/device_manager/mmio.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ impl MMIODeviceManager {
173173
pub fn register_mmio_serial(
174174
&mut self,
175175
vm: &VmFd,
176+
kick_stdin_read_evt: EventFd,
176177
cmdline: &mut kernel_cmdline::Cmdline,
177178
) -> Result<()> {
178179
if self.irq > self.last_irq {
@@ -182,6 +183,7 @@ impl MMIODeviceManager {
182183
let com_evt = EventFd::new(libc::EFD_NONBLOCK).map_err(Error::EventFd)?;
183184
let device = devices::legacy::Serial::new_out(
184185
com_evt.try_clone().map_err(Error::EventFd)?,
186+
Some(kick_stdin_read_evt),
185187
Box::new(io::stdout()),
186188
);
187189

0 commit comments

Comments
 (0)