system_allocator: use config object pattern for constructing

In preparation to allow multiple low memory regions to be passed on, I wanted to
make initialization simpler.

Introduce `MemRegion` struct instead of tuple to help me understand it is a base
and size.

BUG=b:188011323
TEST=build

Change-Id: Ie8b54354a25c478d5ad0a0185b7e07d28840dd87
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3439666
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Junichi Uekawa <uekawa@chromium.org>
This commit is contained in:
Junichi Uekawa 2022-02-04 15:50:06 +09:00 committed by Commit Bot
parent 52e0085daa
commit 67d4219489
7 changed files with 203 additions and 172 deletions

View file

@ -20,7 +20,7 @@ use hypervisor::{
};
use minijail::Minijail;
use remain::sorted;
use resources::{MmioType, SystemAllocator};
use resources::{MemRegion, MmioType, SystemAllocator, SystemAllocatorConfig};
use sync::Mutex;
use thiserror::Error;
use vm_control::BatteryType;
@ -561,12 +561,23 @@ impl AArch64 {
guest_phys_end, high_mmio_base,
);
});
SystemAllocator::builder()
.add_low_mmio_addresses(AARCH64_MMIO_BASE, AARCH64_MMIO_SIZE)
.add_platform_mmio_addresses(plat_mmio_base, plat_mmio_size)
.add_high_mmio_addresses(high_mmio_base, high_mmio_size)
.create_allocator(AARCH64_IRQ_BASE)
.unwrap()
SystemAllocator::new(SystemAllocatorConfig {
io: None,
low_mmio: MemRegion {
base: AARCH64_MMIO_BASE,
size: AARCH64_MMIO_SIZE,
},
high_mmio: MemRegion {
base: high_mmio_base,
size: high_mmio_size,
},
platform_mmio: Some(MemRegion {
base: plat_mmio_base,
size: plat_mmio_size,
}),
first_irq: AARCH64_IRQ_BASE,
})
.unwrap()
}
/// This adds any early platform devices for this architecture.

View file

