xref: /cloud-hypervisor/vm-allocator/src/system.rs (revision 5a9dd7489cdd27ad83b278ae94609214350b07b1)
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 
17 use crate::page_size::get_page_size;
18 
19 /// Manages allocating system resources such as address space and interrupt numbers.
20 ///
21 /// # Example - Use the `SystemAddress` builder.
22 ///
23 /// ```
24 /// # #[cfg(target_arch = "x86_64")]
25 /// # use vm_allocator::{GsiApic, SystemAllocator};
26 /// # #[cfg(target_arch = "aarch64")]
27 /// # use vm_allocator::SystemAllocator;
28 /// # use vm_memory::{Address, GuestAddress, GuestUsize};
29 ///   let mut allocator = SystemAllocator::new(
30 ///           #[cfg(target_arch = "x86_64")] GuestAddress(0x1000),
31 ///           #[cfg(target_arch = "x86_64")] 0x10000,
32 ///           GuestAddress(0x10000000), 0x10000000,
33 ///           GuestAddress(0x20000000), 0x100000,
34 ///           #[cfg(target_arch = "x86_64")] vec![GsiApic::new(5, 19)]).unwrap();
35 ///   #[cfg(target_arch = "x86_64")]
36 ///   assert_eq!(allocator.allocate_irq(), Some(5));
37 ///   #[cfg(target_arch = "aarch64")]
38 ///   assert_eq!(allocator.allocate_irq(), Some(32));
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 ///   assert_eq!(allocator.allocate_platform_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fff_f000)));
44 ///
45 /// ```
46 pub struct SystemAllocator {
47     #[cfg(target_arch = "x86_64")]
48     io_address_space: AddressAllocator,
49     platform_mmio_address_space: AddressAllocator,
50     mmio_hole_address_space: AddressAllocator,
51     gsi_allocator: GsiAllocator,
52 }
53 
54 impl SystemAllocator {
55     /// Creates a new `SystemAllocator` for managing addresses and irq numvers.
56     /// Can return `None` if `base` + `size` overflows a u64
57     ///
58     /// * `io_base` - (X86) The starting address of IO memory.
59     /// * `io_size` - (X86) The size of IO memory.
60     /// * `platform_mmio_base` - The starting address of platform MMIO memory.
61     /// * `platform_mmio_size` - The size of platform MMIO memory.
62     /// * `mmio_hole_base` - The starting address of MMIO memory in 32-bit address space.
63     /// * `mmio_hole_size` - The size of MMIO memory in 32-bit address space.
64     /// * `apics` - (X86) Vector of APIC's.
65     ///
66     pub fn new(
67         #[cfg(target_arch = "x86_64")] io_base: GuestAddress,
68         #[cfg(target_arch = "x86_64")] io_size: GuestUsize,
69         platform_mmio_base: GuestAddress,
70         platform_mmio_size: GuestUsize,
71         mmio_hole_base: GuestAddress,
72         mmio_hole_size: GuestUsize,
73         #[cfg(target_arch = "x86_64")] apics: Vec<GsiApic>,
74     ) -> Option<Self> {
75         Some(SystemAllocator {
76             #[cfg(target_arch = "x86_64")]
77             io_address_space: AddressAllocator::new(io_base, io_size)?,
78             platform_mmio_address_space: AddressAllocator::new(
79                 platform_mmio_base,
80                 platform_mmio_size,
81             )?,
82             mmio_hole_address_space: AddressAllocator::new(mmio_hole_base, mmio_hole_size)?,
83             #[cfg(target_arch = "x86_64")]
84             gsi_allocator: GsiAllocator::new(apics),
85             #[cfg(target_arch = "aarch64")]
86             gsi_allocator: GsiAllocator::new(),
87         })
88     }
89 
90     /// Reserves the next available system irq number.
91     pub fn allocate_irq(&mut self) -> Option<u32> {
92         self.gsi_allocator.allocate_irq().ok()
93     }
94 
95     /// Reserves the next available GSI.
96     pub fn allocate_gsi(&mut self) -> Option<u32> {
97         self.gsi_allocator.allocate_gsi().ok()
98     }
99 
100     #[cfg(target_arch = "x86_64")]
101     /// Reserves a section of `size` bytes of IO address space.
102     pub fn allocate_io_addresses(
103         &mut self,
104         address: Option<GuestAddress>,
105         size: GuestUsize,
106         align_size: Option<GuestUsize>,
107     ) -> Option<GuestAddress> {
108         self.io_address_space
109             .allocate(address, size, Some(align_size.unwrap_or(0x1)))
110     }
111 
112     /// Reserves a section of `size` bytes of platform MMIO address space.
113     pub fn allocate_platform_mmio_addresses(
114         &mut self,
115         address: Option<GuestAddress>,
116         size: GuestUsize,
117         align_size: Option<GuestUsize>,
118     ) -> Option<GuestAddress> {
119         self.platform_mmio_address_space.allocate(
120             address,
121             size,
122             Some(align_size.unwrap_or(get_page_size())),
123         )
124     }
125 
126     /// Reserves a section of `size` bytes of MMIO address space.
127     pub fn allocate_mmio_hole_addresses(
128         &mut self,
129         address: Option<GuestAddress>,
130         size: GuestUsize,
131         align_size: Option<GuestUsize>,
132     ) -> Option<GuestAddress> {
133         self.mmio_hole_address_space.allocate(
134             address,
135             size,
136             Some(align_size.unwrap_or(get_page_size())),
137         )
138     }
139 
140     #[cfg(target_arch = "x86_64")]
141     /// Free an IO address range.
142     /// We can only free a range if it matches exactly an already allocated range.
143     pub fn free_io_addresses(&mut self, address: GuestAddress, size: GuestUsize) {
144         self.io_address_space.free(address, size)
145     }
146 
147     /// Free a platform MMIO address range.
148     /// We can only free a range if it matches exactly an already allocated range.
149     pub fn free_platform_mmio_addresses(&mut self, address: GuestAddress, size: GuestUsize) {
150         self.platform_mmio_address_space.free(address, size)
151     }
152 
153     /// Free an MMIO address range from the 32 bits hole.
154     /// We can only free a range if it matches exactly an already allocated range.
155     pub fn free_mmio_hole_addresses(&mut self, address: GuestAddress, size: GuestUsize) {
156         self.mmio_hole_address_space.free(address, size)
157     }
158 }
159