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 numbers. 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