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