1 // Copyright 2022 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 crate::serial_device::{Error, SerialParameters};
6 use base::named_pipes;
7 use base::named_pipes::{BlockingMode, FramingMode};
8 use base::FileSync;
9 use base::{AsRawDescriptor, Event, RawDescriptor};
10 use hypervisor::ProtectionType;
11 use std::io::{self};
12 use std::path::Path;
13
14 pub use base::Console as ConsoleInput;
15
16 pub const SYSTEM_SERIAL_TYPE_NAME: &str = "NamedPipe";
17
18 /// Abstraction over serial-like devices that can be created given an event and optional input and
19 /// output streams.
20 pub trait SerialDevice {
new( protected_vm: ProtectionType, interrupt_evt: Event, input: Option<Box<dyn io::Read + Send>>, output: Option<Box<dyn io::Write + Send>>, sync: Option<Box<dyn FileSync + Send>>, out_timestamp: bool, keep_rds: Vec<RawDescriptor>, ) -> Self21 fn new(
22 protected_vm: ProtectionType,
23 interrupt_evt: Event,
24 input: Option<Box<dyn io::Read + Send>>,
25 output: Option<Box<dyn io::Write + Send>>,
26 sync: Option<Box<dyn FileSync + Send>>,
27 out_timestamp: bool,
28 keep_rds: Vec<RawDescriptor>,
29 ) -> Self;
new_pipe( protected_vm: ProtectionType, interrupt_evt: Event, pipe_in: named_pipes::PipeConnection, pipe_out: named_pipes::PipeConnection, keep_rds: Vec<RawDescriptor>, ) -> Self30 fn new_pipe(
31 protected_vm: ProtectionType,
32 interrupt_evt: Event,
33 pipe_in: named_pipes::PipeConnection,
34 pipe_out: named_pipes::PipeConnection,
35 keep_rds: Vec<RawDescriptor>,
36 ) -> Self;
37 }
38
create_system_type_serial_device<T: SerialDevice>( param: &SerialParameters, protected_vm: ProtectionType, evt: Event, _input: Option<Box<dyn io::Read + Send>>, keep_rds: &mut Vec<RawDescriptor>, ) -> std::result::Result<T, Error>39 pub(crate) fn create_system_type_serial_device<T: SerialDevice>(
40 param: &SerialParameters,
41 protected_vm: ProtectionType,
42 evt: Event,
43 _input: Option<Box<dyn io::Read + Send>>,
44 keep_rds: &mut Vec<RawDescriptor>,
45 ) -> std::result::Result<T, Error> {
46 match ¶m.path {
47 None => return Err(Error::PathRequired),
48 Some(path) => {
49 // We must create this pipe in non-blocking mode because a blocking
50 // read in one thread will block a write in another thread having a
51 // handle to the same end of the pipe, which will hang the
52 // emulator. This does mean that the event loop writing to the
53 // pipe's output will need to swallow errors caused by writing to
54 // the pipe when it's not ready; but in practice this does not seem
55 // to cause a problem.
56 let pipe_in = named_pipes::create_server_pipe(
57 path.to_str().unwrap(),
58 &FramingMode::Byte,
59 &BlockingMode::NoWait,
60 0, // default timeout
61 named_pipes::DEFAULT_BUFFER_SIZE,
62 false,
63 )
64 .map_err(Error::SystemTypeError)?;
65
66 let pipe_out = pipe_in.try_clone().map_err(Error::SystemTypeError)?;
67
68 keep_rds.push(pipe_in.as_raw_descriptor());
69 keep_rds.push(pipe_out.as_raw_descriptor());
70
71 return Ok(T::new_pipe(
72 protected_vm,
73 evt,
74 pipe_in,
75 pipe_out,
76 keep_rds.to_vec(),
77 ));
78 }
79 }
80 }
81