devices, vmm: Use a bit field for ACPI GED interrupt type

Use independent bits for storing whether there is a CPU or memory device
changed when reporting changes via ACPI GED interrupt. This prevents a
later notification squashing an earlier one and ensure that hotplugging
both CPU and memory at the same time succeeds.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-01-14 10:17:23 +00:00 committed by Samuel Ortiz
parent d2d1248342
commit 7310ab6fa7
6 changed files with 27 additions and 19 deletions

1
Cargo.lock generated
View File

@ -234,6 +234,7 @@ dependencies = [
name = "devices" name = "devices"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"epoll 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "epoll 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kvm-bindings 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kvm-bindings 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -4,6 +4,7 @@ version = "0.1.0"
authors = ["The Chromium OS Authors"] authors = ["The Chromium OS Authors"]
[dependencies] [dependencies]
bitflags = ">=1.2.1"
byteorder = "1.3.2" byteorder = "1.3.2"
epoll = ">=4.0.1" epoll = ">=4.0.1"
kvm-bindings = "0.2.0" kvm-bindings = "0.2.0"

View File

@ -5,7 +5,7 @@
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
use BusDevice; use BusDevice;
use HotPlugNotificationType; use HotPlugNotificationFlags;
use Interrupt; use Interrupt;
/// A device for handling ACPI shutdown and reboot /// A device for handling ACPI shutdown and reboot
@ -46,6 +46,7 @@ impl BusDevice for AcpiShutdownDevice {
const SLEEP_VALUE_BIT: u8 = 2; const SLEEP_VALUE_BIT: u8 = 2;
if data[0] == (S5_SLEEP_VALUE << SLEEP_VALUE_BIT) | (1 << SLEEP_STATUS_EN_BIT) { if data[0] == (S5_SLEEP_VALUE << SLEEP_VALUE_BIT) | (1 << SLEEP_STATUS_EN_BIT) {
debug!("ACPI Shutdown signalled"); debug!("ACPI Shutdown signalled");
extern crate bitflags;
if let Err(e) = self.exit_evt.write(1) { if let Err(e) = self.exit_evt.write(1) {
error!("Error triggering ACPI shutdown event: {}", e); error!("Error triggering ACPI shutdown event: {}", e);
} }
@ -56,7 +57,7 @@ impl BusDevice for AcpiShutdownDevice {
/// A device for handling ACPI GED event generation /// A device for handling ACPI GED event generation
pub struct AcpiGEDDevice { pub struct AcpiGEDDevice {
interrupt: Box<dyn Interrupt>, interrupt: Box<dyn Interrupt>,
notification_type: HotPlugNotificationType, notification_type: HotPlugNotificationFlags,
ged_irq: u32, ged_irq: u32,
} }
@ -64,16 +65,16 @@ impl AcpiGEDDevice {
pub fn new(interrupt: Box<dyn Interrupt>, ged_irq: u32) -> AcpiGEDDevice { pub fn new(interrupt: Box<dyn Interrupt>, ged_irq: u32) -> AcpiGEDDevice {
AcpiGEDDevice { AcpiGEDDevice {
interrupt, interrupt,
notification_type: HotPlugNotificationType::NoDevicesChanged, notification_type: HotPlugNotificationFlags::NO_DEVICES_CHANGED,
ged_irq, ged_irq,
} }
} }
pub fn notify( pub fn notify(
&mut self, &mut self,
notification_type: HotPlugNotificationType, notification_type: HotPlugNotificationFlags,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
self.notification_type = notification_type; self.notification_type |= notification_type;
self.interrupt.deliver() self.interrupt.deliver()
} }
@ -86,8 +87,8 @@ impl AcpiGEDDevice {
impl BusDevice for AcpiGEDDevice { impl BusDevice for AcpiGEDDevice {
// Spec has all fields as zero // Spec has all fields as zero
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) { fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
data[0] = self.notification_type as u8; data[0] = self.notification_type.bits();
self.notification_type = HotPlugNotificationType::NoDevicesChanged; self.notification_type = HotPlugNotificationFlags::NO_DEVICES_CHANGED;
} }
fn write(&mut self, _base: u64, _offset: u64, _data: &[u8]) {} fn write(&mut self, _base: u64, _offset: u64, _data: &[u8]) {}

View File

@ -6,6 +6,8 @@
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
//! Emulates virtual and hardware devices. //! Emulates virtual and hardware devices.
#[macro_use]
extern crate bitflags;
extern crate byteorder; extern crate byteorder;
extern crate epoll; extern crate epoll;
extern crate kvm_bindings; extern crate kvm_bindings;
@ -71,9 +73,10 @@ pub trait Interrupt: Send + Sync {
fn deliver(&self) -> result::Result<(), std::io::Error>; fn deliver(&self) -> result::Result<(), std::io::Error>;
} }
#[derive(Clone, Copy)] bitflags! {
pub enum HotPlugNotificationType { pub struct HotPlugNotificationFlags: u8 {
NoDevicesChanged, const NO_DEVICES_CHANGED = 0;
CPUDevicesChanged, const CPU_DEVICES_CHANGED = 0b1;
MemoryDevicesChanged, const MEMORY_DEVICES_CHANGED = 0b10;
}
} }

View File

@ -19,7 +19,7 @@ use acpi_tables::{aml, aml::Aml};
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use arch::layout; use arch::layout;
use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START}; use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START};
use devices::{ioapic, HotPlugNotificationType}; use devices::{ioapic, HotPlugNotificationFlags};
use kvm_bindings::kvm_irq_routing_entry; use kvm_bindings::kvm_irq_routing_entry;
use kvm_ioctls::*; use kvm_ioctls::*;
use libc::O_TMPFILE; use libc::O_TMPFILE;
@ -1618,7 +1618,7 @@ impl DeviceManager {
pub fn notify_hotplug( pub fn notify_hotplug(
&self, &self,
_notification_type: HotPlugNotificationType, _notification_type: HotPlugNotificationFlags,
) -> DeviceManagerResult<()> { ) -> DeviceManagerResult<()> {
#[cfg(feature = "acpi")] #[cfg(feature = "acpi")]
return self return self
@ -1670,12 +1670,14 @@ fn create_ged_device(ged_irq: u32) -> Vec<u8> {
true, true,
vec![ vec![
&aml::Store::new(&aml::Local(0), &aml::Path::new("GDAT")), &aml::Store::new(&aml::Local(0), &aml::Path::new("GDAT")),
&aml::And::new(&aml::Local(1), &aml::Local(0), &aml::ONE),
&aml::If::new( &aml::If::new(
&aml::Equal::new(&aml::Local(0), &aml::ONE), &aml::Equal::new(&aml::Local(1), &aml::ONE),
vec![&aml::MethodCall::new("\\_SB_.CPUS.CSCN".into(), vec![])], vec![&aml::MethodCall::new("\\_SB_.CPUS.CSCN".into(), vec![])],
), ),
&aml::And::new(&aml::Local(1), &aml::Local(0), &2usize),
&aml::If::new( &aml::If::new(
&aml::Equal::new(&aml::Local(0), &2usize), &aml::Equal::new(&aml::Local(1), &2usize),
vec![&aml::MethodCall::new("\\_SB_.MHPC.MSCN".into(), vec![])], vec![&aml::MethodCall::new("\\_SB_.MHPC.MSCN".into(), vec![])],
), ),
], ],

View File

@ -31,7 +31,7 @@ use crate::memory_manager::{get_host_cpu_phys_bits, Error as MemoryManagerError,
use anyhow::anyhow; use anyhow::anyhow;
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use arch::layout; use arch::layout;
use devices::{ioapic, HotPlugNotificationType}; use devices::{ioapic, HotPlugNotificationFlags};
use kvm_bindings::{kvm_enable_cap, kvm_userspace_memory_region, KVM_CAP_SPLIT_IRQCHIP}; use kvm_bindings::{kvm_enable_cap, kvm_userspace_memory_region, KVM_CAP_SPLIT_IRQCHIP};
use kvm_ioctls::*; use kvm_ioctls::*;
use linux_loader::cmdline::Cmdline; use linux_loader::cmdline::Cmdline;
@ -491,7 +491,7 @@ impl Vm {
.resize(desired_vcpus) .resize(desired_vcpus)
.map_err(Error::CpuManager)?; .map_err(Error::CpuManager)?;
self.devices self.devices
.notify_hotplug(HotPlugNotificationType::CPUDevicesChanged) .notify_hotplug(HotPlugNotificationFlags::CPU_DEVICES_CHANGED)
.map_err(Error::DeviceManager)?; .map_err(Error::DeviceManager)?;
self.config.lock().unwrap().cpus.boot_vcpus = desired_vcpus; self.config.lock().unwrap().cpus.boot_vcpus = desired_vcpus;
} }
@ -503,7 +503,7 @@ impl Vm {
.resize(desired_memory) .resize(desired_memory)
.map_err(Error::MemoryManager)?; .map_err(Error::MemoryManager)?;
self.devices self.devices
.notify_hotplug(HotPlugNotificationType::MemoryDevicesChanged) .notify_hotplug(HotPlugNotificationFlags::MEMORY_DEVICES_CHANGED)
.map_err(Error::DeviceManager)?; .map_err(Error::DeviceManager)?;
self.config.lock().unwrap().memory.size = desired_memory; self.config.lock().unwrap().memory.size = desired_memory;
} }