1use std::fmt::Debug;
10use std::fs::File;
11use std::io::{self, Read, Stdin, Write};
12use std::os::unix::io::{AsRawFd, RawFd};
13use std::sync::{Arc, Barrier};
14
15use event_manager::{EventOps, Events, MutEventSubscriber};
16use libc::EFD_NONBLOCK;
17use log::{error, warn};
18use serde::Serialize;
19use vm_superio::serial::{Error as SerialError, SerialEvents};
20use vm_superio::{Serial, Trigger};
21use vmm_sys_util::epoll::EventSet;
22use vmm_sys_util::eventfd::EventFd;
23
24use crate::devices::legacy::EventFdTrigger;
25use crate::logger::{IncMetric, SharedIncMetric};
26use crate::vstate::bus::BusDevice;
27
28pub const IER_RDA_BIT: u8 = 0b0000_0001;
31pub const IER_RDA_OFFSET: u8 = 1;
33
34#[derive(Debug, Serialize, Default)]
36pub struct SerialDeviceMetrics {
37 pub error_count: SharedIncMetric,
39 pub flush_count: SharedIncMetric,
41 pub missed_read_count: SharedIncMetric,
43 pub missed_write_count: SharedIncMetric,
45 pub read_count: SharedIncMetric,
47 pub write_count: SharedIncMetric,
49}
50impl SerialDeviceMetrics {
51 pub const fn new() -> Self {
53 Self {
54 error_count: SharedIncMetric::new(),
55 flush_count: SharedIncMetric::new(),
56 missed_read_count: SharedIncMetric::new(),
57 missed_write_count: SharedIncMetric::new(),
58 read_count: SharedIncMetric::new(),
59 write_count: SharedIncMetric::new(),
60 }
61 }
62}
63
64pub(super) static METRICS: SerialDeviceMetrics = SerialDeviceMetrics::new();
66
67#[derive(Debug, thiserror::Error, displaydoc::Display)]
68pub enum RawIOError {
69 Serial(SerialError<io::Error>),
71}
72
73pub trait RawIOHandler {
74 fn raw_input(&mut self, _data: &[u8]) -> Result<(), RawIOError>;
76}
77
78impl<EV: SerialEvents + Debug, W: Write + Debug> RawIOHandler for Serial<EventFdTrigger, EV, W> {
79 fn raw_input(&mut self, data: &[u8]) -> Result<(), RawIOError> {
81 if data.len() > self.fifo_capacity() {
83 return Err(RawIOError::Serial(SerialError::FullFifo));
84 }
85
86 if self.fifo_capacity() >= data.len() {
89 self.enqueue_raw_bytes(data).map_err(RawIOError::Serial)?;
90 }
91 Ok(())
92 }
93}
94
95#[derive(Debug)]
97pub struct SerialEventsWrapper {
98 pub buffer_ready_event_fd: Option<EventFdTrigger>,
100}
101
102impl SerialEvents for SerialEventsWrapper {
103 fn buffer_read(&self) {
104 METRICS.read_count.inc();
105 }
106
107 fn out_byte(&self) {
108 METRICS.write_count.inc();
109 }
110
111 fn tx_lost_byte(&self) {
112 METRICS.missed_write_count.inc();
113 }
114
115 fn in_buffer_empty(&self) {
116 match self
117 .buffer_ready_event_fd
118 .as_ref()
119 .map_or(Ok(()), |buf_ready| buf_ready.write(1))
120 {
121 Ok(_) => (),
122 Err(err) => error!(
123 "Could not signal that serial device buffer is ready: {:?}",
124 err
125 ),
126 }
127 }
128}
129
130#[derive(Debug)]
131pub enum SerialOut {
132 Sink,
133 Stdout(std::io::Stdout),
134 File(File),
135}
136impl std::io::Write for SerialOut {
137 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
138 match self {
139 Self::Sink => Ok(buf.len()),
140 Self::Stdout(stdout) => stdout.write(buf),
141 Self::File(file) => file.write(buf),
142 }
143 }
144 fn flush(&mut self) -> std::io::Result<()> {
145 match self {
146 Self::Sink => Ok(()),
147 Self::Stdout(stdout) => stdout.flush(),
148 Self::File(file) => file.flush(),
149 }
150 }
151}
152
153#[derive(Debug)]
155pub struct SerialWrapper<T: Trigger, EV: SerialEvents, I: Read + AsRawFd + Send> {
156 pub serial: Serial<T, EV, SerialOut>,
158 pub input: Option<I>,
160}
161
162impl<I: Read + AsRawFd + Send + Debug> SerialWrapper<EventFdTrigger, SerialEventsWrapper, I> {
163 fn handle_ewouldblock(&self, ops: &mut EventOps) {
164 let buffer_ready_fd = self.buffer_ready_evt_fd();
165 let input_fd = self.serial_input_fd();
166 if input_fd < 0 || buffer_ready_fd < 0 {
167 error!("Serial does not have a configured input source.");
168 return;
169 }
170 match ops.add(Events::new(&input_fd, EventSet::IN)) {
171 Err(event_manager::Error::FdAlreadyRegistered) => (),
172 Err(err) => {
173 error!(
174 "Could not register the serial input to the event manager: {:?}",
175 err
176 );
177 }
178 Ok(()) => {
179 self.serial.events().in_buffer_empty()
181 }
182 };
183 }
184
185 fn recv_bytes(&mut self) -> io::Result<usize> {
186 let avail_cap = self.serial.fifo_capacity();
187 if avail_cap == 0 {
188 return Err(io::Error::from_raw_os_error(libc::ENOBUFS));
189 }
190
191 if let Some(input) = self.input.as_mut() {
192 let mut out = vec![0u8; avail_cap];
193 let count = input.read(&mut out)?;
194 if count > 0 {
195 self.serial
196 .raw_input(&out[..count])
197 .map_err(|_| io::Error::from_raw_os_error(libc::ENOBUFS))?;
198 }
199
200 return Ok(count);
201 }
202
203 Err(io::Error::from_raw_os_error(libc::ENOTTY))
204 }
205
206 #[inline]
207 fn buffer_ready_evt_fd(&self) -> RawFd {
208 self.serial
209 .events()
210 .buffer_ready_event_fd
211 .as_ref()
212 .map_or(-1, |buf_ready| buf_ready.as_raw_fd())
213 }
214
215 #[inline]
216 fn serial_input_fd(&self) -> RawFd {
217 self.input.as_ref().map_or(-1, |input| input.as_raw_fd())
218 }
219
220 fn consume_buffer_ready_event(&self) -> io::Result<u64> {
221 self.serial
222 .events()
223 .buffer_ready_event_fd
224 .as_ref()
225 .map_or(Ok(0), |buf_ready| buf_ready.read())
226 }
227}
228
229pub type SerialDevice = SerialWrapper<EventFdTrigger, SerialEventsWrapper, Stdin>;
231
232impl SerialDevice {
233 pub fn new(serial_in: Option<Stdin>, serial_out: SerialOut) -> Result<Self, std::io::Error> {
234 let interrupt_evt = EventFdTrigger::new(EventFd::new(EFD_NONBLOCK)?);
235 let buffer_read_event_fd = EventFdTrigger::new(EventFd::new(EFD_NONBLOCK)?);
236
237 let serial = Serial::with_events(
238 interrupt_evt,
239 SerialEventsWrapper {
240 buffer_ready_event_fd: Some(buffer_read_event_fd),
241 },
242 serial_out,
243 );
244
245 Ok(SerialDevice {
246 serial,
247 input: serial_in,
248 })
249 }
250}
251
252impl<I: Read + AsRawFd + Send + Debug> MutEventSubscriber
253 for SerialWrapper<EventFdTrigger, SerialEventsWrapper, I>
254{
255 fn process(&mut self, event: Events, ops: &mut EventOps) {
257 #[inline]
258 fn unregister_source<T: AsRawFd + Debug>(ops: &mut EventOps, source: &T) {
259 match ops.remove(Events::new(source, EventSet::IN)) {
260 Ok(_) => (),
261 Err(_) => error!("Could not unregister source fd: {}", source.as_raw_fd()),
262 }
263 }
264
265 let input_fd = self.serial_input_fd();
266 let buffer_ready_fd = self.buffer_ready_evt_fd();
267 if input_fd < 0 || buffer_ready_fd < 0 {
268 error!("Serial does not have a configured input source.");
269 return;
270 }
271
272 if buffer_ready_fd == event.fd() {
273 match self.consume_buffer_ready_event() {
274 Ok(_) => (),
275 Err(err) => {
276 error!(
277 "Detach serial device input source due to error in consuming the buffer \
278 ready event: {:?}",
279 err
280 );
281 unregister_source(ops, &input_fd);
282 unregister_source(ops, &buffer_ready_fd);
283 return;
284 }
285 }
286 }
287
288 match self.recv_bytes() {
292 Ok(count) => {
293 if input_fd == event.fd() && count == 0 {
295 unregister_source(ops, &input_fd);
296 unregister_source(ops, &buffer_ready_fd);
297 warn!("Detached the serial input due to peer close/error.");
298 }
299 }
300 Err(err) => {
301 match err.raw_os_error() {
302 Some(errno) if errno == libc::ENOBUFS => {
303 unregister_source(ops, &input_fd);
304 }
305 Some(errno) if errno == libc::EWOULDBLOCK => {
306 self.handle_ewouldblock(ops);
307 }
308 Some(errno) if errno == libc::ENOTTY => {
309 error!("The serial device does not have the input source attached.");
310 unregister_source(ops, &input_fd);
311 unregister_source(ops, &buffer_ready_fd);
312 }
313 Some(_) | None => {
314 unregister_source(ops, &input_fd);
316 unregister_source(ops, &buffer_ready_fd);
317 warn!("Detached the serial input due to peer close/error.");
318 }
319 }
320 }
321 }
322 }
323
324 fn init(&mut self, ops: &mut EventOps) {
327 if self.input.is_some() && self.serial.events().buffer_ready_event_fd.is_some() {
328 let serial_fd = self.serial_input_fd();
329 let buf_ready_evt = self.buffer_ready_evt_fd();
330
331 if (unsafe { libc::isatty(serial_fd) } == 1 || is_fifo(serial_fd))
338 && let Err(err) = ops.add(Events::new(&serial_fd, EventSet::IN))
339 {
340 warn!("Failed to register serial input fd: {}", err);
341 }
342 if let Err(err) = ops.add(Events::new(&buf_ready_evt, EventSet::IN)) {
343 warn!("Failed to register serial buffer ready event: {}", err);
344 }
345 }
346 }
347}
348
349fn is_fifo(fd: RawFd) -> bool {
351 let mut stat = std::mem::MaybeUninit::<libc::stat>::uninit();
352
353 if unsafe { libc::fstat(fd, stat.as_mut_ptr()) } < 0 {
357 return false;
358 }
359
360 let stat = unsafe { stat.assume_init() };
363
364 (stat.st_mode & libc::S_IFIFO) != 0
365}
366
367impl<I> BusDevice for SerialWrapper<EventFdTrigger, SerialEventsWrapper, I>
368where
369 I: Read + AsRawFd + Send,
370{
371 fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
372 if let (Ok(offset), 1) = (u8::try_from(offset), data.len()) {
373 data[0] = self.serial.read(offset);
374 } else {
375 METRICS.missed_read_count.inc();
376 }
377 }
378
379 fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
380 if let (Ok(offset), 1) = (u8::try_from(offset), data.len()) {
381 if let Err(err) = self.serial.write(offset, data[0]) {
382 error!("Failed the write to serial: {:?}", err);
384 METRICS.error_count.inc();
385 }
386 } else {
387 METRICS.missed_write_count.inc();
388 }
389 None
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 #![allow(clippy::undocumented_unsafe_blocks)]
396
397 use vmm_sys_util::eventfd::EventFd;
398
399 use super::*;
400 use crate::logger::IncMetric;
401
402 #[test]
403 fn test_serial_bus_read() {
404 let intr_evt = EventFdTrigger::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
405
406 let metrics = &METRICS;
407
408 let mut serial = SerialDevice {
409 serial: Serial::with_events(
410 intr_evt,
411 SerialEventsWrapper {
412 buffer_ready_event_fd: None,
413 },
414 SerialOut::Sink,
415 ),
416 input: None::<std::io::Stdin>,
417 };
418 serial.serial.raw_input(b"abc").unwrap();
419
420 let invalid_reads_before = metrics.missed_read_count.count();
421 let mut v = [0x00; 2];
422 serial.read(0x0, 0u64, &mut v);
423
424 let invalid_reads_after = metrics.missed_read_count.count();
425 assert_eq!(invalid_reads_before + 1, invalid_reads_after);
426
427 let mut v = [0x00; 1];
428 serial.read(0x0, 0u64, &mut v);
429 assert_eq!(v[0], b'a');
430
431 let invalid_reads_after_2 = metrics.missed_read_count.count();
432 assert_eq!(invalid_reads_after_2, invalid_reads_after);
434 }
435
436 #[test]
437 fn test_is_fifo() {
438 let invalid = -1;
440 assert!(!is_fifo(invalid));
441
442 let mut fds: [libc::c_int; 2] = [0; 2];
444 let rc = unsafe { libc::pipe(fds.as_mut_ptr()) };
445 assert!(rc == 0);
446
447 assert!(is_fifo(fds[0]));
448 assert!(is_fifo(fds[1]));
449
450 let tmp_file = vmm_sys_util::tempfile::TempFile::new().unwrap();
452 assert!(!is_fifo(tmp_file.as_file().as_raw_fd()));
453 }
454
455 #[test]
456 fn test_serial_dev_metrics() {
457 let serial_metrics: SerialDeviceMetrics = SerialDeviceMetrics::new();
458 let serial_metrics_local: String = serde_json::to_string(&serial_metrics).unwrap();
459 serde_json::to_string(&METRICS).unwrap();
462 let serial_metrics_global: String = serde_json::to_string(&METRICS).unwrap();
463 assert_eq!(serial_metrics_local, serial_metrics_global);
464 serial_metrics.read_count.inc();
465 assert_eq!(serial_metrics.read_count.count(), 1);
466 }
467}