mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-03 03:15:20 +00:00
vm-virtio: Enable the vmm support for virtio-console
To use the implemented virtio console device, the users can select one of the three options ("off", "tty" or "file=/path/to/the/file") with the command line argument "--console". By default, the console is enabled as a device named "hvc0" (option: tty). When "off" option is used, the console device is not added to the VM configuration at all. Signed-off-by: A K M Fazla Mehrab <fazla.mehrab.akm@intel.com>
This commit is contained in:
parent
577d44c8eb
commit
24438e0390
@ -92,6 +92,12 @@ fn main() {
|
|||||||
Arg::with_name("serial")
|
Arg::with_name("serial")
|
||||||
.long("serial")
|
.long("serial")
|
||||||
.help("Control serial port: off|tty|file=/path/to/a/file")
|
.help("Control serial port: off|tty|file=/path/to/a/file")
|
||||||
|
.default_value("off"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("console")
|
||||||
|
.long("console")
|
||||||
|
.help("Control (virtio) console: off|tty|file=/path/to/a/file")
|
||||||
.default_value("tty"),
|
.default_value("tty"),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
@ -109,6 +115,7 @@ fn main() {
|
|||||||
|
|
||||||
let disks: Option<Vec<&str>> = cmd_arguments.values_of("disk").map(|x| x.collect());
|
let disks: Option<Vec<&str>> = cmd_arguments.values_of("disk").map(|x| x.collect());
|
||||||
let net: Option<Vec<&str>> = cmd_arguments.values_of("net").map(|x| x.collect());
|
let net: Option<Vec<&str>> = cmd_arguments.values_of("net").map(|x| x.collect());
|
||||||
|
let console = cmd_arguments.value_of("console").unwrap();
|
||||||
let fs: Option<Vec<&str>> = cmd_arguments.values_of("fs").map(|x| x.collect());
|
let fs: Option<Vec<&str>> = cmd_arguments.values_of("fs").map(|x| x.collect());
|
||||||
let pmem: Option<Vec<&str>> = cmd_arguments.values_of("pmem").map(|x| x.collect());
|
let pmem: Option<Vec<&str>> = cmd_arguments.values_of("pmem").map(|x| x.collect());
|
||||||
|
|
||||||
@ -123,6 +130,7 @@ fn main() {
|
|||||||
fs,
|
fs,
|
||||||
pmem,
|
pmem,
|
||||||
serial,
|
serial,
|
||||||
|
console,
|
||||||
}) {
|
}) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -50,8 +50,10 @@ pub enum Error<'a> {
|
|||||||
ParsePmemFileParam,
|
ParsePmemFileParam,
|
||||||
/// Failed parsing size parameter.
|
/// Failed parsing size parameter.
|
||||||
ParseSizeParam(std::num::ParseIntError),
|
ParseSizeParam(std::num::ParseIntError),
|
||||||
/// Failed parsing serial parameter.
|
/// Failed parsing console parameter.
|
||||||
ParseSerialParam,
|
ParseConsoleParam,
|
||||||
|
/// Both console and serial are tty.
|
||||||
|
ParseTTYParam,
|
||||||
}
|
}
|
||||||
pub type Result<'a, T> = result::Result<T, Error<'a>>;
|
pub type Result<'a, T> = result::Result<T, Error<'a>>;
|
||||||
|
|
||||||
@ -66,6 +68,7 @@ pub struct VmParams<'a> {
|
|||||||
pub fs: Option<Vec<&'a str>>,
|
pub fs: Option<Vec<&'a str>>,
|
||||||
pub pmem: Option<Vec<&'a str>>,
|
pub pmem: Option<Vec<&'a str>>,
|
||||||
pub serial: &'a str,
|
pub serial: &'a str,
|
||||||
|
pub console: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_size(size: &str) -> Result<u64> {
|
fn parse_size(size: &str) -> Result<u64> {
|
||||||
@ -342,36 +345,36 @@ impl<'a> PmemConfig<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum SerialOutputMode {
|
pub enum ConsoleOutputMode {
|
||||||
Off,
|
Off,
|
||||||
Tty,
|
Tty,
|
||||||
File,
|
File,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SerialConfig<'a> {
|
pub struct ConsoleConfig<'a> {
|
||||||
pub file: Option<&'a Path>,
|
pub file: Option<&'a Path>,
|
||||||
pub mode: SerialOutputMode,
|
pub mode: ConsoleOutputMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SerialConfig<'a> {
|
impl<'a> ConsoleConfig<'a> {
|
||||||
pub fn parse(param: &'a str) -> Result<Self> {
|
pub fn parse(param: &'a str) -> Result<Self> {
|
||||||
if param == "off" {
|
if param == "off" {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
mode: SerialOutputMode::Off,
|
mode: ConsoleOutputMode::Off,
|
||||||
file: None,
|
file: None,
|
||||||
})
|
})
|
||||||
} else if param == "tty" {
|
} else if param == "tty" {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
mode: SerialOutputMode::Tty,
|
mode: ConsoleOutputMode::Tty,
|
||||||
file: None,
|
file: None,
|
||||||
})
|
})
|
||||||
} else if param.starts_with("file=") {
|
} else if param.starts_with("file=") {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
mode: SerialOutputMode::File,
|
mode: ConsoleOutputMode::File,
|
||||||
file: Some(Path::new(¶m[5..])),
|
file: Some(Path::new(¶m[5..])),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::ParseSerialParam)
|
Err(Error::ParseConsoleParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,7 +389,8 @@ pub struct VmConfig<'a> {
|
|||||||
pub rng: RngConfig<'a>,
|
pub rng: RngConfig<'a>,
|
||||||
pub fs: Option<Vec<FsConfig<'a>>>,
|
pub fs: Option<Vec<FsConfig<'a>>>,
|
||||||
pub pmem: Option<Vec<PmemConfig<'a>>>,
|
pub pmem: Option<Vec<PmemConfig<'a>>>,
|
||||||
pub serial: SerialConfig<'a>,
|
pub serial: ConsoleConfig<'a>,
|
||||||
|
pub console: ConsoleConfig<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VmConfig<'a> {
|
impl<'a> VmConfig<'a> {
|
||||||
@ -427,6 +431,12 @@ impl<'a> VmConfig<'a> {
|
|||||||
pmem = Some(pmem_config_list);
|
pmem = Some(pmem_config_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let console = ConsoleConfig::parse(vm_params.console)?;
|
||||||
|
let serial = ConsoleConfig::parse(vm_params.serial)?;
|
||||||
|
if console.mode == ConsoleOutputMode::Tty && serial.mode == ConsoleOutputMode::Tty {
|
||||||
|
return Err(Error::ParseTTYParam);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(VmConfig {
|
Ok(VmConfig {
|
||||||
cpus: CpusConfig::parse(vm_params.cpus)?,
|
cpus: CpusConfig::parse(vm_params.cpus)?,
|
||||||
memory: MemoryConfig::parse(vm_params.memory)?,
|
memory: MemoryConfig::parse(vm_params.memory)?,
|
||||||
@ -437,7 +447,8 @@ impl<'a> VmConfig<'a> {
|
|||||||
rng: RngConfig::parse(vm_params.rng)?,
|
rng: RngConfig::parse(vm_params.rng)?,
|
||||||
fs,
|
fs,
|
||||||
pmem,
|
pmem,
|
||||||
serial: SerialConfig::parse(vm_params.serial)?,
|
serial,
|
||||||
|
console,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ extern crate vm_memory;
|
|||||||
extern crate vm_virtio;
|
extern crate vm_virtio;
|
||||||
extern crate vmm_sys_util;
|
extern crate vmm_sys_util;
|
||||||
|
|
||||||
use crate::config::{SerialOutputMode, VmConfig};
|
use crate::config::{ConsoleOutputMode, VmConfig};
|
||||||
use arch::RegionType;
|
use arch::RegionType;
|
||||||
use devices::ioapic;
|
use devices::ioapic;
|
||||||
use kvm_bindings::{
|
use kvm_bindings::{
|
||||||
@ -142,6 +142,9 @@ pub enum Error {
|
|||||||
/// Write to the serial console failed.
|
/// Write to the serial console failed.
|
||||||
Serial(vmm_sys_util::Error),
|
Serial(vmm_sys_util::Error),
|
||||||
|
|
||||||
|
/// Write to the virtio console failed.
|
||||||
|
Console(vmm_sys_util::Error),
|
||||||
|
|
||||||
/// Cannot setup terminal in raw mode.
|
/// Cannot setup terminal in raw mode.
|
||||||
SetTerminalRaw(vmm_sys_util::Error),
|
SetTerminalRaw(vmm_sys_util::Error),
|
||||||
|
|
||||||
@ -189,6 +192,9 @@ pub enum DeviceManagerError {
|
|||||||
/// Cannot create virtio-net device
|
/// Cannot create virtio-net device
|
||||||
CreateVirtioNet(vm_virtio::net::Error),
|
CreateVirtioNet(vm_virtio::net::Error),
|
||||||
|
|
||||||
|
/// Cannot create virtio-console device
|
||||||
|
CreateVirtioConsole(io::Error),
|
||||||
|
|
||||||
/// Cannot create virtio-rng device
|
/// Cannot create virtio-rng device
|
||||||
CreateVirtioRng(io::Error),
|
CreateVirtioRng(io::Error),
|
||||||
|
|
||||||
@ -236,6 +242,9 @@ pub enum DeviceManagerError {
|
|||||||
|
|
||||||
/// Error creating serial output file
|
/// Error creating serial output file
|
||||||
SerialOutputFileOpen(io::Error),
|
SerialOutputFileOpen(io::Error),
|
||||||
|
|
||||||
|
/// Error creating console output file
|
||||||
|
ConsoleOutputFileOpen(io::Error),
|
||||||
}
|
}
|
||||||
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
|
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
|
||||||
|
|
||||||
@ -483,6 +492,7 @@ struct DeviceManager {
|
|||||||
|
|
||||||
// Serial port on 0x3f8
|
// Serial port on 0x3f8
|
||||||
serial: Option<Arc<Mutex<devices::legacy::Serial>>>,
|
serial: Option<Arc<Mutex<devices::legacy::Serial>>>,
|
||||||
|
console: Option<Arc<vm_virtio::ConsoleInput>>,
|
||||||
|
|
||||||
// i8042 device for exit
|
// i8042 device for exit
|
||||||
i8042: Arc<Mutex<devices::legacy::I8042Device>>,
|
i8042: Arc<Mutex<devices::legacy::I8042Device>>,
|
||||||
@ -525,12 +535,12 @@ impl DeviceManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let serial_writer: Option<Box<io::Write + Send>> = match vm_cfg.serial.mode {
|
let serial_writer: Option<Box<io::Write + Send>> = match vm_cfg.serial.mode {
|
||||||
SerialOutputMode::File => Some(Box::new(
|
ConsoleOutputMode::File => Some(Box::new(
|
||||||
File::create(vm_cfg.serial.file.unwrap())
|
File::create(vm_cfg.serial.file.unwrap())
|
||||||
.map_err(DeviceManagerError::SerialOutputFileOpen)?,
|
.map_err(DeviceManagerError::SerialOutputFileOpen)?,
|
||||||
)),
|
)),
|
||||||
SerialOutputMode::Tty => Some(Box::new(stdout())),
|
ConsoleOutputMode::Tty => Some(Box::new(stdout())),
|
||||||
SerialOutputMode::Off => None,
|
ConsoleOutputMode::Off => None,
|
||||||
};
|
};
|
||||||
let serial = if serial_writer.is_some() {
|
let serial = if serial_writer.is_some() {
|
||||||
// Serial is tied to IRQ #4
|
// Serial is tied to IRQ #4
|
||||||
@ -632,6 +642,31 @@ impl DeviceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let console_writer: Option<Box<io::Write + Send>> = match vm_cfg.console.mode {
|
||||||
|
ConsoleOutputMode::File => Some(Box::new(
|
||||||
|
File::create(vm_cfg.console.file.unwrap())
|
||||||
|
.map_err(DeviceManagerError::ConsoleOutputFileOpen)?,
|
||||||
|
)),
|
||||||
|
ConsoleOutputMode::Tty => Some(Box::new(stdout())),
|
||||||
|
ConsoleOutputMode::Off => None,
|
||||||
|
};
|
||||||
|
let console = if console_writer.is_some() {
|
||||||
|
let (virtio_console_device, console) = vm_virtio::Console::new(console_writer)
|
||||||
|
.map_err(DeviceManagerError::CreateVirtioConsole)?;
|
||||||
|
DeviceManager::add_virtio_pci_device(
|
||||||
|
Box::new(virtio_console_device),
|
||||||
|
memory.clone(),
|
||||||
|
allocator,
|
||||||
|
vm_fd,
|
||||||
|
&mut pci,
|
||||||
|
&mut buses,
|
||||||
|
&interrupt_info,
|
||||||
|
)?;
|
||||||
|
Some(console)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Add virtio-rng if required
|
// Add virtio-rng if required
|
||||||
if let Some(rng_path) = vm_cfg.rng.src.to_str() {
|
if let Some(rng_path) = vm_cfg.rng.src.to_str() {
|
||||||
let virtio_rng_device =
|
let virtio_rng_device =
|
||||||
@ -745,6 +780,7 @@ impl DeviceManager {
|
|||||||
io_bus,
|
io_bus,
|
||||||
mmio_bus,
|
mmio_bus,
|
||||||
serial,
|
serial,
|
||||||
|
console,
|
||||||
i8042,
|
i8042,
|
||||||
exit_evt,
|
exit_evt,
|
||||||
ioapic,
|
ioapic,
|
||||||
@ -1253,7 +1289,7 @@ impl<'a> Vm<'a> {
|
|||||||
let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
|
let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
|
||||||
let epoll_fd = self.epoll.as_raw_fd();
|
let epoll_fd = self.epoll.as_raw_fd();
|
||||||
|
|
||||||
if self.devices.serial.is_some() && self.on_tty {
|
if (self.devices.serial.is_some() || self.devices.console.is_some()) && self.on_tty {
|
||||||
io::stdin()
|
io::stdin()
|
||||||
.lock()
|
.lock()
|
||||||
.set_raw_mode()
|
.set_raw_mode()
|
||||||
@ -1276,13 +1312,13 @@ impl<'a> Vm<'a> {
|
|||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
EpollDispatch::Stdin => {
|
EpollDispatch::Stdin => {
|
||||||
if self.devices.serial.is_some() {
|
let mut out = [0u8; 64];
|
||||||
let mut out = [0u8; 64];
|
let count = io::stdin()
|
||||||
let count = io::stdin()
|
.lock()
|
||||||
.lock()
|
.read_raw(&mut out)
|
||||||
.read_raw(&mut out)
|
.map_err(Error::Serial)?;
|
||||||
.map_err(Error::Serial)?;
|
|
||||||
|
|
||||||
|
if self.devices.serial.is_some() {
|
||||||
self.devices
|
self.devices
|
||||||
.serial
|
.serial
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -1292,6 +1328,14 @@ impl<'a> Vm<'a> {
|
|||||||
.queue_input_bytes(&out[..count])
|
.queue_input_bytes(&out[..count])
|
||||||
.map_err(Error::Serial)?;
|
.map_err(Error::Serial)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.devices.console.is_some() {
|
||||||
|
self.devices
|
||||||
|
.console
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.queue_input_bytes(&out[..count]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user