mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-22 04:25:21 +00:00
vmm: Support both reset and shutdown
Add a 2nd EventFd to the VM to control resetting (rebooting) the VM this supplements the EventFd used for managing shutdown of the VM. The default behaviour on i8042 or triple-fault based reset is currently unchanged i.e. it will trigger a shutdown. In order to support restarting the VM it was necessary to make start() function take a reference to the config. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
ebe8edd423
commit
ae66a44d26
@ -34,6 +34,7 @@ impl BusDevice for I8042Device {
|
||||
|
||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) {
|
||||
if data.len() == 1 && data[0] == 0xfe && offset == 3 {
|
||||
debug!("i8042 reset signalled");
|
||||
if let Err(e) = self.reset_evt.write(1) {
|
||||
error!("Error triggering i8042 reset event: {}", e);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ pub mod config;
|
||||
pub mod vm;
|
||||
|
||||
use self::config::VmConfig;
|
||||
use self::vm::Vm;
|
||||
use self::vm::{ExitBehaviour, Vm};
|
||||
|
||||
/// Errors associated with VM management
|
||||
#[derive(Debug)]
|
||||
@ -55,11 +55,15 @@ impl Vmm {
|
||||
}
|
||||
|
||||
pub fn boot_kernel(config: VmConfig) -> Result<()> {
|
||||
let vmm = Vmm::new()?;
|
||||
let mut vm = Vm::new(&vmm.kvm, config).map_err(Error::VmNew)?;
|
||||
loop {
|
||||
let vmm = Vmm::new()?;
|
||||
let mut vm = Vm::new(&vmm.kvm, &config).map_err(Error::VmNew)?;
|
||||
|
||||
let entry = vm.load_kernel().map_err(Error::LoadKernel)?;
|
||||
vm.start(entry).map_err(Error::VmStart)?;
|
||||
let entry = vm.load_kernel().map_err(Error::LoadKernel)?;
|
||||
if vm.start(entry).map_err(Error::VmStart)? == ExitBehaviour::Shutdown {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -605,9 +605,12 @@ struct DeviceManager {
|
||||
serial: Option<Arc<Mutex<devices::legacy::Serial>>>,
|
||||
console_input: Option<Arc<vm_virtio::ConsoleInput>>,
|
||||
|
||||
// i8042 device for exit
|
||||
// i8042 device for i8042 reset
|
||||
i8042: Arc<Mutex<devices::legacy::I8042Device>>,
|
||||
|
||||
// Shutdown (exit) and reboot (reset) control
|
||||
exit_evt: EventFd,
|
||||
reset_evt: EventFd,
|
||||
|
||||
// IOAPIC
|
||||
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
||||
@ -679,6 +682,7 @@ impl DeviceManager {
|
||||
|
||||
// Add a shutdown device (i8042)
|
||||
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?;
|
||||
let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(DeviceManagerError::EventFd)?;
|
||||
let i8042 = Arc::new(Mutex::new(devices::legacy::I8042Device::new(
|
||||
exit_evt.try_clone().map_err(DeviceManagerError::EventFd)?,
|
||||
)));
|
||||
@ -734,6 +738,7 @@ impl DeviceManager {
|
||||
console_input: console,
|
||||
i8042,
|
||||
exit_evt,
|
||||
reset_evt,
|
||||
ioapic,
|
||||
pci,
|
||||
})
|
||||
@ -1298,6 +1303,7 @@ impl DeviceManager {
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
enum EpollDispatch {
|
||||
Exit,
|
||||
Reset,
|
||||
Stdin,
|
||||
}
|
||||
|
||||
@ -1313,7 +1319,7 @@ impl EpollContext {
|
||||
// Initial capacity needs to be large enough to hold:
|
||||
// * 1 exit event
|
||||
// * 1 stdin event
|
||||
let mut dispatch_table = Vec::with_capacity(3);
|
||||
let mut dispatch_table = Vec::with_capacity(4);
|
||||
dispatch_table.push(None);
|
||||
|
||||
Ok(EpollContext {
|
||||
@ -1359,6 +1365,12 @@ impl AsRawFd for EpollContext {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum ExitBehaviour {
|
||||
Shutdown = 1,
|
||||
Reset = 2,
|
||||
}
|
||||
|
||||
pub struct Vm<'a> {
|
||||
fd: Arc<VmFd>,
|
||||
kernel: File,
|
||||
@ -1366,14 +1378,14 @@ pub struct Vm<'a> {
|
||||
vcpus: Vec<thread::JoinHandle<()>>,
|
||||
devices: DeviceManager,
|
||||
cpuid: CpuId,
|
||||
config: VmConfig<'a>,
|
||||
config: &'a VmConfig<'a>,
|
||||
epoll: EpollContext,
|
||||
on_tty: bool,
|
||||
creation_ts: std::time::Instant,
|
||||
}
|
||||
|
||||
impl<'a> Vm<'a> {
|
||||
pub fn new(kvm: &Kvm, config: VmConfig<'a>) -> Result<Self> {
|
||||
pub fn new(kvm: &Kvm, config: &'a VmConfig<'a>) -> Result<Self> {
|
||||
let kernel = File::open(&config.kernel.path).map_err(Error::KernelFile)?;
|
||||
let fd = kvm.create_vm().map_err(Error::VmCreate)?;
|
||||
let fd = Arc::new(fd);
|
||||
@ -1553,7 +1565,7 @@ impl<'a> Vm<'a> {
|
||||
let vm_info = VmInfo {
|
||||
memory: &guest_memory,
|
||||
vm_fd: &fd,
|
||||
vm_cfg: &config,
|
||||
vm_cfg: config,
|
||||
};
|
||||
|
||||
let device_manager = DeviceManager::new(
|
||||
@ -1577,6 +1589,9 @@ impl<'a> Vm<'a> {
|
||||
epoll
|
||||
.add_event(&device_manager.exit_evt, EpollDispatch::Exit)
|
||||
.map_err(Error::EpollError)?;
|
||||
epoll
|
||||
.add_event(&device_manager.reset_evt, EpollDispatch::Reset)
|
||||
.map_err(Error::EpollError)?;
|
||||
|
||||
let vcpus = Vec::with_capacity(u8::from(&config.cpus) as usize);
|
||||
|
||||
@ -1662,7 +1677,7 @@ impl<'a> Vm<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn control_loop(&mut self) -> Result<()> {
|
||||
pub fn control_loop(&mut self) -> Result<ExitBehaviour> {
|
||||
// Let's start the STDIN polling thread.
|
||||
const EPOLL_EVENTS_LEN: usize = 100;
|
||||
|
||||
@ -1676,6 +1691,8 @@ impl<'a> Vm<'a> {
|
||||
.map_err(Error::SetTerminalRaw)?;
|
||||
}
|
||||
|
||||
let exit_behaviour;
|
||||
|
||||
'outer: loop {
|
||||
let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
|
||||
Ok(res) => res,
|
||||
@ -1702,6 +1719,14 @@ impl<'a> Vm<'a> {
|
||||
EpollDispatch::Exit => {
|
||||
// Consume the event.
|
||||
self.devices.exit_evt.read().map_err(Error::EventFd)?;
|
||||
exit_behaviour = ExitBehaviour::Shutdown;
|
||||
|
||||
break 'outer;
|
||||
}
|
||||
EpollDispatch::Reset => {
|
||||
// Consume the event.
|
||||
self.devices.reset_evt.read().map_err(Error::EventFd)?;
|
||||
exit_behaviour = ExitBehaviour::Reset;
|
||||
|
||||
break 'outer;
|
||||
}
|
||||
@ -1749,7 +1774,7 @@ impl<'a> Vm<'a> {
|
||||
.map_err(Error::SetTerminalCanon)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(exit_behaviour)
|
||||
}
|
||||
|
||||
fn os_signal_handler(signals: Signals, console_input_clone: Arc<vm_virtio::ConsoleInput>) {
|
||||
@ -1761,7 +1786,7 @@ impl<'a> Vm<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self, entry_addr: GuestAddress) -> Result<()> {
|
||||
pub fn start(&mut self, entry_addr: GuestAddress) -> Result<ExitBehaviour> {
|
||||
self.devices.register_devices()?;
|
||||
|
||||
let vcpu_count = u8::from(&self.config.cpus);
|
||||
@ -1824,9 +1849,7 @@ impl<'a> Vm<'a> {
|
||||
Err(e) => error!("Signal not found {}", e),
|
||||
}
|
||||
}
|
||||
self.control_loop()?;
|
||||
|
||||
Ok(())
|
||||
self.control_loop()
|
||||
}
|
||||
|
||||
/// Gets an Arc to the guest memory owned by this VM.
|
||||
|
Loading…
x
Reference in New Issue
Block a user