xref: /aosp_15_r20/external/crosvm/devices/src/sys/windows/serial_device.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 &param.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