xref: /cloud-hypervisor/vm-allocator/src/system.rs (revision 5b715f483d8912e2c4c3ae20492798220cef9773)
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Copyright © 2019 Intel Corporation
3 //
4 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style license that can be
6 // found in the LICENSE-BSD-3-Clause file.
7 //
8 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
9 
10 use vm_memory::{GuestAddress, GuestUsize};
11 
12 use crate::address::AddressAllocator;
13 use crate::gsi::GsiAllocator;
14 #[cfg(target_arch = "x86_64")]
15 use crate::gsi::GsiApic;
16 use crate::page_size::get_page_size;
17 
18 /// Manages allocating system resources such as address space and interrupt numbers.
19 ///
20 /// # Example - Use the `SystemAddress` builder.
21 ///
22 /// ```
23 /// # #[cfg(target_arch = "x86_64")]
24 /// # use vm_allocator::{GsiApic, SystemAllocator};
25 /// # #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
26 /// # use vm_allocator::SystemAllocator;
27 /// # use vm_memory::{Address, GuestAddress, GuestUsize};
28 ///   let mut allocator = SystemAllocator::new(
29 ///           #[cfg(target_arch = "x86_64")] GuestAddress(0x1000),
30 ///           #[cfg(target_arch = "x86_64")] 0x10000,
31 ///           GuestAddress(0x10000000), 0x10000000,
32 ///           #[cfg(target_arch = "x86_64")] vec![GsiApic::new(5, 19)]).unwrap();
33 ///   #[cfg(target_arch = "x86_64")]
34 ///   assert_eq!(allocator.allocate_irq(), Some(5));
35 ///   #[cfg(target_arch = "aarch64")]
36 ///   assert_eq!(allocator.allocate_irq(), Some(32));
37 ///   #[cfg(target_arch = "riscv64")]
38 ///   assert_eq!(allocator.allocate_irq(), Some(0));
39 ///   #[cfg(target_arch = "x86_64")]
40 ///   assert_eq!(allocator.allocate_irq(), Some(6));
41 ///   #[cfg(target_arch = "aarch64")]
42 ///   assert_eq!(allocator.allocate_irq(), Some(33));
43 ///   #[cfg(target_arch = "riscv64")]
44 ///   assert_eq!(allocator.allocate_irq(), Some(1));
45 ///   assert_eq!(allocator.allocate_platform_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fff_f000)));
46 ///
47 /// ```
48 pub struct SystemAllocator {
49     #[cfg(target_arch = "x86_64")]
50     io_address_space: AddressAllocator,
51     platform_mmio_address_space: AddressAllocator,
52     gsi_allocator: GsiAllocator,
53 }
54 
55 impl SystemAllocator {
56     /// Creates a new `SystemAllocator` for managing addresses and irq numbers.
57     /// Can return `None` if `base` + `size` overflows a u64
58     ///
59     /// * `io_base` - (X86) The starting address of IO memory.
60     /// * `io_size` - (X86) The size of IO memory.
61     /// * `platform_mmio_base` - The starting address of platform MMIO memory.
62     /// * `platform_mmio_size` - The size of platform MMIO memory.
63     /// * `apics` - (X86) Vector of APIC's.
64     ///
65     pub fn new(
66         #[cfg(target_arch = "x86_64")] io_base: GuestAddress,
67         #[cfg(target_arch = "x86_64")] io_size: GuestUsize,
68         platform_mmio_base: GuestAddress,
69         platform_mmio_size: GuestUsize,
70         #[cfg(target_arch = "x86_64")] apics: Vec<GsiApic>,
71     ) -> Option<Self> {
72         Some(SystemAllocator {
73             #[cfg(target_arch = "x86_64")]
74             io_address_space: AddressAllocator::new(io_base, io_size)?,
75             platform_mmio_address_space: AddressAllocator::new(
76                 platform_mmio_base,
77                 platform_mmio_size,
78             )?,
79             #[cfg(target_arch = "x86_64")]
80             gsi_allocator: GsiAllocator::new(apics),
81             #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
82             gsi_allocator: GsiAllocator::new(),
83         })
84     }
85 
86     /// Reserves the next available system irq number.
87     pub fn allocate_irq(&mut self) -> Option<u32> {
88         self.gsi_allocator.allocate_irq().ok()
89     }
90 
91     /// Reserves the next available GSI.
92     pub fn allocate_gsi(&mut self) -> Option<u32> {
93         self.gsi_allocator.allocate_gsi().ok()
94     }
95 
96     #[cfg(target_arch = "x86_64")]
97     /// Reserves a section of `size` bytes of IO address space.
98     pub fn allocate_io_addresses(
99         &mut self,
100         address: Option<GuestAddress>,
101         size: GuestUsize,
102         align_size: Option<GuestUsize>,
103     ) -> Option<GuestAddress> {
104         self.io_address_space
105             .allocate(address, size, Some(align_size.unwrap_or(0x1)))
106     }
107 
108     /// Reserves a section of `size` bytes of platform MMIO address space.
109     pub fn allocate_platform_mmio_addresses(
110         &mut self,
111         address: Option<GuestAddress>,
112         size: GuestUsize,
113         align_size: Option<GuestUsize>,
114     ) -> Option<GuestAddress> {
115         self.platform_mmio_address_space.allocate(
116             address,
117             size,
118             Some(align_size.unwrap_or_else(get_page_size)),
119         )
120     }
121 
122     #[cfg(target_arch = "x86_64")]
123     /// Free an IO address range.
124     /// We can only free a range if it matches exactly an already allocated range.
125     pub fn free_io_addresses(&mut self, address: GuestAddress, size: GuestUsize) {
126         self.io_address_space.free(address, size)
127     }
128 
129     /// Free a platform MMIO address range.
130     /// We can only free a range if it matches exactly an already allocated range.
131     pub fn free_platform_mmio_addresses(&mut self, address: GuestAddress, size: GuestUsize) {
132         self.platform_mmio_address_space.free(address, size)
133     }
134 }
135