|
1 | 1 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2 | 2 | // SPDX-License-Identifier: Apache-2.0
|
3 | 3 | //! Manages system resources that can be allocated to VMs and their devices.
|
| 4 | +//! |
| 5 | +//! # Example |
| 6 | +//! |
| 7 | +//! Depending on the use case of the VMM, both the `IDAllocator` and the `AddressAllocator` |
| 8 | +//! can be used. In the example below we assume that the `IDAllocator` is used for allocating |
| 9 | +//! unique identifiers for VM devices. We use the address allocator for allocating MMIO ranges |
| 10 | +//! for virtio devices. |
| 11 | +//! |
| 12 | +//! In the example below we use constants that are typical for the x86 platform, but this has no |
| 13 | +//! impact on the code actually working on aarch64. |
| 14 | +//! |
| 15 | +//! ```rust |
| 16 | +//! use std::collections::HashMap; |
| 17 | +//! use std::process::id; |
| 18 | +//! use vm_allocator::{AddressAllocator, AllocPolicy, Error, IdAllocator, RangeInclusive, Result}; |
| 19 | +//! |
| 20 | +//! const FIRST_ADDR_PAST_32BITS: u64 = 1 << 32; |
| 21 | +//! const MEM_32BIT_GAP_SIZE: u64 = 768 << 20; |
| 22 | +//! const MMIO_MEM_START: u64 = FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE; |
| 23 | +//! const PAGE_SIZE: u64 = 0x1000; |
| 24 | +//! |
| 25 | +//! struct DeviceManager { |
| 26 | +//! id_allocator: IdAllocator, |
| 27 | +//! mmio_allocator: AddressAllocator, |
| 28 | +//! slots: HashMap<u32, RangeInclusive>, |
| 29 | +//! } |
| 30 | +//! |
| 31 | +//! #[derive(Clone, Copy)] |
| 32 | +//! struct DeviceSlot { |
| 33 | +//! id: u32, |
| 34 | +//! mmio_range: RangeInclusive, |
| 35 | +//! } |
| 36 | +//! |
| 37 | +//! impl DeviceManager { |
| 38 | +//! pub fn new() -> Result<Self> { |
| 39 | +//! Ok(DeviceManager { |
| 40 | +//! id_allocator: IdAllocator::new(0, 100)?, |
| 41 | +//! mmio_allocator: AddressAllocator::new(MMIO_MEM_START, MEM_32BIT_GAP_SIZE)?, |
| 42 | +//! slots: HashMap::new(), |
| 43 | +//! }) |
| 44 | +//! } |
| 45 | +//! |
| 46 | +//! pub fn reserve_device_slot(&mut self) -> Result<DeviceSlot> { |
| 47 | +//! // We're reserving the first available address that is aligned to the page size. |
| 48 | +//! // For each device we reserve one page of addresses. |
| 49 | +//! let mmio_range = |
| 50 | +//! self.mmio_allocator |
| 51 | +//! .allocate(PAGE_SIZE, PAGE_SIZE, AllocPolicy::FirstMatch)?; |
| 52 | +//! let slot = DeviceSlot { |
| 53 | +//! id: self.id_allocator.allocate_id()?, |
| 54 | +//! mmio_range, |
| 55 | +//! }; |
| 56 | +//! self.slots.insert(slot.id, slot.mmio_range); |
| 57 | +//! Ok(slot) |
| 58 | +//! } |
| 59 | +//! |
| 60 | +//! // Free the device slot corresponding to the passed device ID. |
| 61 | +//! pub fn free_device_slot(&mut self, id: u32) -> Result<()> { |
| 62 | +//! let mmio_range = self.slots.get(&id).ok_or(Error::NeverAllocated(id))?; |
| 63 | +//! let _ = self.id_allocator.free_id(id)?; |
| 64 | +//! self.mmio_allocator.free(mmio_range) |
| 65 | +//! } |
| 66 | +//! } |
| 67 | +//! |
| 68 | +//! # fn main() { |
| 69 | +//! # let mut dm = DeviceManager::new().unwrap(); |
| 70 | +//! # let slot = dm.reserve_device_slot().unwrap(); |
| 71 | +//! # dm.free_device_slot(slot.id).unwrap(); |
| 72 | +//! # } |
| 73 | +//! ``` |
4 | 74 |
|
5 | 75 | #![deny(missing_docs)]
|
6 | 76 |
|
|
0 commit comments