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