summary refs log tree commit diff
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2020-02-14 16:46:36 -0800
committerCommit Bot <commit-bot@chromium.org>2020-04-23 07:17:55 +0000
commitfbd6122f0b722f40bb14f0c3a26342fa46d5a89d (patch)
tree237d82fabe09b84b02ed2b05963ab698a8eaf31e
parent2c1417b43a1846d21bc589563460de4b962afcc6 (diff)
downloadcrosvm-fbd6122f0b722f40bb14f0c3a26342fa46d5a89d.tar
crosvm-fbd6122f0b722f40bb14f0c3a26342fa46d5a89d.tar.gz
crosvm-fbd6122f0b722f40bb14f0c3a26342fa46d5a89d.tar.bz2
crosvm-fbd6122f0b722f40bb14f0c3a26342fa46d5a89d.tar.lz
crosvm-fbd6122f0b722f40bb14f0c3a26342fa46d5a89d.tar.xz
crosvm-fbd6122f0b722f40bb14f0c3a26342fa46d5a89d.tar.zst
crosvm-fbd6122f0b722f40bb14f0c3a26342fa46d5a89d.zip
arch, devices: move serial creation to arch
Split the serial code  into two parts:

- Configuration and setup: arch/src/serial.rs
- Serial device emulation: devices/src/serial.rs

No change in functionality - this is just preparation for generalizing
the command line parsing/setup code so that it can be used with virtio
console devices as well.

BUG=chromium:1059924
TEST=emerge-nami crosvm
TEST=emerge-kevin crosvm

Change-Id: I0aaf9dd6f8096eac4a17077ab5bf569f57d64ff5
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2127319
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
-rw-r--r--aarch64/src/fdt.rs3
-rw-r--r--aarch64/src/lib.rs7
-rw-r--r--arch/src/lib.rs72
-rw-r--r--arch/src/serial.rs269
-rw-r--r--devices/src/lib.rs5
-rw-r--r--devices/src/serial.rs201
-rw-r--r--src/crosvm.rs4
-rw-r--r--src/main.rs4
-rw-r--r--tests/boot.rs2
-rw-r--r--x86_64/src/lib.rs6
10 files changed, 291 insertions, 282 deletions
diff --git a/aarch64/src/fdt.rs b/aarch64/src/fdt.rs
index 9dcafa5..f50286e 100644
--- a/aarch64/src/fdt.rs
+++ b/aarch64/src/fdt.rs
@@ -10,7 +10,8 @@ use arch::fdt::{
     begin_node, end_node, finish_fdt, generate_prop32, generate_prop64, property, property_cstring,
     property_null, property_string, property_u32, property_u64, start_fdt, Error, Result,
 };
-use devices::{PciInterruptPin, SERIAL_ADDR};
+use arch::SERIAL_ADDR;
+use devices::PciInterruptPin;
 use sys_util::{GuestAddress, GuestMemory};
 
 // This is the start of DRAM in the physical address space.
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
index f8a36b9..67e37b4 100644
--- a/aarch64/src/lib.rs
+++ b/aarch64/src/lib.rs
@@ -11,11 +11,8 @@ use std::io;
 use std::os::unix::io::FromRawFd;
 use std::sync::Arc;
 
-use arch::{RunnableLinuxVm, VmComponents, VmImage};
-use devices::{
-    get_serial_tty_string, Bus, BusError, PciConfigMmio, PciDevice, PciInterruptPin,
-    SerialParameters,
-};
+use arch::{get_serial_tty_string, RunnableLinuxVm, SerialParameters, VmComponents, VmImage};
+use devices::{Bus, BusError, PciConfigMmio, PciDevice, PciInterruptPin};
 use io_jail::Minijail;
 use remain::sorted;
 use resources::SystemAllocator;
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index ab08c21..9ba1f27 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -5,6 +5,7 @@
 pub mod android;
 pub mod fdt;
 pub mod pstore;
+pub mod serial;
 
 use std::collections::BTreeMap;
 use std::error::Error as StdError;