@ -720,14 +720,13 @@ mod tests {
use super::*;
use base::EventReadResult;
use hypervisor::kvm::Kvm;
use hypervisor::{
kvm::Kvm, IoapicRedirectionTableEntry, PitRWMode, ProtectionType, TriggerMode, Vm, VmX86_64,
};
use resources::{MemRegion, SystemAllocator, SystemAllocatorConfig};
use vm_memory::GuestMemory;
use hypervisor::{
IoapicRedirectionTableEntry, PitRWMode, ProtectionType, TriggerMode, Vm, VmX86_64,
};
use super::super::super::tests::*;
use crate::irqchip::tests::*;
use crate::IrqChip;
/// Helper function for setting up a KvmKernelIrqChip
@ -905,12 +904,23 @@ mod tests {
let mmio_bus = Bus::new();
let io_bus = Bus::new();
let mut resources = SystemAllocator::builder()
.add_io_addresses(0xc000, 0x10000)
.add_low_mmio_addresses(0, 2048)
.add_high_mmio_addresses(2048, 4096)
.create_allocator(5)
.expect("failed to create SystemAllocator");
let mut resources = SystemAllocator::new(SystemAllocatorConfig {
io: Some(MemRegion {
base: 0xc000,
size: 0x1_0000,
}),
low_mmio: MemRegion {
base: 0,
size: 2048,
},
high_mmio: MemRegion {
base: 2048,
size: 4096,
},
platform_mmio: None,
first_irq: 5,
})
.expect("failed to create SystemAllocator");
// setup an event and a resample event for irq line 1
let evt = Event::new().expect("failed to create event");
@ -1023,12 +1033,23 @@ mod tests {
let mmio_bus = Bus::new();
let io_bus = Bus::new();
let mut resources = SystemAllocator::builder()
.add_io_addresses(0xc000, 0x10000)
.add_low_mmio_addresses(0, 2048)
.add_high_mmio_addresses(2048, 4096)
.create_allocator(5)
.expect("failed to create SystemAllocator");
let mut resources = SystemAllocator::new(SystemAllocatorConfig {
io: Some(MemRegion {
base: 0xc000,
size: 0x1_0000,
}),
low_mmio: MemRegion {
base: 0,
size: 2048,
},
high_mmio: MemRegion {
base: 2048,
size: 4096,
},
platform_mmio: None,
first_irq: 5,
})
.expect("failed to create SystemAllocator");
// setup an event and a resample event for irq line 1
let evt = Event::new().expect("failed to create event");

View file

@ -439,6 +439,7 @@ impl PciDevice for Ac97Dev {
mod tests {
use super::*;
use audio_streams::shm_streams::MockShmStreamSource;
use resources::{MemRegion, SystemAllocatorConfig};
use vm_memory::GuestAddress;
#[test]
@ -446,12 +447,23 @@ mod tests {
let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)]).unwrap();
let mut ac97_dev =
Ac97Dev::new(mem, Ac97Backend::NULL, Box::new(MockShmStreamSource::new()));
let mut allocator = SystemAllocator::builder()
.add_io_addresses(0x1000_0000, 0x1000_0000)
.add_low_mmio_addresses(0x2000_0000, 0x1000_0000)
.add_high_mmio_addresses(0x3000_0000, 0x1000_0000)
.create_allocator(5)
.unwrap();
let mut allocator = SystemAllocator::new(SystemAllocatorConfig {
io: Some(MemRegion {
base: 0x1000_0000,
size: 0x1000_0000,
}),
low_mmio: MemRegion {
base: 0x2000_0000,
size: 0x1000_0000,
},
high_mmio: MemRegion {
base: 0x3000_0000,
size: 0x1000_0000,
},
platform_mmio: None,
first_irq: 5,
})
.unwrap();
assert!(ac97_dev.allocate_address(&mut allocator).is_ok());
assert!(ac97_dev.allocate_io_bars(&mut allocator).is_ok());
}

View file

@ -127,6 +127,7 @@ impl PciDevice for StubPciDevice {
#[cfg(test)]
mod test {
use super::*;
use resources::{MemRegion, SystemAllocator, SystemAllocatorConfig};
const CONFIG: StubPciParameters = StubPciParameters {
address: PciAddress {
@ -155,12 +156,23 @@ mod test {
#[test]
fn address_allocation() {
let mut allocator = SystemAllocator::builder()
.add_io_addresses(0x1000_0000, 0x1000_0000)
.add_low_mmio_addresses(0x2000_0000, 0x1000_0000)
.add_high_mmio_addresses(0x3000_0000, 0x1000_0000)
.create_allocator(5)
.unwrap();
let mut allocator = SystemAllocator::new(SystemAllocatorConfig {
io: Some(MemRegion {
base: 0x1000_0000,
size: 0x1000_0000,
}),
low_mmio: MemRegion {
base: 0x2000_0000,
size: 0x1000_0000,
},
high_mmio: MemRegion {
base: 0x3000_0000,
size: 0x1000_0000,
},
platform_mmio: None,
first_irq: 5,
})
.unwrap();
let mut device = StubPciDevice::new(&CONFIG);
assert!(device.allocate_address(&mut allocator).is_ok());

View file

@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
pub use crate::address_allocator::AddressAllocator;
pub use crate::system_allocator::{MmioType, SystemAllocator};
pub use crate::system_allocator::{MemRegion, MmioType, SystemAllocator, SystemAllocatorConfig};
mod address_allocator;
mod system_allocator;
@ -50,10 +50,6 @@ pub enum Error {
ExistingAlloc(Alloc),
#[error("Invalid Alloc: {0:?}")]
InvalidAlloc(Alloc),
#[error("High MMIO address range not specified")]
MissingHighMMIOAddresses,
#[error("Low MMIO address range not specified")]
MissingLowMMIOAddresses,
#[error("Platform MMIO address range not specified")]
MissingPlatformMMIOAddresses,
#[error("No IO address range specified")]

View file

@ -6,37 +6,9 @@ use std::collections::BTreeMap;
use base::pagesize;
use crate::address_allocator::{AddressAllocator, AddressAllocatorSet};
use crate::{Alloc, Error, Result};
use crate::{Alloc, Result};
/// Manages allocating system resources such as address space and interrupt numbers.
///
/// # Example - Use the `SystemAllocator` builder.
///
/// ```
/// # use resources::{Alloc, MmioType, SystemAllocator};
/// if let Ok(mut a) = SystemAllocator::builder()
/// .add_io_addresses(0x1000, 0x10000)
/// .add_high_mmio_addresses(0x10000000, 0x10000000)
/// .add_low_mmio_addresses(0x30000000, 0x10000)
/// .create_allocator(5) {
/// assert_eq!(a.allocate_irq(), Some(5));
/// assert_eq!(a.allocate_irq(), Some(6));
/// assert_eq!(
/// a.mmio_allocator(MmioType::High)
/// .allocate(
/// 0x100,
/// Alloc::PciBar { bus: 0, dev: 0, func: 0, bar: 0 },
/// "bar0".to_string()
/// ),
/// Ok(0x10000000)
/// );
/// assert_eq!(
/// a.mmio_allocator(MmioType::High)
/// .get(&Alloc::PciBar { bus: 0, dev: 0, func: 0, bar: 0 }),
/// Some(&(0x10000000, 0x100, "bar0".to_string()))
/// );
/// }
/// ```
/// MMIO address Type
/// Low: address allocated from low_address_space
@ -46,6 +18,25 @@ pub enum MmioType {
High,
}
/// Region of memory.
pub struct MemRegion {
pub base: u64,
pub size: u64,
}
pub struct SystemAllocatorConfig {
/// IO memory. Only for x86_64.
pub io: Option<MemRegion>,
/// Low (<=4GB) MMIO region.
pub low_mmio: MemRegion,
/// High (>4GB) MMIO region.
pub high_mmio: MemRegion,
/// Platform MMIO space. Only for ARM.
pub platform_mmio: Option<MemRegion>,
/// The first IRQ number to give out.
pub first_irq: u32,
}
#[derive(Debug)]
pub struct SystemAllocator {
io_address_space: Option<AddressAllocator>,
@ -65,52 +56,48 @@ impl SystemAllocator {
/// Can return `None` if `base` + `size` overflows a u64 or if alignment isn't a power
/// of two.
///
/// * `io_base` - The starting address of IO memory.
/// * `io_size` - The size of IO memory.
/// * `high_base` - The starting address of high MMIO space.
/// * `high_size` - The size of high MMIO space.
/// * `low_base` - The starting address of low MMIO space.
/// * `low_size` - The size of low MMIO space.
/// * `platform_base` - The starting address of platform MMIO space.
/// * `platform_size` - The size of platform MMIO space.
/// * `first_irq` - The first irq number to give out.
fn new(
io_base: Option<u64>,
io_size: Option<u64>,
high_base: u64,
high_size: u64,
low_base: u64,
low_size: u64,
platform_base: Option<u64>,
platform_size: Option<u64>,
first_irq: u32,
) -> Result<Self> {
pub fn new(config: SystemAllocatorConfig) -> Result<Self> {
let page_size = pagesize() as u64;
Ok(SystemAllocator {
io_address_space: if let (Some(b), Some(s)) = (io_base, io_size) {
Some(AddressAllocator::new(b, s, Some(0x400), None)?)
io_address_space: if let Some(io) = config.io {
Some(AddressAllocator::new(io.base, io.size, Some(0x400), None)?)
} else {
None
},
mmio_address_spaces: [
// MmioType::Low
AddressAllocator::new(low_base, low_size, Some(page_size), None)?,
AddressAllocator::new(
config.low_mmio.base,
config.low_mmio.size,
Some(page_size),
None,
)?,
// MmioType::High
AddressAllocator::new(high_base, high_size, Some(page_size), None)?,
AddressAllocator::new(
config.high_mmio.base,
config.high_mmio.size,
Some(page_size),
None,
)?,
],
pci_allocator: BTreeMap::new(),
mmio_platform_address_spaces: if let (Some(b), Some(s)) = (platform_base, platform_size)
{
Some(AddressAllocator::new(b, s, Some(page_size), None)?)
mmio_platform_address_spaces: if let Some(platform) = config.platform_mmio {
Some(AddressAllocator::new(
platform.base,
platform.size,
Some(page_size),
None,
)?)
} else {
None
},
irq_allocator: AddressAllocator::new(
first_irq as u64,
1024 - first_irq as u64,
config.first_irq as u64,
1024 - config.first_irq as u64,
Some(1),
None,
)?,
@ -118,11 +105,6 @@ impl SystemAllocator {
})
}
/// Returns a `SystemAllocatorBuilder` that can create a new `SystemAllocator`.
pub fn builder() -> SystemAllocatorBuilder {
SystemAllocatorBuilder::new()
}
/// Reserves the next available system irq number.
pub fn allocate_irq(&mut self) -> Option<u32> {
let id = self.get_anon_alloc();
@ -250,67 +232,53 @@ impl SystemAllocator {
}
}
/// Used to build a system address map for use in creating a `SystemAllocator`.
pub struct SystemAllocatorBuilder {
io_base: Option<u64>,
io_size: Option<u64>,
low_mmio_base: Option<u64>,
low_mmio_size: Option<u64>,
high_mmio_base: Option<u64>,
high_mmio_size: Option<u64>,
platform_mmio_base: Option<u64>,
platform_mmio_size: Option<u64>,
}
#[cfg(test)]
mod tests {
use super::*;
impl SystemAllocatorBuilder {
pub fn new() -> Self {
SystemAllocatorBuilder {
io_base: None,
io_size: None,
low_mmio_base: None,
low_mmio_size: None,
high_mmio_base: None,
high_mmio_size: None,
platform_mmio_base: None,
platform_mmio_size: None,
}
}
#[test]
fn example() {
let mut a = SystemAllocator::new(SystemAllocatorConfig {
io: Some(MemRegion {
base: 0x1000,
size: 0x1_0000,
}),
low_mmio: MemRegion {
base: 0x3000_0000,
size: 0x1_0000,
},
high_mmio: MemRegion {
base: 0x1000_0000,
size: 0x1000_0000,
},
platform_mmio: None,
first_irq: 5,
})
.unwrap();
pub fn add_io_addresses(mut self, base: u64, size: u64) -> Self {
self.io_base = Some(base);
self.io_size = Some(size);
self
}
pub fn add_low_mmio_addresses(mut self, base: u64, size: u64) -> Self {
self.low_mmio_base = Some(base);
self.low_mmio_size = Some(size);
self
}
pub fn add_high_mmio_addresses(mut self, base: u64, size: u64) -> Self {
self.high_mmio_base = Some(base);
self.high_mmio_size = Some(size);
self
}
pub fn add_platform_mmio_addresses(mut self, base: u64, size: u64) -> Self {
self.platform_mmio_base = Some(base);
self.platform_mmio_size = Some(size);
self
}
pub fn create_allocator(&self, first_irq: u32) -> Result<SystemAllocator> {
SystemAllocator::new(
self.io_base,
self.io_size,
self.high_mmio_base.ok_or(Error::MissingHighMMIOAddresses)?,
self.high_mmio_size.ok_or(Error::MissingHighMMIOAddresses)?,
self.low_mmio_base.ok_or(Error::MissingLowMMIOAddresses)?,
self.low_mmio_size.ok_or(Error::MissingLowMMIOAddresses)?,
self.platform_mmio_base,
self.platform_mmio_size,
first_irq,
)
assert_eq!(a.allocate_irq(), Some(5));
assert_eq!(a.allocate_irq(), Some(6));
assert_eq!(
a.mmio_allocator(MmioType::High).allocate(
0x100,
Alloc::PciBar {
bus: 0,
dev: 0,
func: 0,
bar: 0
},
"bar0".to_string()
),
Ok(0x10000000)
);
assert_eq!(
a.mmio_allocator(MmioType::High).get(&Alloc::PciBar {
bus: 0,
dev: 0,
func: 0,
bar: 0
}),
Some(&(0x10000000, 0x100, "bar0".to_string()))
);
}
}

View file

@ -63,7 +63,7 @@ use devices::{
use hypervisor::{HypervisorX86_64, ProtectionType, VcpuX86_64, Vm, VmX86_64};
use minijail::Minijail;
use remain::sorted;
use resources::SystemAllocator;
use resources::{MemRegion, SystemAllocator, SystemAllocatorConfig};
use sync::Mutex;
use thiserror::Error;
use vm_control::{BatControl, BatteryType};
@ -394,12 +394,23 @@ impl arch::LinuxArch for X8664arch {
let guest_mem = vm.get_memory();
let high_mmio_start = Self::get_high_mmio_base(guest_mem);
let high_mmio_size = Self::get_high_mmio_size(vm);
SystemAllocator::builder()
.add_io_addresses(0xc000, 0x1_0000)
.add_low_mmio_addresses(END_ADDR_BEFORE_32BITS, PCI_MMIO_SIZE)
.add_high_mmio_addresses(high_mmio_start, high_mmio_size)
.create_allocator(X86_64_IRQ_BASE)
.unwrap()
SystemAllocator::new(SystemAllocatorConfig {
io: Some(MemRegion {
base: 0xc000,
size: 0x1_0000,
}),
low_mmio: MemRegion {
base: END_ADDR_BEFORE_32BITS,
size: PCI_MMIO_SIZE,
},
high_mmio: MemRegion {
base: high_mmio_start,
size: high_mmio_size,
},
platform_mmio: None,
first_irq: X86_64_IRQ_BASE,
})
.unwrap()
}
fn build_vm<V, Vcpu>(