diff --git a/vm-allocator/src/gsi.rs b/vm-allocator/src/gsi.rs new file mode 100644 index 000000000..88e05bf8e --- /dev/null +++ b/vm-allocator/src/gsi.rs @@ -0,0 +1,84 @@ +// Copyright © 2019 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause + +use std::collections::btree_map::BTreeMap; +use std::result; + +#[derive(Debug)] +pub enum Error { + Overflow, +} + +pub type Result = result::Result; + +/// GsiApic +#[derive(Copy, Clone)] +pub struct GsiApic { + base: u32, + irqs: u32, +} + +impl GsiApic { + /// New GSI APIC + pub fn new(base: u32, irqs: u32) -> Self { + GsiApic { base, irqs } + } +} + +/// GsiAllocator +pub struct GsiAllocator { + apics: BTreeMap, + next_irq: u32, + next_gsi: u32, +} + +impl GsiAllocator { + /// New GSI allocator + pub fn new(apics: Vec) -> Self { + let mut allocator = GsiAllocator { + apics: BTreeMap::new(), + next_irq: 0xffff_ffff, + next_gsi: 0, + }; + + for apic in &apics { + if apic.base < allocator.next_irq { + allocator.next_irq = apic.base; + } + + if apic.base + apic.irqs > allocator.next_gsi { + allocator.next_gsi = apic.base + apic.irqs; + } + + allocator.apics.insert(apic.base, apic.irqs); + } + + allocator + } + + /// Allocate a GSI + pub fn allocate_gsi(&mut self) -> Result { + self.next_gsi = self.next_gsi.checked_add(1).ok_or(Error::Overflow)?; + + Ok(self.next_gsi - 1) + } + + /// Allocate an IRQ + pub fn allocate_irq(&mut self) -> Result { + let mut irq: u32 = 0; + for (base, irqs) in self.apics.iter() { + // HACKHACK - This only works with 1 single IOAPIC... + if self.next_irq >= *base && self.next_irq < *base + *irqs { + irq = self.next_irq; + self.next_irq += 1; + } + } + + if irq == 0 { + return Err(Error::Overflow); + } + + Ok(irq) + } +} diff --git a/vm-allocator/src/lib.rs b/vm-allocator/src/lib.rs index 4a14420dd..15d431ce5 100644 --- a/vm-allocator/src/lib.rs +++ b/vm-allocator/src/lib.rs @@ -14,7 +14,9 @@ extern crate libc; extern crate vm_memory; mod address; +mod gsi; mod system; pub use crate::address::AddressAllocator; +pub use crate::gsi::{GsiAllocator, GsiApic}; pub use crate::system::SystemAllocator; diff --git a/vm-allocator/src/system.rs b/vm-allocator/src/system.rs index e83682540..acb8b4926 100755 --- a/vm-allocator/src/system.rs +++ b/vm-allocator/src/system.rs @@ -10,6 +10,7 @@ use vm_memory::{GuestAddress, GuestUsize}; use crate::address::AddressAllocator; +use crate::gsi::{GsiAllocator, GsiApic}; use libc::{sysconf, _SC_PAGESIZE}; @@ -25,12 +26,12 @@ fn pagesize() -> usize { /// # Example - Use the `SystemAddress` builder. /// /// ``` -/// # use vm_allocator::SystemAllocator; +/// # use vm_allocator::{GsiApic, SystemAllocator}; /// # use vm_memory::{Address, GuestAddress, GuestUsize}; /// let mut allocator = SystemAllocator::new( /// GuestAddress(0x1000), 0x10000, /// GuestAddress(0x10000000), 0x10000000, -/// 5).unwrap(); +/// vec![GsiApic::new(5, 19)]).unwrap(); /// assert_eq!(allocator.allocate_irq(), Some(5)); /// assert_eq!(allocator.allocate_irq(), Some(6)); /// assert_eq!(allocator.allocate_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fffe000))); @@ -39,7 +40,7 @@ fn pagesize() -> usize { pub struct SystemAllocator { io_address_space: AddressAllocator, mmio_address_space: AddressAllocator, - next_irq: u32, + gsi_allocator: GsiAllocator, } impl SystemAllocator { @@ -56,23 +57,23 @@ impl SystemAllocator { io_size: GuestUsize, mmio_base: GuestAddress, mmio_size: GuestUsize, - first_irq: u32, + apics: Vec, ) -> Option { Some(SystemAllocator { io_address_space: AddressAllocator::new(io_base, io_size)?, mmio_address_space: AddressAllocator::new(mmio_base, mmio_size)?, - next_irq: first_irq, + gsi_allocator: GsiAllocator::new(apics), }) } /// Reserves the next available system irq number. pub fn allocate_irq(&mut self) -> Option { - if let Some(irq_num) = self.next_irq.checked_add(1) { - self.next_irq = irq_num; - Some(irq_num - 1) - } else { - None - } + self.gsi_allocator.allocate_irq().ok() + } + + /// Reserves the next available GSI. + pub fn allocate_gsi(&mut self) -> Option { + self.gsi_allocator.allocate_gsi().ok() } /// Reserves a section of `size` bytes of IO address space. diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 9b48f0abb..e322eab1b 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -44,7 +44,7 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::ptr::null_mut; use std::sync::{Arc, Barrier, Mutex}; use std::{result, str, thread}; -use vm_allocator::SystemAllocator; +use vm_allocator::{GsiApic, SystemAllocator}; use vm_memory::guest_memory::FileOffset; use vm_memory::{ Address, Bytes, Error as MmapError, GuestAddress, GuestMemory, GuestMemoryMmap, @@ -1066,13 +1066,18 @@ impl<'a> Vm<'a> { CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches); + let ioapic = GsiApic::new( + X86_64_IRQ_BASE, + ioapic::NUM_IOAPIC_PINS as u32 - X86_64_IRQ_BASE, + ); + // Let's allocate 64 GiB of addressable MMIO space, starting at 0. let mut allocator = SystemAllocator::new( GuestAddress(0), 1 << 16 as GuestUsize, GuestAddress(0), 1 << 36 as GuestUsize, - X86_64_IRQ_BASE, + vec![ioapic], ) .ok_or(Error::CreateSystemAllocator)?;