@@ -19,7 +20,6 @@ use devices::split_irqchip_common::GsiRelay;
 use devices::virtio::VirtioDevice;
 use devices::{
     Bus, BusDevice, BusError, PciDevice, PciDeviceError, PciInterruptPin, PciRoot, ProxyDevice,
-    SerialParameters, DEFAULT_SERIAL_PARAMS, SERIAL_ADDR,
 };
 use io_jail::Minijail;
 use kvm::{IoeventAddress, Kvm, Vcpu, Vm};
@@ -28,6 +28,10 @@ use sync::Mutex;
 use sys_util::{syslog, EventFd, GuestAddress, GuestMemory, GuestMemoryError};
 use vm_control::VmIrqRequestSocket;
 
+pub use serial::{
+    add_serial_devices, get_serial_tty_string, SerialParameters, SerialType, SERIAL_ADDR,
+};
+
 pub enum VmImage {
     Kernel(File),
     Bios(File),
@@ -119,7 +123,7 @@ pub enum DeviceRegistrationError {
     // Unable to create a pipe.
     CreatePipe(sys_util::Error),
     // Unable to create serial device from serial parameters
-    CreateSerialDevice(devices::SerialError),
+    CreateSerialDevice(serial::Error),
     /// Could not clone an event fd.
     EventFdClone(sys_util::Error),
     /// Could not create an event fd.
@@ -258,70 +262,6 @@ pub fn generate_pci_root(
     Ok((root, pci_irqs, pid_labels))
 }
 
-/// Adds serial devices to the provided bus based on the serial parameters given. Returns the serial
-///  port number and serial device to be used for stdout if defined.
-///
-/// # Arguments
-///
-/// * `io_bus` - Bus to add the devices to
-/// * `com_evt_1_3` - eventfd for com1 and com3
-/// * `com_evt_1_4` - eventfd for com2 and com4
-/// * `io_bus` - Bus to add the devices to
-/// * `serial_parameters` - definitions of serial parameter configuationis. If a setting is not
-///     provided for a port, then it will use the default configuation.
-pub fn add_serial_devices(
-    io_bus: &mut Bus,
-    com_evt_1_3: &EventFd,
-    com_evt_2_4: &EventFd,
-    serial_parameters: &BTreeMap<u8, SerialParameters>,
-    serial_jail: Option<Minijail>,
-) -> Result<Option<u8>, DeviceRegistrationError> {
-    let mut stdio_serial_num = None;
-
-    for x in 0..=3 {
-        let com_evt = match x {
-            0 => com_evt_1_3,
-            1 => com_evt_2_4,
-            2 => com_evt_1_3,
-            3 => com_evt_2_4,
-            _ => com_evt_1_3,
-        };
-
-        let param = serial_parameters
-            .get(&(x + 1))
-            .unwrap_or(&DEFAULT_SERIAL_PARAMS[x as usize]);
-
-        if param.console {
-            stdio_serial_num = Some(x + 1);
-        }
-
-        let mut preserved_fds = Vec::new();
-        let com = param
-            .create_serial_device(&com_evt, &mut preserved_fds)
-            .map_err(DeviceRegistrationError::CreateSerialDevice)?;
-
-        match serial_jail.as_ref() {
-            Some(jail) => {
-                let com = Arc::new(Mutex::new(
-                    ProxyDevice::new(com, &jail, preserved_fds)
-                        .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
-                ));
-                io_bus
-                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
-                    .unwrap();
-            }
-            None => {
-                let com = Arc::new(Mutex::new(com));
-                io_bus
-                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
-                    .unwrap();
-            }
-        }
-    }
-
-    Ok(stdio_serial_num)
-}
-
 /// Errors for image loading.
 #[derive(Debug)]
 pub enum LoadImageError {
diff --git a/arch/src/serial.rs b/arch/src/serial.rs
new file mode 100644
index 0000000..58947b5
--- /dev/null
+++ b/arch/src/serial.rs
@@ -0,0 +1,269 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::collections::BTreeMap;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::{self, stdin, stdout};
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::path::PathBuf;
+use std::str::FromStr;
+use std::sync::Arc;
+
+use devices::{Bus, ProxyDevice, Serial};
+use io_jail::Minijail;
+use sync::Mutex;
+use sys_util::{read_raw_stdin, syslog, EventFd};
+
+use crate::DeviceRegistrationError;
+
+#[derive(Debug)]
+pub enum Error {
+    CloneEventFd(sys_util::Error),
+    FileError(std::io::Error),
+    InvalidSerialType(String),
+    PathRequired,
+    Unimplemented(SerialType),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e),
+            FileError(e) => write!(f, "unable to open/create file: {}", e),
+            InvalidSerialType(e) => write!(f, "invalid serial type: {}", e),
+            PathRequired => write!(f, "serial device type file requires a path"),
+            Unimplemented(e) => write!(f, "serial device type {} not implemented", e.to_string()),
+        }
+    }
+}
+
+/// Enum for possible type of serial devices
+#[derive(Debug)]
+pub enum SerialType {
+    File,
+    Stdout,
+    Sink,
+    Syslog,
+    UnixSocket, // NOT IMPLEMENTED
+}
+
+impl Display for SerialType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let s = match &self {
+            SerialType::File => "File".to_string(),
+            SerialType::Stdout => "Stdout".to_string(),
+            SerialType::Sink => "Sink".to_string(),
+            SerialType::Syslog => "Syslog".to_string(),
+            SerialType::UnixSocket => "UnixSocket".to_string(),
+        };
+
+        write!(f, "{}", s)
+    }
+}
+
+impl FromStr for SerialType {
+    type Err = Error;
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        match s {
+            "file" | "File" => Ok(SerialType::File),
+            "stdout" | "Stdout" => Ok(SerialType::Stdout),
+            "sink" | "Sink" => Ok(SerialType::Sink),
+            "syslog" | "Syslog" => Ok(SerialType::Syslog),
+            "unix" | "UnixSocket" => Ok(SerialType::UnixSocket),
+            _ => Err(Error::InvalidSerialType(s.to_string())),
+        }
+    }
+}
+
+/// Holds the parameters for a serial device
+#[derive(Debug)]
+pub struct SerialParameters {
+    pub type_: SerialType,
+    pub path: Option<PathBuf>,
+    pub input: Option<PathBuf>,
+    pub num: u8,
+    pub console: bool,
+    pub stdin: bool,
+}
+
+impl SerialParameters {
+    /// Helper function to create a serial device from the defined parameters.
+    ///
+    /// # Arguments
+    /// * `evt_fd` - eventfd used for interrupt events
+    /// * `keep_fds` - Vector of FDs required by this device if it were sandboxed in a child
+    ///                process. `evt_fd` will always be added to this vector by this function.
+    pub fn create_serial_device(
+        &self,
+        evt_fd: &EventFd,
+        keep_fds: &mut Vec<RawFd>,
+    ) -> std::result::Result<Serial, Error> {
+        let evt_fd = evt_fd.try_clone().map_err(Error::CloneEventFd)?;
+        keep_fds.push(evt_fd.as_raw_fd());
+        let input: Option<Box<dyn io::Read + Send>> = if let Some(input_path) = &self.input {
+            let input_file = File::open(input_path.as_path()).map_err(Error::FileError)?;
+            keep_fds.push(input_file.as_raw_fd());
+            Some(Box::new(input_file))
+        } else if self.stdin {
+            keep_fds.push(stdin().as_raw_fd());
+            // This wrapper is used in place of the libstd native version because we don't want
+            // buffering for stdin.
+            struct StdinWrapper;
+            impl io::Read for StdinWrapper {
+                fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
+                    read_raw_stdin(out).map_err(|e| e.into())
+                }
+            }
+            Some(Box::new(StdinWrapper))
+        } else {
+            None
+        };
+        match self.type_ {
+            SerialType::Stdout => {
+                keep_fds.push(stdout().as_raw_fd());
+                Ok(Serial::new(evt_fd, input, Some(Box::new(stdout()))))
+            }
+            SerialType::Sink => Ok(Serial::new(evt_fd, input, None)),
+            SerialType::Syslog => {
+                syslog::push_fds(keep_fds);
+                Ok(Serial::new(
+                    evt_fd,
+                    input,
+                    Some(Box::new(syslog::Syslogger::new(
+                        syslog::Priority::Info,
+                        syslog::Facility::Daemon,
+                    ))),
+                ))
+            }
+            SerialType::File => match &self.path {
+                Some(path) => {
+                    let file = File::create(path.as_path()).map_err(Error::FileError)?;
+                    keep_fds.push(file.as_raw_fd());
+                    Ok(Serial::new(evt_fd, input, Some(Box::new(file))))
+                }
+                _ => Err(Error::PathRequired),
+            },
+            SerialType::UnixSocket => Err(Error::Unimplemented(SerialType::UnixSocket)),
+        }
+    }
+}
+
+// Structure for holding the default configuration of the serial devices.
+const DEFAULT_SERIAL_PARAMS: [SerialParameters; 4] = [
+    SerialParameters {
+        type_: SerialType::Stdout,
+        path: None,
+        input: None,
+        num: 1,
+        console: true,
+        stdin: true,
+    },
+    SerialParameters {
+        type_: SerialType::Sink,
+        path: None,
+        input: None,
+        num: 2,
+        console: false,
+        stdin: false,
+    },
+    SerialParameters {
+        type_: SerialType::Sink,
+        path: None,
+        input: None,
+        num: 3,
+        console: false,
+        stdin: false,
+    },
+    SerialParameters {
+        type_: SerialType::Sink,
+        path: None,
+        input: None,
+        num: 4,
+        console: false,
+        stdin: false,
+    },
+];
+
+/// Address for Serial ports in x86
+pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];
+
+/// String representations of serial devices
+const SERIAL_TTY_STRINGS: [&str; 4] = ["ttyS0", "ttyS1", "ttyS2", "ttyS3"];
+
+/// Helper function to get the tty string of a serial device based on the port number. Will default
+///  to ttyS0 if an invalid number is given.
+pub fn get_serial_tty_string(stdio_serial_num: u8) -> String {
+    stdio_serial_num
+        .checked_sub(1)
+        .and_then(|i| SERIAL_TTY_STRINGS.get(i as usize))
+        .unwrap_or(&SERIAL_TTY_STRINGS[0])
+        .to_string()
+}
+
+/// Adds serial devices to the provided bus based on the serial parameters given. Returns the serial
+///  port number and serial device to be used for stdout if defined.
+///
+/// # Arguments
+///
+/// * `io_bus` - Bus to add the devices to
+/// * `com_evt_1_3` - eventfd for com1 and com3
+/// * `com_evt_1_4` - eventfd for com2 and com4
+/// * `io_bus` - Bus to add the devices to
+/// * `serial_parameters` - definitions of serial parameter configuationis. If a setting is not
+///     provided for a port, then it will use the default configuation.
+pub fn add_serial_devices(
+    io_bus: &mut Bus,
+    com_evt_1_3: &EventFd,
+    com_evt_2_4: &EventFd,
+    serial_parameters: &BTreeMap<u8, SerialParameters>,
+    serial_jail: Option<Minijail>,
+) -> Result<Option<u8>, DeviceRegistrationError> {
+    let mut stdio_serial_num = None;
+
+    for x in 0..=3 {
+        let com_evt = match x {
+            0 => com_evt_1_3,
+            1 => com_evt_2_4,
+            2 => com_evt_1_3,
+            3 => com_evt_2_4,
+            _ => com_evt_1_3,
+        };
+
+        let param = serial_parameters
+            .get(&(x + 1))
+            .unwrap_or(&DEFAULT_SERIAL_PARAMS[x as usize]);
+
+        if param.console {
+            stdio_serial_num = Some(x + 1);
+        }
+
+        let mut preserved_fds = Vec::new();
+        let com = param
+            .create_serial_device(&com_evt, &mut preserved_fds)
+            .map_err(DeviceRegistrationError::CreateSerialDevice)?;
+
+        match serial_jail.as_ref() {
+            Some(jail) => {
+                let com = Arc::new(Mutex::new(
+                    ProxyDevice::new(com, &jail, preserved_fds)
+                        .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
+                ));
+                io_bus
+                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
+                    .unwrap();
+            }
+            None => {
+                let com = Arc::new(Mutex::new(com));
+                io_bus
+                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
+                    .unwrap();
+            }
+        }
+    }
+
+    Ok(stdio_serial_num)
+}
diff --git a/devices/src/lib.rs b/devices/src/lib.rs
index 9ed8417..75c27a8 100644
--- a/devices/src/lib.rs
+++ b/devices/src/lib.rs
@@ -38,10 +38,7 @@ pub use self::pit::{Pit, PitError};
 pub use self::pl030::Pl030;
 pub use self::proxy::Error as ProxyError;
 pub use self::proxy::ProxyDevice;
