• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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