xref: /cloud-hypervisor/devices/src/legacy/serial.rs (revision 19d36c765fdf00be749d95b3e61028bc302d6d73)
1 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style license that can be
6 // found in the LICENSE-BSD-3-Clause file.
7 
8 use std::collections::VecDeque;
9 use std::sync::{Arc, Barrier};
10 use std::{io, result};
11 
12 use serde::{Deserialize, Serialize};
13 use vm_device::interrupt::InterruptSourceGroup;
14 use vm_device::BusDevice;
15 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
16 use vmm_sys_util::errno::Result;
17 
18 const LOOP_SIZE: usize = 0x40;
19 
20 const DATA: u8 = 0;
21 const IER: u8 = 1;
22 const IIR: u8 = 2;
23 const LCR: u8 = 3;
24 const MCR: u8 = 4;
25 const LSR: u8 = 5;
26 const MSR: u8 = 6;
27 const SCR: u8 = 7;
28 
29 const DLAB_LOW: u8 = 0;
30 const DLAB_HIGH: u8 = 1;
31 
32 const IER_RECV_BIT: u8 = 0x1;
33 const IER_THR_BIT: u8 = 0x2;
34 const IER_FIFO_BITS: u8 = 0x0f;
35 
36 const IIR_FIFO_BITS: u8 = 0xc0;
37 const IIR_NONE_BIT: u8 = 0x1;
38 const IIR_THR_BIT: u8 = 0x2;
39 const IIR_RECV_BIT: u8 = 0x4;
40 
41 const LCR_DLAB_BIT: u8 = 0x80;
42 
43 const LSR_DATA_BIT: u8 = 0x1;
44 const LSR_EMPTY_BIT: u8 = 0x20;
45 const LSR_IDLE_BIT: u8 = 0x40;
46 
47 const MCR_LOOP_BIT: u8 = 0x10;
48 
49 const DEFAULT_INTERRUPT_IDENTIFICATION: u8 = IIR_NONE_BIT; // no pending interrupt
50 const DEFAULT_LINE_STATUS: u8 = LSR_EMPTY_BIT | LSR_IDLE_BIT; // THR empty and line is idle
51 const DEFAULT_LINE_CONTROL: u8 = 0x3; // 8-bits per character
52 const DEFAULT_MODEM_CONTROL: u8 = 0x8; // Auxiliary output 2
53 const DEFAULT_MODEM_STATUS: u8 = 0x20 | 0x10 | 0x80; // data ready, clear to send, carrier detect
54 const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps
55 
56 /// Emulates serial COM ports commonly seen on x86 I/O ports 0x3f8/0x2f8/0x3e8/0x2e8.
57 ///
58 /// This can optionally write the guest's output to a Write trait object. To send input to the
59 /// guest, use `queue_input_bytes`.
60 pub struct Serial {
61     id: String,
62     interrupt_enable: u8,
63     interrupt_identification: u8,
64     line_control: u8,
65     line_status: u8,
66     modem_control: u8,
67     modem_status: u8,
68     scratch: u8,
69     baud_divisor: u16,
70     in_buffer: VecDeque<u8>,
71     interrupt: Arc<dyn InterruptSourceGroup>,
72     out: Option<Box<dyn io::Write + Send>>,
73 }
74 
75 #[derive(Serialize, Deserialize)]
76 pub struct SerialState {
77     interrupt_enable: u8,
78     interrupt_identification: u8,
79     line_control: u8,
80     line_status: u8,
81     modem_control: u8,
82     modem_status: u8,
83     scratch: u8,
84     baud_divisor: u16,
85     in_buffer: Vec<u8>,
86 }
87 
88 impl Serial {
89     pub fn new(
90         id: String,
91         interrupt: Arc<dyn InterruptSourceGroup>,
92         out: Option<Box<dyn io::Write + Send>>,
93         state: Option<SerialState>,
94     ) -> Serial {
95         let (
96             interrupt_enable,
97             interrupt_identification,
98             line_control,
99             line_status,
100             modem_control,
101             modem_status,
102             scratch,
103             baud_divisor,
104             in_buffer,
105         ) = if let Some(state) = state {
106             (
107                 state.interrupt_enable,
108                 state.interrupt_identification,
109                 state.line_control,
110                 state.line_status,
111                 state.modem_control,
112                 state.modem_status,
113                 state.scratch,
114                 state.baud_divisor,
115                 state.in_buffer.into(),
116             )
117         } else {
118             (
119                 0,
120                 DEFAULT_INTERRUPT_IDENTIFICATION,
121                 DEFAULT_LINE_CONTROL,
122                 DEFAULT_LINE_STATUS,
123                 DEFAULT_MODEM_CONTROL,
124                 DEFAULT_MODEM_STATUS,
125                 0,
126                 DEFAULT_BAUD_DIVISOR,
127                 VecDeque::new(),
128             )
129         };
130 
131         Serial {
132             id,
133             interrupt_enable,
134             interrupt_identification,
135             line_control,
136             line_status,
137             modem_control,
138             modem_status,
139             scratch,
140             baud_divisor,
141             in_buffer,
142             interrupt,
143             out,
144         }
145     }
146 
147     /// Constructs a Serial port ready for output.
148     pub fn new_out(
149         id: String,
150         interrupt: Arc<dyn InterruptSourceGroup>,
151         out: Box<dyn io::Write + Send>,
152         state: Option<SerialState>,
153     ) -> Serial {
154         Self::new(id, interrupt, Some(out), state)
155     }
156 
157     /// Constructs a Serial port with no connected output.
158     pub fn new_sink(
159         id: String,
160         interrupt: Arc<dyn InterruptSourceGroup>,
161         state: Option<SerialState>,
162     ) -> Serial {
163         Self::new(id, interrupt, None, state)
164     }
165 
166     pub fn set_out(&mut self, out: Option<Box<dyn io::Write + Send>>) {
167         self.out = out;
168     }
169 
170     /// Queues raw bytes for the guest to read and signals the interrupt if the line status would
171     /// change.
172     pub fn queue_input_bytes(&mut self, c: &[u8]) -> Result<()> {
173         if !self.is_loop() {
174             self.in_buffer.extend(c);
175             self.recv_data()?;
176         }
177         Ok(())
178     }
179 
180     pub fn flush_output(&mut self) -> result::Result<(), io::Error> {
181         if let Some(out) = self.out.as_mut() {
182             out.flush()?;
183         }
184         Ok(())
185     }
186 
187     fn is_dlab_set(&self) -> bool {
188         (self.line_control & LCR_DLAB_BIT) != 0
189     }
190 
191     fn is_recv_intr_enabled(&self) -> bool {
192         (self.interrupt_enable & IER_RECV_BIT) != 0
193     }
194 
195     fn is_thr_intr_enabled(&self) -> bool {
196         (self.interrupt_enable & IER_THR_BIT) != 0
197     }
198 
199     fn is_loop(&self) -> bool {
200         (self.modem_control & MCR_LOOP_BIT) != 0
201     }
202 
203     fn add_intr_bit(&mut self, bit: u8) {
204         self.interrupt_identification &= !IIR_NONE_BIT;
205         self.interrupt_identification |= bit;
206     }
207 
208     fn del_intr_bit(&mut self, bit: u8) {
209         self.interrupt_identification &= !bit;
210         if self.interrupt_identification == 0x0 {
211             self.interrupt_identification = IIR_NONE_BIT;
212         }
213     }
214 
215     fn thr_empty(&mut self) -> Result<()> {
216         if self.is_thr_intr_enabled() {
217             self.add_intr_bit(IIR_THR_BIT);
218             self.trigger_interrupt()?
219         }
220         Ok(())
221     }
222 
223     fn recv_data(&mut self) -> Result<()> {
224         if self.is_recv_intr_enabled() {
225             self.add_intr_bit(IIR_RECV_BIT);
226             self.trigger_interrupt()?
227         }
228         self.line_status |= LSR_DATA_BIT;
229         Ok(())
230     }
231 
232     fn trigger_interrupt(&mut self) -> result::Result<(), io::Error> {
233         self.interrupt.trigger(0)
234     }
235 
236     fn iir_reset(&mut self) {
237         self.interrupt_identification = DEFAULT_INTERRUPT_IDENTIFICATION;
238     }
239 
240     fn handle_write(&mut self, offset: u8, v: u8) -> Result<()> {
241         match offset {
242             DLAB_LOW if self.is_dlab_set() => {
243                 self.baud_divisor = (self.baud_divisor & 0xff00) | u16::from(v)
244             }
245             DLAB_HIGH if self.is_dlab_set() => {
246                 self.baud_divisor = (self.baud_divisor & 0x00ff) | ((u16::from(v)) << 8)
247             }
248             DATA => {
249                 if self.is_loop() {
250                     if self.in_buffer.len() < LOOP_SIZE {
251                         self.in_buffer.push_back(v);
252                         self.recv_data()?;
253                     }
254                 } else {
255                     if let Some(out) = self.out.as_mut() {
256                         out.write_all(&[v])?;
257                         out.flush()?;
258                     }
259                     self.thr_empty()?;
260                 }
261             }
262             IER => self.interrupt_enable = v & IER_FIFO_BITS,
263             LCR => self.line_control = v,
264             MCR => self.modem_control = v,
265             SCR => self.scratch = v,
266             _ => {}
267         }
268         Ok(())
269     }
270 
271     fn state(&self) -> SerialState {
272         SerialState {
273             interrupt_enable: self.interrupt_enable,
274             interrupt_identification: self.interrupt_identification,
275             line_control: self.line_control,
276             line_status: self.line_status,
277             modem_control: self.modem_control,
278             modem_status: self.modem_status,
279             scratch: self.scratch,
280             baud_divisor: self.baud_divisor,
281             in_buffer: self.in_buffer.clone().into(),
282         }
283     }
284 }
285 
286 impl BusDevice for Serial {
287     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
288         if data.len() != 1 {
289             return;
290         }
291 
292         data[0] = match offset as u8 {
293             DLAB_LOW if self.is_dlab_set() => self.baud_divisor as u8,
294             DLAB_HIGH if self.is_dlab_set() => (self.baud_divisor >> 8) as u8,
295             DATA => {
296                 self.del_intr_bit(IIR_RECV_BIT);
297                 if self.in_buffer.len() <= 1 {
298                     self.line_status &= !LSR_DATA_BIT;
299                 }
300                 self.in_buffer.pop_front().unwrap_or_default()
301             }
302             IER => self.interrupt_enable,
303             IIR => {
304                 let v = self.interrupt_identification | IIR_FIFO_BITS;
305                 self.iir_reset();
306                 v
307             }
308             LCR => self.line_control,
309             MCR => self.modem_control,
310             LSR => self.line_status,
311             MSR => self.modem_status,
312             SCR => self.scratch,
313             _ => 0,
314         };
315     }
316 
317     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
318         if data.len() != 1 {
319             return None;
320         }
321 
322         self.handle_write(offset as u8, data[0]).ok();
323 
324         None
325     }
326 }
327 
328 impl Snapshottable for Serial {
329     fn id(&self) -> String {
330         self.id.clone()
331     }
332 
333     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
334         Snapshot::new_from_state(&self.state())
335     }
336 }
337 
338 impl Pausable for Serial {}
339 impl Transportable for Serial {}
340 impl Migratable for Serial {}
341 
342 #[cfg(test)]
343 mod tests {
344     use std::sync::Mutex;
345 
346     use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
347     use vmm_sys_util::eventfd::EventFd;
348 
349     use super::*;
350 
351     const SERIAL_NAME: &str = "serial";
352 
353     struct TestInterrupt {
354         event_fd: EventFd,
355     }
356 
357     impl InterruptSourceGroup for TestInterrupt {
358         fn trigger(&self, _index: InterruptIndex) -> result::Result<(), std::io::Error> {
359             self.event_fd.write(1)
360         }
361         fn update(
362             &self,
363             _index: InterruptIndex,
364             _config: InterruptSourceConfig,
365             _masked: bool,
366             _set_gsi: bool,
367         ) -> result::Result<(), std::io::Error> {
368             Ok(())
369         }
370         fn set_gsi(&self) -> result::Result<(), std::io::Error> {
371             Ok(())
372         }
373         fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
374             Some(self.event_fd.try_clone().unwrap())
375         }
376     }
377 
378     impl TestInterrupt {
379         fn new(event_fd: EventFd) -> Self {
380             TestInterrupt { event_fd }
381         }
382     }
383 
384     #[derive(Clone)]
385     struct SharedBuffer {
386         buf: Arc<Mutex<Vec<u8>>>,
387     }
388 
389     impl SharedBuffer {
390         fn new() -> SharedBuffer {
391             SharedBuffer {
392                 buf: Arc::new(Mutex::new(Vec::new())),
393             }
394         }
395     }
396 
397     impl io::Write for SharedBuffer {
398         fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
399             self.buf.lock().unwrap().write(buf)
400         }
401         fn flush(&mut self) -> io::Result<()> {
402             self.buf.lock().unwrap().flush()
403         }
404     }
405 
406     #[test]
407     fn serial_output() {
408         let intr_evt = EventFd::new(0).unwrap();
409         let serial_out = SharedBuffer::new();
410         let mut serial = Serial::new_out(
411             String::from(SERIAL_NAME),
412             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
413             Box::new(serial_out.clone()),
414             None,
415         );
416 
417         serial.write(0, DATA as u64, b"xy");
418         serial.write(0, DATA as u64, b"a");
419         serial.write(0, DATA as u64, b"b");
420         serial.write(0, DATA as u64, b"c");
421         assert_eq!(serial_out.buf.lock().unwrap().as_slice(), b"abc");
422     }
423 
424     #[test]
425     fn serial_input() {
426         let intr_evt = EventFd::new(0).unwrap();
427         let serial_out = SharedBuffer::new();
428         let mut serial = Serial::new_out(
429             String::from(SERIAL_NAME),
430             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
431             Box::new(serial_out),
432             None,
433         );
434 
435         // write 1 to the interrupt event fd, so that read doesn't block in case the event fd
436         // counter doesn't change (for 0 it blocks)
437         assert!(intr_evt.write(1).is_ok());
438         serial.write(0, IER as u64, &[IER_RECV_BIT]);
439         serial.queue_input_bytes(b"abc").unwrap();
440 
441         assert_eq!(intr_evt.read().unwrap(), 2);
442 
443         // check if reading in a 2-length array doesn't have side effects
444         let mut data = [0u8, 0u8];
445         serial.read(0, DATA as u64, &mut data[..]);
446         assert_eq!(data, [0u8, 0u8]);
447 
448         let mut data = [0u8];
449         serial.read(0, LSR as u64, &mut data[..]);
450         assert_ne!(data[0] & LSR_DATA_BIT, 0);
451         serial.read(0, DATA as u64, &mut data[..]);
452         assert_eq!(data[0], b'a');
453         serial.read(0, DATA as u64, &mut data[..]);
454         assert_eq!(data[0], b'b');
455         serial.read(0, DATA as u64, &mut data[..]);
456         assert_eq!(data[0], b'c');
457 
458         // check if reading from the largest u8 offset returns 0
459         serial.read(0, 0xff, &mut data[..]);
460         assert_eq!(data[0], 0);
461     }
462 
463     #[test]
464     fn serial_thr() {
465         let intr_evt = EventFd::new(0).unwrap();
466         let mut serial = Serial::new_sink(
467             String::from(SERIAL_NAME),
468             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
469             None,
470         );
471 
472         // write 1 to the interrupt event fd, so that read doesn't block in case the event fd
473         // counter doesn't change (for 0 it blocks)
474         assert!(intr_evt.write(1).is_ok());
475         serial.write(0, IER as u64, &[IER_THR_BIT]);
476         serial.write(0, DATA as u64, b"a");
477 
478         assert_eq!(intr_evt.read().unwrap(), 2);
479         let mut data = [0u8];
480         serial.read(0, IER as u64, &mut data[..]);
481         assert_eq!(data[0] & IER_FIFO_BITS, IER_THR_BIT);
482         serial.read(0, IIR as u64, &mut data[..]);
483         assert_ne!(data[0] & IIR_THR_BIT, 0);
484     }
485 
486     #[test]
487     fn serial_dlab() {
488         let intr_evt = EventFd::new(0).unwrap();
489         let mut serial = Serial::new_sink(
490             String::from(SERIAL_NAME),
491             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
492             None,
493         );
494 
495         serial.write(0, LCR as u64, &[LCR_DLAB_BIT]);
496         serial.write(0, DLAB_LOW as u64, &[0x12]);
497         serial.write(0, DLAB_HIGH as u64, &[0x34]);
498 
499         let mut data = [0u8];
500         serial.read(0, LCR as u64, &mut data[..]);
501         assert_eq!(data[0], LCR_DLAB_BIT);
502         serial.read(0, DLAB_LOW as u64, &mut data[..]);
503         assert_eq!(data[0], 0x12);
504         serial.read(0, DLAB_HIGH as u64, &mut data[..]);
505         assert_eq!(data[0], 0x34);
506     }
507 
508     #[test]
509     fn serial_modem() {
510         let intr_evt = EventFd::new(0).unwrap();
511         let mut serial = Serial::new_sink(
512             String::from(SERIAL_NAME),
513             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
514             None,
515         );
516 
517         serial.write(0, MCR as u64, &[MCR_LOOP_BIT]);
518         serial.write(0, DATA as u64, b"a");
519         serial.write(0, DATA as u64, b"b");
520         serial.write(0, DATA as u64, b"c");
521 
522         let mut data = [0u8];
523         serial.read(0, MSR as u64, &mut data[..]);
524         assert_eq!(data[0], DEFAULT_MODEM_STATUS);
525         serial.read(0, MCR as u64, &mut data[..]);
526         assert_eq!(data[0], MCR_LOOP_BIT);
527         serial.read(0, DATA as u64, &mut data[..]);
528         assert_eq!(data[0], b'a');
529         serial.read(0, DATA as u64, &mut data[..]);
530         assert_eq!(data[0], b'b');
531         serial.read(0, DATA as u64, &mut data[..]);
532         assert_eq!(data[0], b'c');
533     }
534 
535     #[test]
536     fn serial_scratch() {
537         let intr_evt = EventFd::new(0).unwrap();
538         let mut serial = Serial::new_sink(
539             String::from(SERIAL_NAME),
540             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
541             None,
542         );
543 
544         serial.write(0, SCR as u64, &[0x12]);
545 
546         let mut data = [0u8];
547         serial.read(0, SCR as u64, &mut data[..]);
548         assert_eq!(data[0], 0x12);
549     }
550 }
551