-pub use self::serial::Error as SerialError;
-pub use self::serial::{
-    get_serial_tty_string, Serial, SerialParameters, SerialType, DEFAULT_SERIAL_PARAMS, SERIAL_ADDR,
-};
+pub use self::serial::Serial;
 pub use self::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
 pub use self::usb::xhci::xhci_controller::XhciController;
 pub use self::vfio::{VfioContainer, VfioDevice};
diff --git a/devices/src/serial.rs b/devices/src/serial.rs
index caf1ee0..756217d 100644
--- a/devices/src/serial.rs
+++ b/devices/src/serial.rs
@@ -3,18 +3,13 @@
 // found in the LICENSE file.
 
 use std::collections::VecDeque;
-use std::fmt::{self, Display};
-use std::fs::File;
-use std::io::{self, stdin, stdout, Read, Write};
-use std::os::unix::io::{AsRawFd, RawFd};
-use std::path::PathBuf;
-use std::str::FromStr;
+use std::io::{self, Write};
 use std::sync::atomic::{AtomicU8, Ordering};
 use std::sync::mpsc::{channel, Receiver, TryRecvError};
 use std::sync::Arc;
 use std::thread::{self};
 
-use sys_util::{error, read_raw_stdin, syslog, EventFd, Result};
+use sys_util::{error, EventFd, Result};
 
 use crate::BusDevice;
 
