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