xref: /aosp_15_r20/external/crosvm/arch/src/serial.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "seccomp_trace")]
8*bb4ee6a4SAndroid Build Coastguard Worker use base::debug;
9*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
10*bb4ee6a4SAndroid Build Coastguard Worker use devices::serial_device::SerialHardware;
11*bb4ee6a4SAndroid Build Coastguard Worker use devices::serial_device::SerialParameters;
12*bb4ee6a4SAndroid Build Coastguard Worker use devices::serial_device::SerialType;
13*bb4ee6a4SAndroid Build Coastguard Worker use devices::Bus;
14*bb4ee6a4SAndroid Build Coastguard Worker use devices::Serial;
15*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::ProtectionType;
16*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "seccomp_trace")]
17*bb4ee6a4SAndroid Build Coastguard Worker use jail::read_jail_addr;
18*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(windows)]
19*bb4ee6a4SAndroid Build Coastguard Worker use jail::FakeMinijailStub as Minijail;
20*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
21*bb4ee6a4SAndroid Build Coastguard Worker use minijail::Minijail;
22*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
23*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
24*bb4ee6a4SAndroid Build Coastguard Worker 
25*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceRegistrationError;
26*bb4ee6a4SAndroid Build Coastguard Worker 
27*bb4ee6a4SAndroid Build Coastguard Worker mod sys;
28*bb4ee6a4SAndroid Build Coastguard Worker 
29*bb4ee6a4SAndroid Build Coastguard Worker /// Add the default serial parameters for serial ports that have not already been specified.
30*bb4ee6a4SAndroid Build Coastguard Worker ///
31*bb4ee6a4SAndroid Build Coastguard Worker /// This ensures that `serial_parameters` will contain parameters for each of the four PC-style
32*bb4ee6a4SAndroid Build Coastguard Worker /// serial ports (COM1-COM4).
33*bb4ee6a4SAndroid Build Coastguard Worker ///
34*bb4ee6a4SAndroid Build Coastguard Worker /// It also sets the first `SerialHardware::Serial` to be the default console device if no other
35*bb4ee6a4SAndroid Build Coastguard Worker /// serial parameters exist with console=true and the first serial device has not already been
36*bb4ee6a4SAndroid Build Coastguard Worker /// configured explicitly.
set_default_serial_parameters( serial_parameters: &mut BTreeMap<(SerialHardware, u8), SerialParameters>, is_vhost_user_console_enabled: bool, )37*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_default_serial_parameters(
38*bb4ee6a4SAndroid Build Coastguard Worker     serial_parameters: &mut BTreeMap<(SerialHardware, u8), SerialParameters>,
39*bb4ee6a4SAndroid Build Coastguard Worker     is_vhost_user_console_enabled: bool,
40*bb4ee6a4SAndroid Build Coastguard Worker ) {
41*bb4ee6a4SAndroid Build Coastguard Worker     // If no console device exists and the first serial port has not been specified,
42*bb4ee6a4SAndroid Build Coastguard Worker     // set the first serial port as a stdout+stdin console.
43*bb4ee6a4SAndroid Build Coastguard Worker     let default_console = (SerialHardware::Serial, 1);
44*bb4ee6a4SAndroid Build Coastguard Worker     if !serial_parameters.iter().any(|(_, p)| p.console) && !is_vhost_user_console_enabled {
45*bb4ee6a4SAndroid Build Coastguard Worker         serial_parameters
46*bb4ee6a4SAndroid Build Coastguard Worker             .entry(default_console)
47*bb4ee6a4SAndroid Build Coastguard Worker             .or_insert(SerialParameters {
48*bb4ee6a4SAndroid Build Coastguard Worker                 type_: SerialType::Stdout,
49*bb4ee6a4SAndroid Build Coastguard Worker                 hardware: SerialHardware::Serial,
50*bb4ee6a4SAndroid Build Coastguard Worker                 name: None,
51*bb4ee6a4SAndroid Build Coastguard Worker                 path: None,
52*bb4ee6a4SAndroid Build Coastguard Worker                 input: None,
53*bb4ee6a4SAndroid Build Coastguard Worker                 num: 1,
54*bb4ee6a4SAndroid Build Coastguard Worker                 console: true,
55*bb4ee6a4SAndroid Build Coastguard Worker                 earlycon: false,
56*bb4ee6a4SAndroid Build Coastguard Worker                 stdin: true,
57*bb4ee6a4SAndroid Build Coastguard Worker                 out_timestamp: false,
58*bb4ee6a4SAndroid Build Coastguard Worker                 ..Default::default()
59*bb4ee6a4SAndroid Build Coastguard Worker             });
60*bb4ee6a4SAndroid Build Coastguard Worker     }
61*bb4ee6a4SAndroid Build Coastguard Worker 
62*bb4ee6a4SAndroid Build Coastguard Worker     // Ensure all four of the COM ports exist.
63*bb4ee6a4SAndroid Build Coastguard Worker     // If one of these four SerialHardware::Serial port was not configured by the user,
64*bb4ee6a4SAndroid Build Coastguard Worker     // set it up as a sink.
65*bb4ee6a4SAndroid Build Coastguard Worker     for num in 1..=4 {
66*bb4ee6a4SAndroid Build Coastguard Worker         let key = (SerialHardware::Serial, num);
67*bb4ee6a4SAndroid Build Coastguard Worker         serial_parameters.entry(key).or_insert(SerialParameters {
68*bb4ee6a4SAndroid Build Coastguard Worker             type_: SerialType::Sink,
69*bb4ee6a4SAndroid Build Coastguard Worker             hardware: SerialHardware::Serial,
70*bb4ee6a4SAndroid Build Coastguard Worker             name: None,
71*bb4ee6a4SAndroid Build Coastguard Worker             path: None,
72*bb4ee6a4SAndroid Build Coastguard Worker             input: None,
73*bb4ee6a4SAndroid Build Coastguard Worker             num,
74*bb4ee6a4SAndroid Build Coastguard Worker             console: false,
75*bb4ee6a4SAndroid Build Coastguard Worker             earlycon: false,
76*bb4ee6a4SAndroid Build Coastguard Worker             stdin: false,
77*bb4ee6a4SAndroid Build Coastguard Worker             out_timestamp: false,
78*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
79*bb4ee6a4SAndroid Build Coastguard Worker         });
80*bb4ee6a4SAndroid Build Coastguard Worker     }
81*bb4ee6a4SAndroid Build Coastguard Worker }
82*bb4ee6a4SAndroid Build Coastguard Worker 
83*bb4ee6a4SAndroid Build Coastguard Worker /// Address for Serial ports in x86
84*bb4ee6a4SAndroid Build Coastguard Worker pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];
85*bb4ee6a4SAndroid Build Coastguard Worker 
86*bb4ee6a4SAndroid Build Coastguard Worker /// Information about a serial device (16550-style UART) created by `add_serial_devices()`.
87*bb4ee6a4SAndroid Build Coastguard Worker pub struct SerialDeviceInfo {
88*bb4ee6a4SAndroid Build Coastguard Worker     /// Address of the device on the bus.
89*bb4ee6a4SAndroid Build Coastguard Worker     /// This is the I/O bus on x86 machines and MMIO otherwise.
90*bb4ee6a4SAndroid Build Coastguard Worker     pub address: u64,
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker     /// Size of the device's address space on the bus.
93*bb4ee6a4SAndroid Build Coastguard Worker     pub size: u64,
94*bb4ee6a4SAndroid Build Coastguard Worker 
95*bb4ee6a4SAndroid Build Coastguard Worker     /// IRQ number of the device.
96*bb4ee6a4SAndroid Build Coastguard Worker     pub irq: u32,
97*bb4ee6a4SAndroid Build Coastguard Worker }
98*bb4ee6a4SAndroid Build Coastguard Worker 
99*bb4ee6a4SAndroid Build Coastguard Worker /// Adds serial devices to the provided bus based on the serial parameters given.
100*bb4ee6a4SAndroid Build Coastguard Worker ///
101*bb4ee6a4SAndroid Build Coastguard Worker /// Only devices with hardware type `SerialHardware::Serial` are added by this function.
102*bb4ee6a4SAndroid Build Coastguard Worker ///
103*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
104*bb4ee6a4SAndroid Build Coastguard Worker ///
105*bb4ee6a4SAndroid Build Coastguard Worker /// * `protection_type` - VM protection mode.
106*bb4ee6a4SAndroid Build Coastguard Worker /// * `io_bus` - Bus to add the devices to
107*bb4ee6a4SAndroid Build Coastguard Worker /// * `com_evt_1_3` - irq and event for com1 and com3
108*bb4ee6a4SAndroid Build Coastguard Worker /// * `com_evt_1_4` - irq and event for com2 and com4
109*bb4ee6a4SAndroid Build Coastguard Worker /// * `serial_parameters` - definitions of serial parameter configurations.
110*bb4ee6a4SAndroid Build Coastguard Worker /// * `serial_jail` - minijail object cloned for use with each serial device. All four of the
111*bb4ee6a4SAndroid Build Coastguard Worker ///   traditional PC-style serial ports (COM1-COM4) must be specified.
add_serial_devices( protection_type: ProtectionType, io_bus: &Bus, com_evt_1_3: (u32, &Event), com_evt_2_4: (u32, &Event), serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>, #[cfg_attr(windows, allow(unused_variables))] serial_jail: Option<Minijail>, #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>, ) -> std::result::Result<Vec<SerialDeviceInfo>, DeviceRegistrationError>112*bb4ee6a4SAndroid Build Coastguard Worker pub fn add_serial_devices(
113*bb4ee6a4SAndroid Build Coastguard Worker     protection_type: ProtectionType,
114*bb4ee6a4SAndroid Build Coastguard Worker     io_bus: &Bus,
115*bb4ee6a4SAndroid Build Coastguard Worker     com_evt_1_3: (u32, &Event),
116*bb4ee6a4SAndroid Build Coastguard Worker     com_evt_2_4: (u32, &Event),
117*bb4ee6a4SAndroid Build Coastguard Worker     serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
118*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg_attr(windows, allow(unused_variables))] serial_jail: Option<Minijail>,
119*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
120*bb4ee6a4SAndroid Build Coastguard Worker ) -> std::result::Result<Vec<SerialDeviceInfo>, DeviceRegistrationError> {
121*bb4ee6a4SAndroid Build Coastguard Worker     let mut devices = Vec::new();
122*bb4ee6a4SAndroid Build Coastguard Worker     for com_num in 0..=3 {
123*bb4ee6a4SAndroid Build Coastguard Worker         let com_evt = match com_num {
124*bb4ee6a4SAndroid Build Coastguard Worker             0 => &com_evt_1_3,
125*bb4ee6a4SAndroid Build Coastguard Worker             1 => &com_evt_2_4,
126*bb4ee6a4SAndroid Build Coastguard Worker             2 => &com_evt_1_3,
127*bb4ee6a4SAndroid Build Coastguard Worker             3 => &com_evt_2_4,
128*bb4ee6a4SAndroid Build Coastguard Worker             _ => &com_evt_1_3,
129*bb4ee6a4SAndroid Build Coastguard Worker         };
130*bb4ee6a4SAndroid Build Coastguard Worker 
131*bb4ee6a4SAndroid Build Coastguard Worker         let (irq, com_evt) = (com_evt.0, com_evt.1);
132*bb4ee6a4SAndroid Build Coastguard Worker 
133*bb4ee6a4SAndroid Build Coastguard Worker         let param = serial_parameters
134*bb4ee6a4SAndroid Build Coastguard Worker             .get(&(SerialHardware::Serial, com_num + 1))
135*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(DeviceRegistrationError::MissingRequiredSerialDevice(
136*bb4ee6a4SAndroid Build Coastguard Worker                 com_num + 1,
137*bb4ee6a4SAndroid Build Coastguard Worker             ))?;
138*bb4ee6a4SAndroid Build Coastguard Worker 
139*bb4ee6a4SAndroid Build Coastguard Worker         let mut preserved_descriptors = Vec::new();
140*bb4ee6a4SAndroid Build Coastguard Worker         let com = param
141*bb4ee6a4SAndroid Build Coastguard Worker             .create_serial_device::<Serial>(protection_type, com_evt, &mut preserved_descriptors)
142*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(DeviceRegistrationError::CreateSerialDevice)?;
143*bb4ee6a4SAndroid Build Coastguard Worker 
144*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(any(target_os = "android", target_os = "linux"))]
145*bb4ee6a4SAndroid Build Coastguard Worker         let serial_jail = if let Some(serial_jail) = serial_jail.as_ref() {
146*bb4ee6a4SAndroid Build Coastguard Worker             let jail_clone = serial_jail
147*bb4ee6a4SAndroid Build Coastguard Worker                 .try_clone()
148*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(DeviceRegistrationError::CloneJail)?;
149*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "seccomp_trace")]
150*bb4ee6a4SAndroid Build Coastguard Worker             debug!(
151*bb4ee6a4SAndroid Build Coastguard Worker                     "seccomp_trace {{\"event\": \"minijail_clone\", \"src_jail_addr\": \"0x{:x}\", \"dst_jail_addr\": \"0x{:x}\"}}",
152*bb4ee6a4SAndroid Build Coastguard Worker                     read_jail_addr(serial_jail),
153*bb4ee6a4SAndroid Build Coastguard Worker                     read_jail_addr(&jail_clone)
154*bb4ee6a4SAndroid Build Coastguard Worker                 );
155*bb4ee6a4SAndroid Build Coastguard Worker             Some(jail_clone)
156*bb4ee6a4SAndroid Build Coastguard Worker         } else {
157*bb4ee6a4SAndroid Build Coastguard Worker             None
158*bb4ee6a4SAndroid Build Coastguard Worker         };
159*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(windows)]
160*bb4ee6a4SAndroid Build Coastguard Worker         let serial_jail = None;
161*bb4ee6a4SAndroid Build Coastguard Worker 
162*bb4ee6a4SAndroid Build Coastguard Worker         let com = sys::add_serial_device(
163*bb4ee6a4SAndroid Build Coastguard Worker             com,
164*bb4ee6a4SAndroid Build Coastguard Worker             param,
165*bb4ee6a4SAndroid Build Coastguard Worker             serial_jail,
166*bb4ee6a4SAndroid Build Coastguard Worker             preserved_descriptors,
167*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "swap")]
168*bb4ee6a4SAndroid Build Coastguard Worker             swap_controller,
169*bb4ee6a4SAndroid Build Coastguard Worker         )?;
170*bb4ee6a4SAndroid Build Coastguard Worker 
171*bb4ee6a4SAndroid Build Coastguard Worker         let address = SERIAL_ADDR[usize::from(com_num)];
172*bb4ee6a4SAndroid Build Coastguard Worker         let size = 0x8; // 16550 UART uses 8 bytes of address space.
173*bb4ee6a4SAndroid Build Coastguard Worker         io_bus.insert(com, address, size).unwrap();
174*bb4ee6a4SAndroid Build Coastguard Worker         devices.push(SerialDeviceInfo { address, size, irq })
175*bb4ee6a4SAndroid Build Coastguard Worker     }
176*bb4ee6a4SAndroid Build Coastguard Worker 
177*bb4ee6a4SAndroid Build Coastguard Worker     Ok(devices)
178*bb4ee6a4SAndroid Build Coastguard Worker }
179*bb4ee6a4SAndroid Build Coastguard Worker 
180*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
181*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
182*bb4ee6a4SAndroid Build Coastguard Worker pub enum GetSerialCmdlineError {
183*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Error appending to cmdline: {0}")]
184*bb4ee6a4SAndroid Build Coastguard Worker     KernelCmdline(kernel_cmdline::Error),
185*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Hardware {0} not supported as earlycon")]
186*bb4ee6a4SAndroid Build Coastguard Worker     UnsupportedEarlyconHardware(SerialHardware),
187*bb4ee6a4SAndroid Build Coastguard Worker }
188*bb4ee6a4SAndroid Build Coastguard Worker 
189*bb4ee6a4SAndroid Build Coastguard Worker pub type GetSerialCmdlineResult<T> = std::result::Result<T, GetSerialCmdlineError>;
190*bb4ee6a4SAndroid Build Coastguard Worker 
191*bb4ee6a4SAndroid Build Coastguard Worker /// Add serial options to the provided `cmdline` based on `serial_parameters`.
192*bb4ee6a4SAndroid Build Coastguard Worker /// `serial_io_type` should be "io" if the platform uses x86-style I/O ports for serial devices
193*bb4ee6a4SAndroid Build Coastguard Worker /// or "mmio" if the serial ports are memory mapped.
194*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/227407433): Support cases where vhost-user console is specified.
get_serial_cmdline( cmdline: &mut kernel_cmdline::Cmdline, serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>, serial_io_type: &str, serial_devices: &[SerialDeviceInfo], ) -> GetSerialCmdlineResult<()>195*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_serial_cmdline(
196*bb4ee6a4SAndroid Build Coastguard Worker     cmdline: &mut kernel_cmdline::Cmdline,
197*bb4ee6a4SAndroid Build Coastguard Worker     serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
198*bb4ee6a4SAndroid Build Coastguard Worker     serial_io_type: &str,
199*bb4ee6a4SAndroid Build Coastguard Worker     serial_devices: &[SerialDeviceInfo],
200*bb4ee6a4SAndroid Build Coastguard Worker ) -> GetSerialCmdlineResult<()> {
201*bb4ee6a4SAndroid Build Coastguard Worker     for serial_parameter in serial_parameters
202*bb4ee6a4SAndroid Build Coastguard Worker         .iter()
203*bb4ee6a4SAndroid Build Coastguard Worker         .filter(|(_, p)| p.console)
204*bb4ee6a4SAndroid Build Coastguard Worker         .map(|(k, _)| k)
205*bb4ee6a4SAndroid Build Coastguard Worker     {
206*bb4ee6a4SAndroid Build Coastguard Worker         match serial_parameter {
207*bb4ee6a4SAndroid Build Coastguard Worker             (SerialHardware::Serial, num) => {
208*bb4ee6a4SAndroid Build Coastguard Worker                 cmdline
209*bb4ee6a4SAndroid Build Coastguard Worker                     .insert("console", &format!("ttyS{}", num - 1))
210*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(GetSerialCmdlineError::KernelCmdline)?;
211*bb4ee6a4SAndroid Build Coastguard Worker             }
212*bb4ee6a4SAndroid Build Coastguard Worker             (SerialHardware::VirtioConsole, num) => {
213*bb4ee6a4SAndroid Build Coastguard Worker                 cmdline
214*bb4ee6a4SAndroid Build Coastguard Worker                     .insert("console", &format!("hvc{}", num - 1))
215*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(GetSerialCmdlineError::KernelCmdline)?;
216*bb4ee6a4SAndroid Build Coastguard Worker             }
217*bb4ee6a4SAndroid Build Coastguard Worker             (SerialHardware::Debugcon, _) => {}
218*bb4ee6a4SAndroid Build Coastguard Worker         }
219*bb4ee6a4SAndroid Build Coastguard Worker     }
220*bb4ee6a4SAndroid Build Coastguard Worker 
221*bb4ee6a4SAndroid Build Coastguard Worker     match serial_parameters
222*bb4ee6a4SAndroid Build Coastguard Worker         .iter()
223*bb4ee6a4SAndroid Build Coastguard Worker         .filter(|(_, p)| p.earlycon)
224*bb4ee6a4SAndroid Build Coastguard Worker         .map(|(k, _)| k)
225*bb4ee6a4SAndroid Build Coastguard Worker         .next()
226*bb4ee6a4SAndroid Build Coastguard Worker     {
227*bb4ee6a4SAndroid Build Coastguard Worker         Some((SerialHardware::Serial, num)) => {
228*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(serial_device) = serial_devices.get(*num as usize - 1) {
229*bb4ee6a4SAndroid Build Coastguard Worker                 cmdline
230*bb4ee6a4SAndroid Build Coastguard Worker                     .insert(
231*bb4ee6a4SAndroid Build Coastguard Worker                         "earlycon",
232*bb4ee6a4SAndroid Build Coastguard Worker                         &format!("uart8250,{},0x{:x}", serial_io_type, serial_device.address),
233*bb4ee6a4SAndroid Build Coastguard Worker                     )
234*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(GetSerialCmdlineError::KernelCmdline)?;
235*bb4ee6a4SAndroid Build Coastguard Worker             }
236*bb4ee6a4SAndroid Build Coastguard Worker         }
237*bb4ee6a4SAndroid Build Coastguard Worker         Some((hw, _num)) => {
238*bb4ee6a4SAndroid Build Coastguard Worker             return Err(GetSerialCmdlineError::UnsupportedEarlyconHardware(*hw));
239*bb4ee6a4SAndroid Build Coastguard Worker         }
240*bb4ee6a4SAndroid Build Coastguard Worker         None => {}
241*bb4ee6a4SAndroid Build Coastguard Worker     }
242*bb4ee6a4SAndroid Build Coastguard Worker 
243*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
244*bb4ee6a4SAndroid Build Coastguard Worker }
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
247*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
248*bb4ee6a4SAndroid Build Coastguard Worker     use devices::BusType;
249*bb4ee6a4SAndroid Build Coastguard Worker     use kernel_cmdline::Cmdline;
250*bb4ee6a4SAndroid Build Coastguard Worker 
251*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
252*bb4ee6a4SAndroid Build Coastguard Worker 
253*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
get_serial_cmdline_default()254*bb4ee6a4SAndroid Build Coastguard Worker     fn get_serial_cmdline_default() {
255*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmdline = Cmdline::new();
256*bb4ee6a4SAndroid Build Coastguard Worker         let mut serial_parameters = BTreeMap::new();
257*bb4ee6a4SAndroid Build Coastguard Worker         let io_bus = Bus::new(BusType::Io);
258*bb4ee6a4SAndroid Build Coastguard Worker         let evt1_3 = Event::new().unwrap();
259*bb4ee6a4SAndroid Build Coastguard Worker         let evt2_4 = Event::new().unwrap();
260*bb4ee6a4SAndroid Build Coastguard Worker 
261*bb4ee6a4SAndroid Build Coastguard Worker         set_default_serial_parameters(&mut serial_parameters, false);
262*bb4ee6a4SAndroid Build Coastguard Worker         let serial_devices = add_serial_devices(
263*bb4ee6a4SAndroid Build Coastguard Worker             ProtectionType::Unprotected,
264*bb4ee6a4SAndroid Build Coastguard Worker             &io_bus,
265*bb4ee6a4SAndroid Build Coastguard Worker             (4, &evt1_3),
266*bb4ee6a4SAndroid Build Coastguard Worker             (3, &evt2_4),
267*bb4ee6a4SAndroid Build Coastguard Worker             &serial_parameters,
268*bb4ee6a4SAndroid Build Coastguard Worker             None,
269*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "swap")]
270*bb4ee6a4SAndroid Build Coastguard Worker             &mut None,
271*bb4ee6a4SAndroid Build Coastguard Worker         )
272*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
273*bb4ee6a4SAndroid Build Coastguard Worker         get_serial_cmdline(&mut cmdline, &serial_parameters, "io", &serial_devices)
274*bb4ee6a4SAndroid Build Coastguard Worker             .expect("get_serial_cmdline failed");
275*bb4ee6a4SAndroid Build Coastguard Worker 
276*bb4ee6a4SAndroid Build Coastguard Worker         let cmdline_str = cmdline.as_str();
277*bb4ee6a4SAndroid Build Coastguard Worker         assert!(cmdline_str.contains("console=ttyS0"));
278*bb4ee6a4SAndroid Build Coastguard Worker     }
279*bb4ee6a4SAndroid Build Coastguard Worker 
280*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
get_serial_cmdline_virtio_console()281*bb4ee6a4SAndroid Build Coastguard Worker     fn get_serial_cmdline_virtio_console() {
282*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmdline = Cmdline::new();
283*bb4ee6a4SAndroid Build Coastguard Worker         let mut serial_parameters = BTreeMap::new();
284*bb4ee6a4SAndroid Build Coastguard Worker         let io_bus = Bus::new(BusType::Io);
285*bb4ee6a4SAndroid Build Coastguard Worker         let evt1_3 = Event::new().unwrap();
286*bb4ee6a4SAndroid Build Coastguard Worker         let evt2_4 = Event::new().unwrap();
287*bb4ee6a4SAndroid Build Coastguard Worker 
288*bb4ee6a4SAndroid Build Coastguard Worker         // Add a virtio-console device with console=true.
289*bb4ee6a4SAndroid Build Coastguard Worker         serial_parameters.insert(
290*bb4ee6a4SAndroid Build Coastguard Worker             (SerialHardware::VirtioConsole, 1),
291*bb4ee6a4SAndroid Build Coastguard Worker             SerialParameters {
292*bb4ee6a4SAndroid Build Coastguard Worker                 type_: SerialType::Stdout,
293*bb4ee6a4SAndroid Build Coastguard Worker                 hardware: SerialHardware::VirtioConsole,
294*bb4ee6a4SAndroid Build Coastguard Worker                 num: 1,
295*bb4ee6a4SAndroid Build Coastguard Worker                 console: true,
296*bb4ee6a4SAndroid Build Coastguard Worker                 stdin: true,
297*bb4ee6a4SAndroid Build Coastguard Worker                 ..Default::default()
298*bb4ee6a4SAndroid Build Coastguard Worker             },
299*bb4ee6a4SAndroid Build Coastguard Worker         );
300*bb4ee6a4SAndroid Build Coastguard Worker 
301*bb4ee6a4SAndroid Build Coastguard Worker         set_default_serial_parameters(&mut serial_parameters, false);
302*bb4ee6a4SAndroid Build Coastguard Worker         let serial_devices = add_serial_devices(
303*bb4ee6a4SAndroid Build Coastguard Worker             ProtectionType::Unprotected,
304*bb4ee6a4SAndroid Build Coastguard Worker             &io_bus,
305*bb4ee6a4SAndroid Build Coastguard Worker             (4, &evt1_3),
306*bb4ee6a4SAndroid Build Coastguard Worker             (3, &evt2_4),
307*bb4ee6a4SAndroid Build Coastguard Worker             &serial_parameters,
308*bb4ee6a4SAndroid Build Coastguard Worker             None,
309*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "swap")]
310*bb4ee6a4SAndroid Build Coastguard Worker             &mut None,
311*bb4ee6a4SAndroid Build Coastguard Worker         )
312*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
313*bb4ee6a4SAndroid Build Coastguard Worker         get_serial_cmdline(&mut cmdline, &serial_parameters, "io", &serial_devices)
314*bb4ee6a4SAndroid Build Coastguard Worker             .expect("get_serial_cmdline failed");
315*bb4ee6a4SAndroid Build Coastguard Worker 
316*bb4ee6a4SAndroid Build Coastguard Worker         let cmdline_str = cmdline.as_str();
317*bb4ee6a4SAndroid Build Coastguard Worker         assert!(cmdline_str.contains("console=hvc0"));
318*bb4ee6a4SAndroid Build Coastguard Worker     }
319*bb4ee6a4SAndroid Build Coastguard Worker 
320*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
get_serial_cmdline_virtio_console_serial_earlycon()321*bb4ee6a4SAndroid Build Coastguard Worker     fn get_serial_cmdline_virtio_console_serial_earlycon() {
322*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmdline = Cmdline::new();
323*bb4ee6a4SAndroid Build Coastguard Worker         let mut serial_parameters = BTreeMap::new();
324*bb4ee6a4SAndroid Build Coastguard Worker         let io_bus = Bus::new(BusType::Io);
325*bb4ee6a4SAndroid Build Coastguard Worker         let evt1_3 = Event::new().unwrap();
326*bb4ee6a4SAndroid Build Coastguard Worker         let evt2_4 = Event::new().unwrap();
327*bb4ee6a4SAndroid Build Coastguard Worker 
328*bb4ee6a4SAndroid Build Coastguard Worker         // Add a virtio-console device with console=true.
329*bb4ee6a4SAndroid Build Coastguard Worker         serial_parameters.insert(
330*bb4ee6a4SAndroid Build Coastguard Worker             (SerialHardware::VirtioConsole, 1),
331*bb4ee6a4SAndroid Build Coastguard Worker             SerialParameters {
332*bb4ee6a4SAndroid Build Coastguard Worker                 type_: SerialType::Stdout,
333*bb4ee6a4SAndroid Build Coastguard Worker                 hardware: SerialHardware::VirtioConsole,
334*bb4ee6a4SAndroid Build Coastguard Worker                 num: 1,
335*bb4ee6a4SAndroid Build Coastguard Worker                 console: true,
336*bb4ee6a4SAndroid Build Coastguard Worker                 stdin: true,
337*bb4ee6a4SAndroid Build Coastguard Worker                 ..Default::default()
338*bb4ee6a4SAndroid Build Coastguard Worker             },
339*bb4ee6a4SAndroid Build Coastguard Worker         );
340*bb4ee6a4SAndroid Build Coastguard Worker 
341*bb4ee6a4SAndroid Build Coastguard Worker         // Override the default COM1 with an earlycon device.
342*bb4ee6a4SAndroid Build Coastguard Worker         serial_parameters.insert(
343*bb4ee6a4SAndroid Build Coastguard Worker             (SerialHardware::Serial, 1),
344*bb4ee6a4SAndroid Build Coastguard Worker             SerialParameters {
345*bb4ee6a4SAndroid Build Coastguard Worker                 type_: SerialType::Stdout,
346*bb4ee6a4SAndroid Build Coastguard Worker                 hardware: SerialHardware::Serial,
347*bb4ee6a4SAndroid Build Coastguard Worker                 num: 1,
348*bb4ee6a4SAndroid Build Coastguard Worker                 earlycon: true,
349*bb4ee6a4SAndroid Build Coastguard Worker                 ..Default::default()
350*bb4ee6a4SAndroid Build Coastguard Worker             },
351*bb4ee6a4SAndroid Build Coastguard Worker         );
352*bb4ee6a4SAndroid Build Coastguard Worker 
353*bb4ee6a4SAndroid Build Coastguard Worker         set_default_serial_parameters(&mut serial_parameters, false);
354*bb4ee6a4SAndroid Build Coastguard Worker         let serial_devices = add_serial_devices(
355*bb4ee6a4SAndroid Build Coastguard Worker             ProtectionType::Unprotected,
356*bb4ee6a4SAndroid Build Coastguard Worker             &io_bus,
357*bb4ee6a4SAndroid Build Coastguard Worker             (4, &evt1_3),
358*bb4ee6a4SAndroid Build Coastguard Worker             (3, &evt2_4),
359*bb4ee6a4SAndroid Build Coastguard Worker             &serial_parameters,
360*bb4ee6a4SAndroid Build Coastguard Worker             None,
361*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "swap")]
362*bb4ee6a4SAndroid Build Coastguard Worker             &mut None,
363*bb4ee6a4SAndroid Build Coastguard Worker         )
364*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
365*bb4ee6a4SAndroid Build Coastguard Worker         get_serial_cmdline(&mut cmdline, &serial_parameters, "io", &serial_devices)
366*bb4ee6a4SAndroid Build Coastguard Worker             .expect("get_serial_cmdline failed");
367*bb4ee6a4SAndroid Build Coastguard Worker 
368*bb4ee6a4SAndroid Build Coastguard Worker         let cmdline_str = cmdline.as_str();
369*bb4ee6a4SAndroid Build Coastguard Worker         assert!(cmdline_str.contains("console=hvc0"));
370*bb4ee6a4SAndroid Build Coastguard Worker         assert!(cmdline_str.contains("earlycon=uart8250,io,0x3f8"));
371*bb4ee6a4SAndroid Build Coastguard Worker     }
372*bb4ee6a4SAndroid Build Coastguard Worker 
373*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
get_serial_cmdline_virtio_console_invalid_earlycon()374*bb4ee6a4SAndroid Build Coastguard Worker     fn get_serial_cmdline_virtio_console_invalid_earlycon() {
375*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmdline = Cmdline::new();
376*bb4ee6a4SAndroid Build Coastguard Worker         let mut serial_parameters = BTreeMap::new();
377*bb4ee6a4SAndroid Build Coastguard Worker         let io_bus = Bus::new(BusType::Io);
378*bb4ee6a4SAndroid Build Coastguard Worker         let evt1_3 = Event::new().unwrap();
379*bb4ee6a4SAndroid Build Coastguard Worker         let evt2_4 = Event::new().unwrap();
380*bb4ee6a4SAndroid Build Coastguard Worker 
381*bb4ee6a4SAndroid Build Coastguard Worker         // Try to add a virtio-console device with earlycon=true (unsupported).
382*bb4ee6a4SAndroid Build Coastguard Worker         serial_parameters.insert(
383*bb4ee6a4SAndroid Build Coastguard Worker             (SerialHardware::VirtioConsole, 1),
384*bb4ee6a4SAndroid Build Coastguard Worker             SerialParameters {
385*bb4ee6a4SAndroid Build Coastguard Worker                 type_: SerialType::Stdout,
386*bb4ee6a4SAndroid Build Coastguard Worker                 hardware: SerialHardware::VirtioConsole,
387*bb4ee6a4SAndroid Build Coastguard Worker                 num: 1,
388*bb4ee6a4SAndroid Build Coastguard Worker                 earlycon: true,
389*bb4ee6a4SAndroid Build Coastguard Worker                 stdin: true,
390*bb4ee6a4SAndroid Build Coastguard Worker                 ..Default::default()
391*bb4ee6a4SAndroid Build Coastguard Worker             },
392*bb4ee6a4SAndroid Build Coastguard Worker         );
393*bb4ee6a4SAndroid Build Coastguard Worker 
394*bb4ee6a4SAndroid Build Coastguard Worker         set_default_serial_parameters(&mut serial_parameters, false);
395*bb4ee6a4SAndroid Build Coastguard Worker         let serial_devices = add_serial_devices(
396*bb4ee6a4SAndroid Build Coastguard Worker             ProtectionType::Unprotected,
397*bb4ee6a4SAndroid Build Coastguard Worker             &io_bus,
398*bb4ee6a4SAndroid Build Coastguard Worker             (4, &evt1_3),
399*bb4ee6a4SAndroid Build Coastguard Worker             (3, &evt2_4),
400*bb4ee6a4SAndroid Build Coastguard Worker             &serial_parameters,
401*bb4ee6a4SAndroid Build Coastguard Worker             None,
402*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "swap")]
403*bb4ee6a4SAndroid Build Coastguard Worker             &mut None,
404*bb4ee6a4SAndroid Build Coastguard Worker         )
405*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
406*bb4ee6a4SAndroid Build Coastguard Worker         get_serial_cmdline(&mut cmdline, &serial_parameters, "io", &serial_devices)
407*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("get_serial_cmdline succeeded");
408*bb4ee6a4SAndroid Build Coastguard Worker     }
409*bb4ee6a4SAndroid Build Coastguard Worker }
410