1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use sys_util::pagesize; 6 7 use crate::address_allocator::AddressAllocator; 8 use crate::gpu_allocator::{self, GpuMemoryAllocator}; 9 use crate::{Alloc, Error, Result}; 10 11 /// Manages allocating system resources such as address space and interrupt numbers. 12 /// 13 /// # Example - Use the `SystemAddress` builder. 14 /// 15 /// ``` 16 /// # use resources::{Alloc, SystemAllocator}; 17 /// if let Ok(mut a) = SystemAllocator::builder() 18 /// .add_io_addresses(0x1000, 0x10000) 19 /// .add_device_addresses(0x10000000, 0x10000000) 20 /// .add_mmio_addresses(0x30000000, 0x10000) 21 /// .create_allocator(5, false) { 22 /// assert_eq!(a.allocate_irq(), Some(5)); 23 /// assert_eq!(a.allocate_irq(), Some(6)); 24 /// assert_eq!( 25 /// a.device_allocator() 26 /// .allocate( 27 /// 0x100, 28 /// Alloc::PciBar { bus: 0, dev: 0, bar: 0 }, 29 /// "bar0".to_string() 30 /// ), 31 /// Ok(0x10000000) 32 /// ); 33 /// assert_eq!( 34 /// a.device_allocator().get(&Alloc::PciBar { bus: 0, dev: 0, bar: 0 }), 35 /// Some(&(0x10000000, 0x100, "bar0".to_string())) 36 /// ); 37 /// } 38 /// ``` 39 #[derive(Debug)] 40 pub struct SystemAllocator { 41 io_address_space: Option<AddressAllocator>, 42 device_address_space: AddressAllocator, 43 mmio_address_space: AddressAllocator, 44 gpu_allocator: Option<Box<dyn GpuMemoryAllocator>>, 45 next_irq: u32, 46 next_anon_id: usize, 47 } 48 49 impl SystemAllocator { 50 /// Creates a new `SystemAllocator` for managing addresses and irq numvers. 51 /// Can return `None` if `base` + `size` overflows a u64 or if alignment isn't a power 52 /// of two. 53 /// 54 /// * `io_base` - The starting address of IO memory. 55 /// * `io_size` - The size of IO memory. 56 /// * `dev_base` - The starting address of device memory. 57 /// * `dev_size` - The size of device memory. 58 /// * `mmio_base` - The starting address of MMIO space. 59 /// * `mmio_size` - The size of MMIO space. 60 /// * `create_gpu_allocator` - If true, enable gpu memory allocation. 61 /// * `first_irq` - The first irq number to give out. new( io_base: Option<u64>, io_size: Option<u64>, dev_base: u64, dev_size: u64, mmio_base: u64, mmio_size: u64, create_gpu_allocator: bool, first_irq: u32, ) -> Result<Self>62 fn new( 63 io_base: Option<u64>, 64 io_size: Option<u64>, 65 dev_base: u64, 66 dev_size: u64, 67 mmio_base: u64, 68 mmio_size: u64, 69 create_gpu_allocator: bool, 70 first_irq: u32, 71 ) -> Result<Self> { 72 let page_size = pagesize() as u64; 73 Ok(SystemAllocator { 74 io_address_space: if let (Some(b), Some(s)) = (io_base, io_size) { 75 Some(AddressAllocator::new(b, s, Some(0x400))?) 76 } else { 77 None 78 }, 79 device_address_space: AddressAllocator::new(dev_base, dev_size, Some(page_size))?, 80 mmio_address_space: AddressAllocator::new(mmio_base, mmio_size, Some(page_size))?, 81 gpu_allocator: if create_gpu_allocator { 82 gpu_allocator::create_gpu_memory_allocator().map_err(Error::CreateGpuAllocator)? 83 } else { 84 None 85 }, 86 next_irq: first_irq, 87 next_anon_id: 0, 88 }) 89 } 90 91 /// Returns a `SystemAllocatorBuilder` that can create a new `SystemAllocator`. builder() -> SystemAllocatorBuilder92 pub fn builder() -> SystemAllocatorBuilder { 93 SystemAllocatorBuilder::new() 94 } 95 96 /// Reserves the next available system irq number. allocate_irq(&mut self) -> Option<u32>97 pub fn allocate_irq(&mut self) -> Option<u32> { 98 if let Some(irq_num) = self.next_irq.checked_add(1) { 99 self.next_irq = irq_num; 100 Some(irq_num - 1) 101 } else { 102 None 103 } 104 } 105 106 /// Gets an allocator to be used for IO memory. io_allocator(&mut self) -> Option<&mut AddressAllocator>107 pub fn io_allocator(&mut self) -> Option<&mut AddressAllocator> { 108 self.io_address_space.as_mut() 109 } 110 111 /// Gets an allocator to be used for device memory. device_allocator(&mut self) -> &mut AddressAllocator112 pub fn device_allocator(&mut self) -> &mut AddressAllocator { 113 &mut self.device_address_space 114 } 115 116 /// Gets an allocator to be used for MMIO memory. mmio_allocator(&mut self) -> &mut AddressAllocator117 pub fn mmio_allocator(&mut self) -> &mut AddressAllocator { 118 &mut self.mmio_address_space 119 } 120 121 /// Gets an allocator to be used for GPU memory. gpu_memory_allocator(&self) -> Option<&dyn GpuMemoryAllocator>122 pub fn gpu_memory_allocator(&self) -> Option<&dyn GpuMemoryAllocator> { 123 self.gpu_allocator.as_ref().map(|v| v.as_ref()) 124 } 125 126 /// Gets a unique anonymous allocation get_anon_alloc(&mut self) -> Alloc127 pub fn get_anon_alloc(&mut self) -> Alloc { 128 self.next_anon_id += 1; 129 Alloc::Anon(self.next_anon_id) 130 } 131 } 132 133 /// Used to build a system address map for use in creating a `SystemAllocator`. 134 pub struct SystemAllocatorBuilder { 135 io_base: Option<u64>, 136 io_size: Option<u64>, 137 mmio_base: Option<u64>, 138 mmio_size: Option<u64>, 139 device_base: Option<u64>, 140 device_size: Option<u64>, 141 } 142 143 impl SystemAllocatorBuilder { new() -> Self144 pub fn new() -> Self { 145 SystemAllocatorBuilder { 146 io_base: None, 147 io_size: None, 148 mmio_base: None, 149 mmio_size: None, 150 device_base: None, 151 device_size: None, 152 } 153 } 154 add_io_addresses(mut self, base: u64, size: u64) -> Self155 pub fn add_io_addresses(mut self, base: u64, size: u64) -> Self { 156 self.io_base = Some(base); 157 self.io_size = Some(size); 158 self 159 } 160 add_mmio_addresses(mut self, base: u64, size: u64) -> Self161 pub fn add_mmio_addresses(mut self, base: u64, size: u64) -> Self { 162 self.mmio_base = Some(base); 163 self.mmio_size = Some(size); 164 self 165 } 166 add_device_addresses(mut self, base: u64, size: u64) -> Self167 pub fn add_device_addresses(mut self, base: u64, size: u64) -> Self { 168 self.device_base = Some(base); 169 self.device_size = Some(size); 170 self 171 } 172 create_allocator( &self, first_irq: u32, gpu_allocation: bool, ) -> Result<SystemAllocator>173 pub fn create_allocator( 174 &self, 175 first_irq: u32, 176 gpu_allocation: bool, 177 ) -> Result<SystemAllocator> { 178 SystemAllocator::new( 179 self.io_base, 180 self.io_size, 181 self.device_base.ok_or(Error::MissingDeviceAddresses)?, 182 self.device_size.ok_or(Error::MissingDeviceAddresses)?, 183 self.mmio_base.ok_or(Error::MissingMMIOAddresses)?, 184 self.mmio_size.ok_or(Error::MissingMMIOAddresses)?, 185 gpu_allocation, 186 first_irq, 187 ) 188 } 189 } 190