@@ -62,196 +57,6 @@ const DEFAULT_MODEM_CONTROL: u8 = MCR_OUT2_BIT;
 const DEFAULT_MODEM_STATUS: u8 = MSR_DSR_BIT | MSR_CTS_BIT | MSR_DCD_BIT;
 const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps
 
-#[derive(Debug)]
-pub enum Error {
-    CloneEventFd(sys_util::Error),
-    InvalidSerialType(String),
-    PathRequired,
-    FileError(std::io::Error),
-    Unimplemented(SerialType),
-}
-
-impl Display for Error {
-    #[remain::check]
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::Error::*;
-
-        #[sorted]
-        match self {
-            CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e),
-            FileError(e) => write!(f, "Unable to open/create file: {}", e),
-            InvalidSerialType(e) => write!(f, "invalid serial type: {}", e),
-            PathRequired => write!(f, "serial device type file requires a path"),
-            Unimplemented(e) => write!(f, "serial device type {} not implemented", e.to_string()),
-        }
-    }
-}
-
-/// Enum for possible type of serial devices
-#[derive(Debug)]
-pub enum SerialType {
-    File,
-    Stdout,
-    Sink,
-    Syslog,
-    UnixSocket, // NOT IMPLEMENTED
-}
-
-impl Display for SerialType {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let s = match &self {
-            SerialType::File => "File".to_string(),
-            SerialType::Stdout => "Stdout".to_string(),
-            SerialType::Sink => "Sink".to_string(),
-            SerialType::Syslog => "Syslog".to_string(),
-            SerialType::UnixSocket => "UnixSocket".to_string(),
-        };
-
-        write!(f, "{}", s)
-    }
-}
-
-impl FromStr for SerialType {
-    type Err = Error;
-    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
-        match s {
-            "file" | "File" => Ok(SerialType::File),
-            "stdout" | "Stdout" => Ok(SerialType::Stdout),
-            "sink" | "Sink" => Ok(SerialType::Sink),
-            "syslog" | "Syslog" => Ok(SerialType::Syslog),
-            "unix" | "UnixSocket" => Ok(SerialType::UnixSocket),
-            _ => Err(Error::InvalidSerialType(s.to_string())),
-        }
-    }
-}
-
-/// Holds the parameters for a serial device
-#[derive(Debug)]
-pub struct SerialParameters {
-    pub type_: SerialType,
-    pub path: Option<PathBuf>,
-    pub input: Option<PathBuf>,
-    pub num: u8,
-    pub console: bool,
-    pub stdin: bool,
-}
-
-impl SerialParameters {
-    /// Helper function to create a serial device from the defined parameters.
-    ///
-    /// # Arguments
-    /// * `evt_fd` - eventfd used for interrupt events
-    /// * `keep_fds` - Vector of FDs required by this device if it were sandboxed in a child
-    ///                process. `evt_fd` will always be added to this vector by this function.
-    pub fn create_serial_device(
-        &self,
-        evt_fd: &EventFd,
-        keep_fds: &mut Vec<RawFd>,
-    ) -> std::result::Result<Serial, Error> {
-        let evt_fd = evt_fd.try_clone().map_err(Error::CloneEventFd)?;
-        keep_fds.push(evt_fd.as_raw_fd());
-        let input: Option<Box<dyn io::Read + Send>> = if let Some(input_path) = &self.input {
-            let input_file = File::open(input_path.as_path()).map_err(Error::FileError)?;
-            keep_fds.push(input_file.as_raw_fd());
-            Some(Box::new(input_file))
-        } else if self.stdin {
-            keep_fds.push(stdin().as_raw_fd());
-            // This wrapper is used in place of the libstd native version because we don't want
-            // buffering for stdin.
-            struct StdinWrapper;
-            impl io::Read for StdinWrapper {
-                fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
-                    read_raw_stdin(out).map_err(|e| e.into())
-                }
-            }
-            Some(Box::new(StdinWrapper))
-        } else {
-            None
-        };
-        match self.type_ {
-            SerialType::Stdout => {
-                keep_fds.push(stdout().as_raw_fd());
-                Ok(Serial::new(evt_fd, input, Some(Box::new(stdout()))))
-            }
-            SerialType::Sink => Ok(Serial::new(evt_fd, input, None)),
-            SerialType::Syslog => {
-                syslog::push_fds(keep_fds);
-                Ok(Serial::new(
-                    evt_fd,
-                    input,
-                    Some(Box::new(syslog::Syslogger::new(
-                        syslog::Priority::Info,
-                        syslog::Facility::Daemon,
-                    ))),
-                ))
-            }
-            SerialType::File => match &self.path {
-                Some(path) => {
-                    let file = File::create(path.as_path()).map_err(Error::FileError)?;
-                    keep_fds.push(file.as_raw_fd());
-                    Ok(Serial::new(evt_fd, input, Some(Box::new(file))))
-                }
-                _ => Err(Error::PathRequired),
-            },
-            SerialType::UnixSocket => Err(Error::Unimplemented(SerialType::UnixSocket)),
-        }
-    }
-}
-
-// Structure for holding the default configuration of the serial devices.
-pub const DEFAULT_SERIAL_PARAMS: [SerialParameters; 4] = [
-    SerialParameters {
-        type_: SerialType::Stdout,
-        path: None,
-        input: None,
-        num: 1,
-        console: true,
-        stdin: true,
-    },
-    SerialParameters {
-        type_: SerialType::Sink,
-        path: None,
-        input: None,
-        num: 2,
-        console: false,
-        stdin: false,
-    },
-    SerialParameters {
-        type_: SerialType::Sink,
-        path: None,
-        input: None,
-        num: 3,
-        console: false,
-        stdin: false,
-    },
-    SerialParameters {
-        type_: SerialType::Sink,
-        path: None,
-        input: None,
-        num: 4,
-        console: false,
-        stdin: false,
-    },
-];
-
-/// Address for Serial ports in x86
-pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];
-
-/// String representations of serial devices
-pub const SERIAL_TTY_STRINGS: [&str; 4] = ["ttyS0", "ttyS1", "ttyS2", "ttyS3"];
-
-/// Helper function to get the tty string of a serial device based on the port number. Will default
-///  to ttyS0 if an invalid number is given.
-pub fn get_serial_tty_string(stdio_serial_num: u8) -> String {
-    match stdio_serial_num {
-        1 => SERIAL_TTY_STRINGS[0].to_string(),
-        2 => SERIAL_TTY_STRINGS[1].to_string(),
-        3 => SERIAL_TTY_STRINGS[2].to_string(),
-        4 => SERIAL_TTY_STRINGS[3].to_string(),
-        _ => SERIAL_TTY_STRINGS[0].to_string(),
-    }
-}
-
 /// Emulates serial COM ports commonly seen on x86 I/O ports 0x3f8/0x2f8/0x3e8/0x2e8.
 ///
 /// This can optionally write the guest's output to a Write trait object. To send input to the
