xref: /cloud-hypervisor/vm-allocator/src/system.rs (revision 50bac1694f5bb305f00f02dc257896536eac5e0f)
1db7937d4SSamuel Ortiz // Copyright 2018 The Chromium OS Authors. All rights reserved.
2db7937d4SSamuel Ortiz // Copyright © 2019 Intel Corporation
3db7937d4SSamuel Ortiz //
4db7937d4SSamuel Ortiz // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5db7937d4SSamuel Ortiz // Use of this source code is governed by a BSD-style license that can be
6040ea543SSamuel Ortiz // found in the LICENSE-BSD-3-Clause file.
7040ea543SSamuel Ortiz //
8040ea543SSamuel Ortiz // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
9db7937d4SSamuel Ortiz 
10db7937d4SSamuel Ortiz use vm_memory::{GuestAddress, GuestUsize};
11db7937d4SSamuel Ortiz 
12db7937d4SSamuel Ortiz use crate::address::AddressAllocator;
13e9488846SMichael Zhao use crate::gsi::GsiAllocator;
14e9488846SMichael Zhao #[cfg(target_arch = "x86_64")]
15e9488846SMichael Zhao use crate::gsi::GsiApic;
165a9dd748SJianyong Wu use crate::page_size::get_page_size;
17db7937d4SSamuel Ortiz 
18db7937d4SSamuel Ortiz /// Manages allocating system resources such as address space and interrupt numbers.
19db7937d4SSamuel Ortiz ///
20db7937d4SSamuel Ortiz /// # Example - Use the `SystemAddress` builder.
21db7937d4SSamuel Ortiz ///
22db7937d4SSamuel Ortiz /// ```
2399e72be1SHenry Wang /// # #[cfg(target_arch = "x86_64")]
240a04a950SSamuel Ortiz /// # use vm_allocator::{GsiApic, SystemAllocator};
255b715f48SRuoqing He /// # #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
2699e72be1SHenry Wang /// # use vm_allocator::SystemAllocator;
27db7937d4SSamuel Ortiz /// # use vm_memory::{Address, GuestAddress, GuestUsize};
28db7937d4SSamuel Ortiz ///   let mut allocator = SystemAllocator::new(
29*50bac169SAlyssa Ross ///           GuestAddress(0x1000),
30*50bac169SAlyssa Ross ///           0x10000,
31db7937d4SSamuel Ortiz ///           GuestAddress(0x10000000), 0x10000000,
3299e72be1SHenry Wang ///           #[cfg(target_arch = "x86_64")] vec![GsiApic::new(5, 19)]).unwrap();
3399e72be1SHenry Wang ///   #[cfg(target_arch = "x86_64")]
34db7937d4SSamuel Ortiz ///   assert_eq!(allocator.allocate_irq(), Some(5));
3599e72be1SHenry Wang ///   #[cfg(target_arch = "aarch64")]
36ff46fb69SMichael Zhao ///   assert_eq!(allocator.allocate_irq(), Some(32));
375b715f48SRuoqing He ///   #[cfg(target_arch = "riscv64")]
385b715f48SRuoqing He ///   assert_eq!(allocator.allocate_irq(), Some(0));
3999e72be1SHenry Wang ///   #[cfg(target_arch = "x86_64")]
40db7937d4SSamuel Ortiz ///   assert_eq!(allocator.allocate_irq(), Some(6));
4199e72be1SHenry Wang ///   #[cfg(target_arch = "aarch64")]
42ff46fb69SMichael Zhao ///   assert_eq!(allocator.allocate_irq(), Some(33));
435b715f48SRuoqing He ///   #[cfg(target_arch = "riscv64")]
445b715f48SRuoqing He ///   assert_eq!(allocator.allocate_irq(), Some(1));
45def98fafSRob Bradford ///   assert_eq!(allocator.allocate_platform_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fff_f000)));
46db7937d4SSamuel Ortiz ///
47db7937d4SSamuel Ortiz /// ```
48db7937d4SSamuel Ortiz pub struct SystemAllocator {
49af7cd74eSChao Peng     io_address_space: AddressAllocator,
50def98fafSRob Bradford     platform_mmio_address_space: AddressAllocator,
510a04a950SSamuel Ortiz     gsi_allocator: GsiAllocator,
52db7937d4SSamuel Ortiz }
53db7937d4SSamuel Ortiz 
54db7937d4SSamuel Ortiz impl SystemAllocator {
557bf0cc1eSPhilipp Schuster     /// Creates a new `SystemAllocator` for managing addresses and irq numbers.
5696fb38a5SChao Peng     /// Can return `None` if `base` + `size` overflows a u64
57db7937d4SSamuel Ortiz     ///
58b5f1c912SMichael Zhao     /// * `io_base` - (X86) The starting address of IO memory.
59b5f1c912SMichael Zhao     /// * `io_size` - (X86) The size of IO memory.
60def98fafSRob Bradford     /// * `platform_mmio_base` - The starting address of platform MMIO memory.
61def98fafSRob Bradford     /// * `platform_mmio_size` - The size of platform MMIO memory.
62e9488846SMichael Zhao     /// * `apics` - (X86) Vector of APIC's.
63e9488846SMichael Zhao     ///
new( io_base: GuestAddress, io_size: GuestUsize, platform_mmio_base: GuestAddress, platform_mmio_size: GuestUsize, #[cfg(target_arch = "x86_64")] apics: Vec<GsiApic>, ) -> Option<Self>64db7937d4SSamuel Ortiz     pub fn new(
65*50bac169SAlyssa Ross         io_base: GuestAddress,
66*50bac169SAlyssa Ross         io_size: GuestUsize,
67def98fafSRob Bradford         platform_mmio_base: GuestAddress,
68def98fafSRob Bradford         platform_mmio_size: GuestUsize,
69e9488846SMichael Zhao         #[cfg(target_arch = "x86_64")] apics: Vec<GsiApic>,
70db7937d4SSamuel Ortiz     ) -> Option<Self> {
71db7937d4SSamuel Ortiz         Some(SystemAllocator {
7296fb38a5SChao Peng             io_address_space: AddressAllocator::new(io_base, io_size)?,
73def98fafSRob Bradford             platform_mmio_address_space: AddressAllocator::new(
74def98fafSRob Bradford                 platform_mmio_base,
75def98fafSRob Bradford                 platform_mmio_size,
76def98fafSRob Bradford             )?,
77e9488846SMichael Zhao             #[cfg(target_arch = "x86_64")]
780a04a950SSamuel Ortiz             gsi_allocator: GsiAllocator::new(apics),
795b715f48SRuoqing He             #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
80e9488846SMichael Zhao             gsi_allocator: GsiAllocator::new(),
81db7937d4SSamuel Ortiz         })
82db7937d4SSamuel Ortiz     }
83db7937d4SSamuel Ortiz 
84db7937d4SSamuel Ortiz     /// Reserves the next available system irq number.
allocate_irq(&mut self) -> Option<u32>85db7937d4SSamuel Ortiz     pub fn allocate_irq(&mut self) -> Option<u32> {
860a04a950SSamuel Ortiz         self.gsi_allocator.allocate_irq().ok()
87db7937d4SSamuel Ortiz     }
880a04a950SSamuel Ortiz 
890a04a950SSamuel Ortiz     /// Reserves the next available GSI.
allocate_gsi(&mut self) -> Option<u32>900a04a950SSamuel Ortiz     pub fn allocate_gsi(&mut self) -> Option<u32> {
910a04a950SSamuel Ortiz         self.gsi_allocator.allocate_gsi().ok()
92db7937d4SSamuel Ortiz     }
93db7937d4SSamuel Ortiz 
94db7937d4SSamuel Ortiz     /// Reserves a section of `size` bytes of IO address space.
allocate_io_addresses( &mut self, address: Option<GuestAddress>, size: GuestUsize, align_size: Option<GuestUsize>, ) -> Option<GuestAddress>95db7937d4SSamuel Ortiz     pub fn allocate_io_addresses(
96db7937d4SSamuel Ortiz         &mut self,
97af7cd74eSChao Peng         address: Option<GuestAddress>,
98db7937d4SSamuel Ortiz         size: GuestUsize,
9996fb38a5SChao Peng         align_size: Option<GuestUsize>,
100db7937d4SSamuel Ortiz     ) -> Option<GuestAddress> {
10196fb38a5SChao Peng         self.io_address_space
10296fb38a5SChao Peng             .allocate(address, size, Some(align_size.unwrap_or(0x1)))
103db7937d4SSamuel Ortiz     }
104db7937d4SSamuel Ortiz 
105def98fafSRob Bradford     /// Reserves a section of `size` bytes of platform MMIO address space.
allocate_platform_mmio_addresses( &mut self, address: Option<GuestAddress>, size: GuestUsize, align_size: Option<GuestUsize>, ) -> Option<GuestAddress>106def98fafSRob Bradford     pub fn allocate_platform_mmio_addresses(
107db7937d4SSamuel Ortiz         &mut self,
108db7937d4SSamuel Ortiz         address: Option<GuestAddress>,
109db7937d4SSamuel Ortiz         size: GuestUsize,
11096fb38a5SChao Peng         align_size: Option<GuestUsize>,
111db7937d4SSamuel Ortiz     ) -> Option<GuestAddress> {
112def98fafSRob Bradford         self.platform_mmio_address_space.allocate(
11396fb38a5SChao Peng             address,
11496fb38a5SChao Peng             size,
115274f1aa2SMuminul Islam             Some(align_size.unwrap_or_else(get_page_size)),
11696fb38a5SChao Peng         )
117db7937d4SSamuel Ortiz     }
1189f247751SSamuel Ortiz 
1199f247751SSamuel Ortiz     /// Free an IO address range.
1209f247751SSamuel Ortiz     /// We can only free a range if it matches exactly an already allocated range.
free_io_addresses(&mut self, address: GuestAddress, size: GuestUsize)1219f247751SSamuel Ortiz     pub fn free_io_addresses(&mut self, address: GuestAddress, size: GuestUsize) {
122af7cd74eSChao Peng         self.io_address_space.free(address, size)
1239f247751SSamuel Ortiz     }
1249f247751SSamuel Ortiz 
125def98fafSRob Bradford     /// Free a platform MMIO address range.
1269f247751SSamuel Ortiz     /// We can only free a range if it matches exactly an already allocated range.
free_platform_mmio_addresses(&mut self, address: GuestAddress, size: GuestUsize)127def98fafSRob Bradford     pub fn free_platform_mmio_addresses(&mut self, address: GuestAddress, size: GuestUsize) {
128def98fafSRob Bradford         self.platform_mmio_address_space.free(address, size)
1299f247751SSamuel Ortiz     }
130db7937d4SSamuel Ortiz }
131