diff options
author | Daniel Verkamp <dverkamp@chromium.org> | 2020-03-09 13:16:46 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-04-23 07:17:59 +0000 |
commit | a7b6a1c897205d8320482eb506167c5df66647b2 (patch) | |
tree | 10b3f4ba971bfbd0a03c258193bbd47b8c672aa4 /src | |
parent | b865810340f1b264b407137c4e69ad232194cc5e (diff) | |
download | crosvm-a7b6a1c897205d8320482eb506167c5df66647b2.tar crosvm-a7b6a1c897205d8320482eb506167c5df66647b2.tar.gz crosvm-a7b6a1c897205d8320482eb506167c5df66647b2.tar.bz2 crosvm-a7b6a1c897205d8320482eb506167c5df66647b2.tar.lz crosvm-a7b6a1c897205d8320482eb506167c5df66647b2.tar.xz crosvm-a7b6a1c897205d8320482eb506167c5df66647b2.tar.zst crosvm-a7b6a1c897205d8320482eb506167c5df66647b2.zip |
arch, main: add virtio-console parsing and creation
This allows the creation of virtio-console devices using the new hardware=virtio-console parameter to the --serial option. Also add support for the serial earlycon option, which allows using virtio-console as the main console device with a traditional serial device as the early console. This allows logging during early boot before PCI device discovery (when virtio-console devices are set up). BUG=chromium:1059924 TEST=crosvm run -r vm_rootfs.img \ --serial hardware=serial,type=stdout,console=false,earlycon=true \ --serial hardware=virtio-console,type=stdout,console=true,stdin=true \ vm_kernel Change-Id: Iff48800272b154d49b1da00f3914799089268afe Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2127322 Reviewed-by: Zach Reizner <zachr@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/crosvm.rs | 4 | ||||
-rw-r--r-- | src/linux.rs | 31 | ||||
-rw-r--r-- | src/main.rs | 60 |
3 files changed, 81 insertions, 14 deletions
diff --git a/src/crosvm.rs b/src/crosvm.rs index 75e384f..49a08c0 100644 --- a/src/crosvm.rs +++ b/src/crosvm.rs @@ -16,7 +16,7 @@ use std::os::unix::io::RawFd; use std::path::{Path, PathBuf}; use std::str::FromStr; -use arch::{Pstore, SerialParameters}; +use arch::{Pstore, SerialHardware, SerialParameters}; use devices::virtio::fs::passthrough; #[cfg(feature = "gpu")] use devices::virtio::gpu::GpuParameters; @@ -193,7 +193,7 @@ pub struct Config { pub display_window_keyboard: bool, pub display_window_mouse: bool, pub ac97_parameters: Vec<Ac97Parameters>, - pub serial_parameters: BTreeMap<u8, SerialParameters>, + pub serial_parameters: BTreeMap<(SerialHardware, u8), SerialParameters>, pub syslog_tag: Option<String>, pub virtio_single_touch: Option<TouchDeviceOption>, pub virtio_trackpad: Option<TouchDeviceOption>, diff --git a/src/linux.rs b/src/linux.rs index c469e0c..8690ff7 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -29,7 +29,7 @@ use libc::{self, c_int, gid_t, uid_t}; #[cfg(feature = "gpu")] use devices::virtio::EventDevice; -use devices::virtio::{self, VirtioDevice}; +use devices::virtio::{self, Console, VirtioDevice}; use devices::{ self, Ac97Backend, Ac97Dev, HostBackendDeviceProvider, PciDevice, VfioContainer, VfioDevice, VfioPciDevice, VirtioPciDevice, XhciController, @@ -61,7 +61,10 @@ use vm_control::{ }; use crate::{Config, DiskOption, Executable, SharedDir, SharedDirKind, TouchDeviceOption}; -use arch::{self, LinuxArch, RunnableLinuxVm, VirtioDeviceStub, VmComponents, VmImage}; +use arch::{ + self, LinuxArch, RunnableLinuxVm, SerialHardware, SerialParameters, VirtioDeviceStub, + VmComponents, VmImage, +}; #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] use aarch64::AArch64 as Arch; @@ -82,6 +85,7 @@ pub enum Error { ChownTpmStorage(sys_util::Error), CloneEventFd(sys_util::Error), CreateAc97(devices::PciDeviceError), + CreateConsole(arch::serial::Error), CreateDiskError(disk::Error), CreateEventFd(sys_util::Error), CreatePollContext(sys_util::Error), @@ -166,6 +170,7 @@ impl Display for Error { ChownTpmStorage(e) => write!(f, "failed to chown tpm storage: {}", e), CloneEventFd(e) => write!(f, "failed to clone eventfd: {}", e), CreateAc97(e) => write!(f, "failed to create ac97 device: {}", e), + CreateConsole(e) => write!(f, "failed to create console device: {}", e), CreateDiskError(e) => write!(f, "failed to create virtual disk: {}", e), CreateEventFd(e) => write!(f, "failed to create eventfd: {}", e), CreatePollContext(e) => write!(f, "failed to create poll context: {}", e), @@ -963,6 +968,19 @@ fn create_pmem_device( }) } +fn create_console_device(cfg: &Config, param: &SerialParameters) -> DeviceResult { + let mut keep_fds = Vec::new(); + let evt = EventFd::new().map_err(Error::CreateEventFd)?; + let dev = param + .create_serial_device::<Console>(&evt, &mut keep_fds) + .map_err(Error::CreateConsole)?; + + Ok(VirtioDeviceStub { + dev: Box::new(dev), + jail: simple_jail(&cfg, "serial")?, // TODO(dverkamp): use a separate policy for console? + }) +} + // gpu_device_socket is not used when GPU support is disabled. #[cfg_attr(not(feature = "gpu"), allow(unused_variables))] fn create_virtio_devices( @@ -979,6 +997,15 @@ fn create_virtio_devices( ) -> DeviceResult<Vec<VirtioDeviceStub>> { let mut devs = Vec::new(); + for (_, param) in cfg + .serial_parameters + .iter() + .filter(|(_k, v)| v.hardware == SerialHardware::VirtioConsole) + { + let dev = create_console_device(cfg, param)?; + devs.push(dev); + } + for disk in &cfg.disks { let disk_device_socket = disk_device_sockets.remove(0); devs.push(create_block_device(cfg, disk, disk_device_socket)?); diff --git a/src/main.rs b/src/main.rs index 9775d5f..557c630 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, SerialParameters, SerialType}; +use arch::{set_default_serial_parameters, Pstore, SerialHardware, SerialParameters, SerialType}; use audio_streams::StreamEffect; use crosvm::{ argument::{self, print_help, set_arguments, Argument}, @@ -301,10 +301,12 @@ fn parse_ac97_options(s: &str) -> argument::Result<Ac97Parameters> { fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> { let mut serial_setting = SerialParameters { type_: SerialType::Sink, + hardware: SerialHardware::Serial, path: None, input: None, num: 1, console: false, + earlycon: false, stdin: false, }; @@ -315,6 +317,11 @@ fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> { for (k, v) in opts { match k { + "hardware" => { + serial_setting.hardware = v + .parse::<SerialHardware>() + .map_err(|e| argument::Error::UnknownArgument(format!("{}", e)))? + } "type" => { serial_setting.type_ = v .parse::<SerialType>() @@ -340,6 +347,14 @@ fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> { )) })? } + "earlycon" => { + serial_setting.earlycon = v.parse::<bool>().map_err(|e| { + argument::Error::Syntax(format!( + "serial device earlycon is not parseable: {}", + e, + )) + })? + } "stdin" => { serial_setting.stdin = v.parse::<bool>().map_err(|e| { argument::Error::Syntax(format!("serial device stdin is not parseable: {}", e)) @@ -549,10 +564,11 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: "serial" => { let serial_params = parse_serial_options(value.unwrap())?; let num = serial_params.num; - if cfg.serial_parameters.contains_key(&num) { + let key = (serial_params.hardware, num); + if cfg.serial_parameters.contains_key(&key) { return Err(argument::Error::TooManyArguments(format!( - "serial num {}", - num + "serial hardware {} num {}", + serial_params.hardware, num, ))); } @@ -560,8 +576,29 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: for params in cfg.serial_parameters.values() { if params.console { return Err(argument::Error::TooManyArguments(format!( - "serial device {} already set as console", - params.num + "{} device {} already set as console", + params.hardware, params.num, + ))); + } + } + } + + if serial_params.earlycon { + // Only SerialHardware::Serial supports earlycon= currently. + match serial_params.hardware { + SerialHardware::Serial => {} + _ => { + return Err(argument::Error::InvalidValue { + value: serial_params.hardware.to_string().to_owned(), + expected: String::from("earlycon not supported for hardware"), + }); + } + } + for params in cfg.serial_parameters.values() { + if params.earlycon { + return Err(argument::Error::TooManyArguments(format!( + "{} device {} already set as earlycon", + params.hardware, params.num, ))); } } @@ -570,13 +607,13 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if serial_params.stdin { if let Some(previous_stdin) = cfg.serial_parameters.values().find(|sp| sp.stdin) { return Err(argument::Error::TooManyArguments(format!( - "serial device {} already connected to standard input", - previous_stdin.num + "{} device {} already connected to standard input", + previous_stdin.hardware, previous_stdin.num, ))); } } - cfg.serial_parameters.insert(num, serial_params); + cfg.serial_parameters.insert(key, serial_params); } "syslog-tag" => { if cfg.syslog_tag.is_some() { @@ -1231,6 +1268,7 @@ fn validate_arguments(cfg: &mut Config) -> std::result::Result<(), argument::Err } } } + set_default_serial_parameters(&mut cfg.serial_parameters); Ok(()) } @@ -1281,14 +1319,16 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> { capture - Enable audio capture capture_effects - | separated effects to be enabled for recording. The only supported effect value now is EchoCancellation or aec."), Argument::value("serial", - "type=TYPE,[num=NUM,path=PATH,input=PATH,console,stdin]", + "type=TYPE,[hardware=HW,num=NUM,path=PATH,input=PATH,console,earlycon,stdin]", "Comma separated key=value pairs for setting up serial devices. Can be given more than once. Possible key values: type=(stdout,syslog,sink,file) - Where to route the serial device + hardware=(serial,virtio-console) - Which type of serial hardware to emulate. Defaults to 8250 UART (serial). num=(1,2,3,4) - Serial Device Number. If not provided, num will default to 1. path=PATH - The path to the file to write to when type=file input=PATH - The path to the file to read from when not stdin console - Use this serial device as the guest console. Can only be given once. Will default to first serial port if not provided. + earlycon - Use this serial device as the early console. Can only be given once. stdin - Direct standard input to this serial device. Can only be given once. Will default to first serial port if not provided. "), Argument::value("syslog-tag", "TAG", "When logging to syslog, use the provided tag."), |