@@ -277,7 +82,7 @@ pub struct Serial {
 }
 
 impl Serial {
-    fn new(
+    pub fn new(
         interrupt_evt: EventFd,
         input: Option<Box<dyn io::Read + Send>>,
         out: Option<Box<dyn io::Write + Send>>,
diff --git a/src/crosvm.rs b/src/crosvm.rs
index a55d2e4..75e384f 100644
--- a/src/crosvm.rs
+++ b/src/crosvm.rs
@@ -16,11 +16,11 @@ use std::os::unix::io::RawFd;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
-use arch::Pstore;
+use arch::{Pstore, SerialParameters};
 use devices::virtio::fs::passthrough;
 #[cfg(feature = "gpu")]
 use devices::virtio::gpu::GpuParameters;
-use devices::{Ac97Parameters, SerialParameters};
+use devices::Ac97Parameters;
 use libc::{getegid, geteuid};
 
 static SECCOMP_POLICY_DIR: &str = "/usr/share/policy/crosvm";
diff --git a/src/main.rs b/src/main.rs
index fc20f8b..9775d5f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,7 +17,7 @@ use std::string::String;
 use std::thread::sleep;
 use std::time::Duration;
 
-use arch::Pstore;
+use arch::{Pstore, SerialParameters, SerialType};
 use audio_streams::StreamEffect;
 use crosvm::{
     argument::{self, print_help, set_arguments, Argument},
@@ -25,7 +25,7 @@ use crosvm::{
 };
 #[cfg(feature = "gpu")]
 use devices::virtio::gpu::{GpuMode, GpuParameters};
-use devices::{Ac97Backend, Ac97Parameters, SerialParameters, SerialType};
+use devices::{Ac97Backend, Ac97Parameters};
 use disk::QcowFile;
 use msg_socket::{MsgReceiver, MsgSender, MsgSocket};
 use sys_util::{
diff --git a/tests/boot.rs b/tests/boot.rs
index d5f52dc..c60ba4b 100644
--- a/tests/boot.rs
+++ b/tests/boot.rs
@@ -13,8 +13,8 @@ use std::sync::Once;
 
 use libc::{cpu_set_t, sched_getaffinity};
 
+use arch::{SerialParameters, SerialType};
 use crosvm::{linux, Config, Executable};
-use devices::{SerialParameters, SerialType};
 use sys_util::syslog;
 
 const CHROOT_KERNEL_PATH: &str = "/mnt/host/source/src/third_party/kernel/v4.19/";
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index a4ba444..c073223 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -54,11 +54,11 @@ use std::mem;
 use std::sync::Arc;
 
 use crate::bootparam::boot_params;
-use arch::{RunnableLinuxVm, VmComponents, VmImage};
+use arch::{get_serial_tty_string, RunnableLinuxVm, SerialParameters, VmComponents, VmImage};
 use devices::split_irqchip_common::GsiRelay;
 use devices::{
-    get_serial_tty_string, Ioapic, PciConfigIo, PciDevice, PciInterruptPin, Pic, SerialParameters,
-    IOAPIC_BASE_ADDRESS, IOAPIC_MEM_LENGTH_BYTES,
+    Ioapic, PciConfigIo, PciDevice, PciInterruptPin, Pic, IOAPIC_BASE_ADDRESS,
+    IOAPIC_MEM_LENGTH_BYTES,
 };
 use io_jail::Minijail;
 use kvm::*;