• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::collections::VecDeque;
6 use std::fmt::{self, Display};
7 use std::fs::File;
8 use std::io::{self, stdout};
9 use std::path::PathBuf;
10 use std::str::FromStr;
11 
12 use sys_util::{error, syslog, EventFd, Result};
13 
14 use crate::BusDevice;
15 
16 const LOOP_SIZE: usize = 0x40;
17 
18 const DATA: u8 = 0;
19 const IER: u8 = 1;
20 const IIR: u8 = 2;
21 const LCR: u8 = 3;
22 const MCR: u8 = 4;
23 const LSR: u8 = 5;
24 const MSR: u8 = 6;
25 const SCR: u8 = 7;
26 const DLAB_LOW: u8 = 0;
27 const DLAB_HIGH: u8 = 1;
28 
29 const IER_RECV_BIT: u8 = 0x1;
30 const IER_THR_BIT: u8 = 0x2;
31 const IER_FIFO_BITS: u8 = 0x0f;
32 
33 const IIR_FIFO_BITS: u8 = 0xc0;
34 const IIR_NONE_BIT: u8 = 0x1;
35 const IIR_THR_BIT: u8 = 0x2;
36 const IIR_RECV_BIT: u8 = 0x4;
37 
38 const LSR_DATA_BIT: u8 = 0x1;
39 const LSR_EMPTY_BIT: u8 = 0x20;
40 const LSR_IDLE_BIT: u8 = 0x40;
41 
42 const MCR_DTR_BIT: u8 = 0x01; // Data Terminal Ready
43 const MCR_RTS_BIT: u8 = 0x02; // Request to Send
44 const MCR_OUT1_BIT: u8 = 0x04;
45 const MCR_OUT2_BIT: u8 = 0x08;
46 const MCR_LOOP_BIT: u8 = 0x10;
47 
48 const MSR_CTS_BIT: u8 = 0x10; // Clear to Send
49 const MSR_DSR_BIT: u8 = 0x20; // Data Set Ready
50 const MSR_RI_BIT: u8 = 0x40; // Ring Indicator
51 const MSR_DCD_BIT: u8 = 0x80; // Data Carrier Detect
52 
53 const DEFAULT_INTERRUPT_IDENTIFICATION: u8 = IIR_NONE_BIT; // no pending interrupt
54 const DEFAULT_LINE_STATUS: u8 = LSR_EMPTY_BIT | LSR_IDLE_BIT; // THR empty and line is idle
55 const DEFAULT_LINE_CONTROL: u8 = 0x3; // 8-bits per character
56 const DEFAULT_MODEM_CONTROL: u8 = MCR_OUT2_BIT;
57 const DEFAULT_MODEM_STATUS: u8 = MSR_DSR_BIT | MSR_CTS_BIT | MSR_DCD_BIT;
58 const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps
59 
60 #[derive(Debug)]
61 pub enum Error {
62     CloneEventFd(sys_util::Error),
63     InvalidSerialType(String),
64     PathRequired,
65     FileError(std::io::Error),
66     Unimplemented(SerialType),
67 }
68 
69 impl Display for Error {
70     #[remain::check]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result71     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72         use self::Error::*;
73 
74         #[sorted]
75         match self {
76             CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e),
77             FileError(e) => write!(f, "Unable to open/create file: {}", e),
78             InvalidSerialType(e) => write!(f, "invalid serial type: {}", e),
79             PathRequired => write!(f, "serial device type file requires a path"),
80             Unimplemented(e) => write!(f, "serial device type {} not implemented", e.to_string()),
81         }
82     }
83 }
84 
85 /// Enum for possible type of serial devices
86 #[derive(Debug)]
87 pub enum SerialType {
88     File,
89     Stdout,
90     Sink,
91     Syslog,
92     UnixSocket, // NOT IMPLEMENTED
93 }
94 
95 impl Display for SerialType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result96     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97         let s = match &self {
98             SerialType::File => "File".to_string(),
99             SerialType::Stdout => "Stdout".to_string(),
100             SerialType::Sink => "Sink".to_string(),
101             SerialType::Syslog => "Syslog".to_string(),
102             SerialType::UnixSocket => "UnixSocket".to_string(),
103         };
104 
105         write!(f, "{}", s)
106     }
107 }
108 
109 impl FromStr for SerialType {
110     type Err = Error;
from_str(s: &str) -> std::result::Result<Self, Self::Err>111     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
112         match s {
113             "file" | "File" => Ok(SerialType::File),
114             "stdout" | "Stdout" => Ok(SerialType::Stdout),
115             "sink" | "Sink" => Ok(SerialType::Sink),
116             "syslog" | "Syslog" => Ok(SerialType::Syslog),
117             "unix" | "UnixSocket" => Ok(SerialType::UnixSocket),
118             _ => Err(Error::InvalidSerialType(s.to_string())),
119         }
120     }
121 }
122 
123 /// Holds the parameters for a serial device
124 #[derive(Debug)]
125 pub struct SerialParameters {
126     pub type_: SerialType,
127     pub path: Option<PathBuf>,
128     pub num: u8,
129     pub console: bool,
130 }
131 
132 impl SerialParameters {
133     /// Helper function to create a serial device from the defined parameters.
134     ///
135     /// # Arguments
136     /// * `evt_fd` - eventfd used for interrupt events
create_serial_device(&self, evt_fd: &EventFd) -> std::result::Result<Serial, Error>137     pub fn create_serial_device(&self, evt_fd: &EventFd) -> std::result::Result<Serial, Error> {
138         match self.type_ {
139             SerialType::Stdout => Ok(Serial::new_out(
140                 evt_fd.try_clone().map_err(Error::CloneEventFd)?,
141                 Box::new(stdout()),
142             )),
143             SerialType::Sink => Ok(Serial::new_sink(
144                 evt_fd.try_clone().map_err(Error::CloneEventFd)?,
145             )),
146             SerialType::Syslog => Ok(Serial::new_out(
147                 evt_fd.try_clone().map_err(Error::CloneEventFd)?,
148                 Box::new(syslog::Syslogger::new(
149                     syslog::Priority::Info,
150                     syslog::Facility::Daemon,
151                 )),
152             )),
153             SerialType::File => match &self.path {
154                 None => Err(Error::PathRequired),
155                 Some(path) => Ok(Serial::new_out(
156                     evt_fd.try_clone().map_err(Error::CloneEventFd)?,
157                     Box::new(File::create(path.as_path()).map_err(Error::FileError)?),
158                 )),
159             },
160             SerialType::UnixSocket => Err(Error::Unimplemented(SerialType::UnixSocket)),
161         }
162     }
163 }
164 
165 // Structure for holding the default configuration of the serial devices.
166 pub const DEFAULT_SERIAL_PARAMS: [SerialParameters; 4] = [
167     SerialParameters {
168         type_: SerialType::Stdout,
169         path: None,
170         num: 1,
171         console: true,
172     },
173     SerialParameters {
174         type_: SerialType::Sink,
175         path: None,
176         num: 2,
177         console: false,
178     },
179     SerialParameters {
180         type_: SerialType::Sink,
181         path: None,
182         num: 3,
183         console: false,
184     },
185     SerialParameters {
186         type_: SerialType::Sink,
187         path: None,
188         num: 4,
189         console: false,
190     },
191 ];
192 
193 /// Address for Serial ports in x86
194 pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];
195 
196 /// String representations of serial devices
197 pub const SERIAL_TTY_STRINGS: [&str; 4] = ["ttyS0", "ttyS1", "ttyS2", "ttyS3"];
198 
199 /// Helper function to get the tty string of a serial device based on the port number. Will default
200 ///  to ttyS0 if an invalid number is given.
get_serial_tty_string(stdio_serial_num: u8) -> String201 pub fn get_serial_tty_string(stdio_serial_num: u8) -> String {
202     match stdio_serial_num {
203         1 => SERIAL_TTY_STRINGS[0].to_string(),
204         2 => SERIAL_TTY_STRINGS[1].to_string(),
205         3 => SERIAL_TTY_STRINGS[2].to_string(),
206         4 => SERIAL_TTY_STRINGS[3].to_string(),
207         _ => SERIAL_TTY_STRINGS[0].to_string(),
208     }
209 }
210 
211 /// Emulates serial COM ports commonly seen on x86 I/O ports 0x3f8/0x2f8/0x3e8/0x2e8.
212 ///
213 /// This can optionally write the guest's output to a Write trait object. To send input to the
214 /// guest, use `queue_input_bytes`.
215 pub struct Serial {
216     interrupt_enable: u8,
217     interrupt_identification: u8,
218     interrupt_evt: EventFd,
219     line_control: u8,
220     line_status: u8,
221     modem_control: u8,
222     modem_status: u8,
223     scratch: u8,
224     baud_divisor: u16,
225     in_buffer: VecDeque<u8>,
226     out: Option<Box<dyn io::Write + Send>>,
227 }
228 
229 impl Serial {
new(interrupt_evt: EventFd, out: Option<Box<dyn io::Write + Send>>) -> Serial230     fn new(interrupt_evt: EventFd, out: Option<Box<dyn io::Write + Send>>) -> Serial {
231         Serial {
232             interrupt_enable: 0,
233             interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
234             interrupt_evt,
235             line_control: DEFAULT_LINE_CONTROL,
236             line_status: DEFAULT_LINE_STATUS,
237             modem_control: DEFAULT_MODEM_CONTROL,
238             modem_status: DEFAULT_MODEM_STATUS,
239             scratch: 0,
240             baud_divisor: DEFAULT_BAUD_DIVISOR,
241             in_buffer: VecDeque::new(),
242             out,
243         }
244     }
245 
246     /// Constructs a Serial port ready for output.
new_out(interrupt_evt: EventFd, out: Box<dyn io::Write + Send>) -> Serial247     pub fn new_out(interrupt_evt: EventFd, out: Box<dyn io::Write + Send>) -> Serial {
248         Self::new(interrupt_evt, Some(out))
249     }
250 
251     /// Constructs a Serial port with no connected output.
new_sink(interrupt_evt: EventFd) -> Serial252     pub fn new_sink(interrupt_evt: EventFd) -> Serial {
253         Self::new(interrupt_evt, None)
254     }
255 
256     /// Queues raw bytes for the guest to read and signals the interrupt if the line status would
257     /// change.
queue_input_bytes(&mut self, c: &[u8]) -> Result<()>258     pub fn queue_input_bytes(&mut self, c: &[u8]) -> Result<()> {
259         if !self.is_loop() {
260             self.in_buffer.extend(c);
261             self.recv_data()?;
262         }
263         Ok(())
264     }
265 
is_dlab_set(&self) -> bool266     fn is_dlab_set(&self) -> bool {
267         (self.line_control & 0x80) != 0
268     }
269 
is_recv_intr_enabled(&self) -> bool270     fn is_recv_intr_enabled(&self) -> bool {
271         (self.interrupt_enable & IER_RECV_BIT) != 0
272     }
273 
is_thr_intr_enabled(&self) -> bool274     fn is_thr_intr_enabled(&self) -> bool {
275         (self.interrupt_enable & IER_THR_BIT) != 0
276     }
277 
is_loop(&self) -> bool278     fn is_loop(&self) -> bool {
279         (self.modem_control & MCR_LOOP_BIT) != 0
280     }
281 
add_intr_bit(&mut self, bit: u8)282     fn add_intr_bit(&mut self, bit: u8) {
283         self.interrupt_identification &= !IIR_NONE_BIT;
284         self.interrupt_identification |= bit;
285     }
286 
del_intr_bit(&mut self, bit: u8)287     fn del_intr_bit(&mut self, bit: u8) {
288         self.interrupt_identification &= !bit;
289         if self.interrupt_identification == 0x0 {
290             self.interrupt_identification = IIR_NONE_BIT;
291         }
292     }
293 
thr_empty(&mut self) -> Result<()>294     fn thr_empty(&mut self) -> Result<()> {
295         if self.is_thr_intr_enabled() {
296             self.add_intr_bit(IIR_THR_BIT);
297             self.trigger_interrupt()?
298         }
299         Ok(())
300     }
301 
recv_data(&mut self) -> Result<()>302     fn recv_data(&mut self) -> Result<()> {
303         if self.is_recv_intr_enabled() {
304             self.add_intr_bit(IIR_RECV_BIT);
305             self.trigger_interrupt()?
306         }
307         self.line_status |= LSR_DATA_BIT;
308         Ok(())
309     }
310 
trigger_interrupt(&mut self) -> Result<()>311     fn trigger_interrupt(&mut self) -> Result<()> {
312         self.interrupt_evt.write(1)
313     }
314 
iir_reset(&mut self)315     fn iir_reset(&mut self) {
316         self.interrupt_identification = DEFAULT_INTERRUPT_IDENTIFICATION;
317     }
318 
handle_write(&mut self, offset: u8, v: u8) -> Result<()>319     fn handle_write(&mut self, offset: u8, v: u8) -> Result<()> {
320         match offset as u8 {
321             DLAB_LOW if self.is_dlab_set() => {
322                 self.baud_divisor = (self.baud_divisor & 0xff00) | v as u16
323             }
324             DLAB_HIGH if self.is_dlab_set() => {
325                 self.baud_divisor = (self.baud_divisor & 0x00ff) | ((v as u16) << 8)
326             }
327             DATA => {
328                 if self.is_loop() {
329                     if self.in_buffer.len() < LOOP_SIZE {
330                         self.in_buffer.push_back(v);
331                         self.recv_data()?;
332                     }
333                 } else {
334                     if let Some(out) = self.out.as_mut() {
335                         out.write_all(&[v])?;
336                         out.flush()?;
337                     }
338                     self.thr_empty()?;
339                 }
340             }
341             IER => self.interrupt_enable = v & IER_FIFO_BITS,
342             LCR => self.line_control = v,
343             MCR => self.modem_control = v,
344             SCR => self.scratch = v,
345             _ => {}
346         }
347         Ok(())
348     }
349 }
350 
351 impl BusDevice for Serial {
debug_label(&self) -> String352     fn debug_label(&self) -> String {
353         "serial".to_owned()
354     }
355 
write(&mut self, offset: u64, data: &[u8])356     fn write(&mut self, offset: u64, data: &[u8]) {
357         if data.len() != 1 {
358             return;
359         }
360 
361         if let Err(e) = self.handle_write(offset as u8, data[0]) {
362             error!("serial failed write: {}", e);
363         }
364     }
365 
read(&mut self, offset: u64, data: &mut [u8])366     fn read(&mut self, offset: u64, data: &mut [u8]) {
367         if data.len() != 1 {
368             return;
369         }
370 
371         data[0] = match offset as u8 {
372             DLAB_LOW if self.is_dlab_set() => self.baud_divisor as u8,
373             DLAB_HIGH if self.is_dlab_set() => (self.baud_divisor >> 8) as u8,
374             DATA => {
375                 self.del_intr_bit(IIR_RECV_BIT);
376                 if self.in_buffer.len() <= 1 {
377                     self.line_status &= !LSR_DATA_BIT;
378                 }
379                 self.in_buffer.pop_front().unwrap_or_default()
380             }
381             IER => self.interrupt_enable,
382             IIR => {
383                 let v = self.interrupt_identification | IIR_FIFO_BITS;
384                 self.iir_reset();
385                 v
386             }
387             LCR => self.line_control,
388             MCR => self.modem_control,
389             LSR => self.line_status,
390             MSR => {
391                 if self.is_loop() {
392                     let mut msr =
393                         self.modem_status & !(MSR_DSR_BIT | MSR_CTS_BIT | MSR_RI_BIT | MSR_DCD_BIT);
394                     if self.modem_control & MCR_DTR_BIT != 0 {
395                         msr |= MSR_DSR_BIT;
396                     }
397                     if self.modem_control & MCR_RTS_BIT != 0 {
398                         msr |= MSR_CTS_BIT;
399                     }
400                     if self.modem_control & MCR_OUT1_BIT != 0 {
401                         msr |= MSR_RI_BIT;
402                     }
403                     if self.modem_control & MCR_OUT2_BIT != 0 {
404                         msr |= MSR_DCD_BIT;
405                     }
406                     msr
407                 } else {
408                     self.modem_status
409                 }
410             }
411             SCR => self.scratch,
412             _ => 0,
413         };
414     }
415 }
416 
417 #[cfg(test)]
418 mod tests {
419     use super::*;
420     use std::io;
421     use std::sync::Arc;
422 
423     use sync::Mutex;
424 
425     #[derive(Clone)]
426     struct SharedBuffer {
427         buf: Arc<Mutex<Vec<u8>>>,
428     }
429 
430     impl SharedBuffer {
new() -> SharedBuffer431         fn new() -> SharedBuffer {
432             SharedBuffer {
433                 buf: Arc::new(Mutex::new(Vec::new())),
434             }
435         }
436     }
437 
438     impl io::Write for SharedBuffer {
write(&mut self, buf: &[u8]) -> io::Result<usize>439         fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
440             self.buf.lock().write(buf)
441         }
flush(&mut self) -> io::Result<()>442         fn flush(&mut self) -> io::Result<()> {
443             self.buf.lock().flush()
444         }
445     }
446 
447     #[test]
serial_output()448     fn serial_output() {
449         let intr_evt = EventFd::new().unwrap();
450         let serial_out = SharedBuffer::new();
451 
452         let mut serial = Serial::new_out(intr_evt, Box::new(serial_out.clone()));
453 
454         serial.write(DATA as u64, &['a' as u8]);
455         serial.write(DATA as u64, &['b' as u8]);
456         serial.write(DATA as u64, &['c' as u8]);
457         assert_eq!(
458             serial_out.buf.lock().as_slice(),
459             &['a' as u8, 'b' as u8, 'c' as u8]
460         );
461     }
462 
463     #[test]
serial_input()464     fn serial_input() {
465         let intr_evt = EventFd::new().unwrap();
466         let serial_out = SharedBuffer::new();
467 
468         let mut serial =
469             Serial::new_out(intr_evt.try_clone().unwrap(), Box::new(serial_out.clone()));
470 
471         serial.write(IER as u64, &[IER_RECV_BIT]);
472         serial
473             .queue_input_bytes(&['a' as u8, 'b' as u8, 'c' as u8])
474             .unwrap();
475 
476         assert_eq!(intr_evt.read(), Ok(1));
477         let mut data = [0u8; 1];
478         serial.read(DATA as u64, &mut data[..]);
479         assert_eq!(data[0], 'a' as u8);
480         serial.read(DATA as u64, &mut data[..]);
481         assert_eq!(data[0], 'b' as u8);
482         serial.read(DATA as u64, &mut data[..]);
483         assert_eq!(data[0], 'c' as u8);
484     }
485 }
486