mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-12-25 04:14:06 +00:00
resources: Add address allocation helper
Add the AddressAllocator module that will be used by both architectures to manage distributing address ranges to devices. This will make the addition of PCI devices easier as now both MMIO and PCI will need to share address space. Add this to a new resources crate. Change-Id: I6a971dd795f2118bd6cfec7dc34a65b0d4a32f9b Signed-off-by: Dylan Reid <dgreid@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1072570 Reviewed-by: Sonny Rao <sonnyrao@chromium.org>
This commit is contained in:
parent
d678784ae1
commit
dea77cef92
5 changed files with 136 additions and 0 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -71,6 +71,7 @@ dependencies = [
|
|||
"qcow 0.1.0",
|
||||
"qcow_utils 0.1.0",
|
||||
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"resources 0.1.0",
|
||||
"sys_util 0.1.0",
|
||||
"vhost 0.1.0",
|
||||
"vm_control 0.1.0",
|
||||
|
@ -298,6 +299,13 @@ dependencies = [
|
|||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "resources"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"data_model 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.12.15"
|
||||
|
|
|
@ -36,6 +36,7 @@ plugin_proto = { path = "plugin_proto", optional = true }
|
|||
crosvm_plugin = { path = "crosvm_plugin", optional = true }
|
||||
protobuf = { version = "=1.4.3", optional = true }
|
||||
qcow_utils = { path = "qcow_utils" }
|
||||
resources = { path = "resources" }
|
||||
p9 = { path = "p9" }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
|
|
7
resources/Cargo.toml
Normal file
7
resources/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "resources"
|
||||
version = "0.1.0"
|
||||
authors = ["The Chromium OS Authors"]
|
||||
|
||||
[dependencies]
|
||||
data_model = { path = "../data_model" }
|
111
resources/src/address_allocator.rs
Normal file
111
resources/src/address_allocator.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/// Manages allocating address ranges.
|
||||
/// Use `AddressAllocator` whenever an address range needs to be allocated to different users.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use resources::AddressAllocator;
|
||||
/// AddressAllocator::new(0x1000, 0x10000, Some(0x100)).map(|mut pool| {
|
||||
/// assert_eq!(pool.allocate(0x110), Some(0x1000));
|
||||
/// assert_eq!(pool.allocate(0x100), Some(0x1200));
|
||||
/// });
|
||||
/// ```
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct AddressAllocator {
|
||||
pool_base: u64,
|
||||
pool_end: u64,
|
||||
alignment: u64,
|
||||
next_addr: u64,
|
||||
}
|
||||
|
||||
impl AddressAllocator {
|
||||
/// Creates a new `AddressAllocator` for managing a range of addresses.
|
||||
/// Can return `None` if `pool_base` + `pool_size` overflows a u64 or if alignment isn't a power
|
||||
/// of two.
|
||||
///
|
||||
/// * `pool_base` - The starting address of the range to manage.
|
||||
/// * `pool_size` - The size of the address range in bytes.
|
||||
/// * `align_size` - The minimum size of an address region to align to, defaults to four.
|
||||
pub fn new(pool_base: u64, pool_size: u64, align_size: Option<u64>) -> Option<Self> {
|
||||
if pool_size == 0 {
|
||||
return None;
|
||||
}
|
||||
let pool_end = pool_base.checked_add(pool_size - 1)?;
|
||||
let alignment = align_size.unwrap_or(4);
|
||||
if !alignment.is_power_of_two() || alignment == 0 {
|
||||
return None;
|
||||
}
|
||||
Some(AddressAllocator {
|
||||
pool_base,
|
||||
pool_end,
|
||||
alignment,
|
||||
next_addr: pool_base,
|
||||
})
|
||||
}
|
||||
|
||||
/// Allocates a range of addresses from the managed region. Returns `Some(allocated_address)`
|
||||
/// when successful, or `None` if an area of `size` can't be allocated.
|
||||
pub fn allocate(&mut self, size: u64) -> Option<u64> {
|
||||
if size == 0 {
|
||||
return None;
|
||||
}
|
||||
let align_adjust = if self.next_addr % self.alignment != 0 {
|
||||
self.alignment - (self.next_addr % self.alignment)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let addr = self.next_addr.checked_add(align_adjust)?;
|
||||
let end_addr = addr.checked_add(size - 1)?;
|
||||
if end_addr > self.pool_end {
|
||||
return None;
|
||||
}
|
||||
// TODO(dgreid): Use a smarter allocation strategy. The current strategy is just
|
||||
// bumping this pointer, meaning it will eventually exhaust available addresses.
|
||||
self.next_addr = end_addr.saturating_add(1);
|
||||
Some(addr)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn new_fails_overflow() {
|
||||
assert_eq!(AddressAllocator::new(u64::max_value(), 0x100, None), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_fails_size_zero() {
|
||||
assert_eq!(AddressAllocator::new(0x1000, 0, None), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_fails_alignment_zero() {
|
||||
assert_eq!(AddressAllocator::new(0x1000, 0x10000, Some(0)), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_fails_alignment_non_power_of_two() {
|
||||
assert_eq!(AddressAllocator::new(0x1000, 0x10000, Some(200)), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_fails_not_enough_space() {
|
||||
let mut pool = AddressAllocator::new(0x1000, 0x1000, Some(0x100)).unwrap();
|
||||
assert_eq!(pool.allocate(0x800), Some(0x1000));
|
||||
assert_eq!(pool.allocate(0x900), None);
|
||||
assert_eq!(pool.allocate(0x800), Some(0x1800));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_alignment() {
|
||||
let mut pool = AddressAllocator::new(0x1000, 0x10000, Some(0x100)).unwrap();
|
||||
assert_eq!(pool.allocate(0x110), Some(0x1000));
|
||||
assert_eq!(pool.allocate(0x100), Some(0x1200));
|
||||
}
|
||||
}
|
9
resources/src/lib.rs
Normal file
9
resources/src/lib.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! Manages system resources that can be allocated to VMs and their devices.
|
||||
|
||||
mod address_allocator;
|
||||
|
||||
pub use address_allocator::AddressAllocator;
|
Loading…
Reference in a new issue