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 use crate::page_size::get_page_size; 17 18 /// Manages allocating system resources such as address space and interrupt numbers. 19 /// 20 /// # Example - Use the `SystemAddress` builder. 21 /// 22 /// ``` 23 /// # #[cfg(target_arch = "x86_64")] 24 /// # use vm_allocator::{GsiApic, SystemAllocator}; 25 /// # #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 26 /// # use vm_allocator::SystemAllocator; 27 /// # use vm_memory::{Address, GuestAddress, GuestUsize}; 28 /// let mut allocator = SystemAllocator::new( 29 /// #[cfg(target_arch = "x86_64")] GuestAddress(0x1000), 30 /// #[cfg(target_arch = "x86_64")] 0x10000, 31 /// GuestAddress(0x10000000), 0x10000000, 32 /// #[cfg(target_arch = "x86_64")] vec![GsiApic::new(5, 19)]).unwrap(); 33 /// #[cfg(target_arch = "x86_64")] 34 /// assert_eq!(allocator.allocate_irq(), Some(5)); 35 /// #[cfg(target_arch = "aarch64")] 36 /// assert_eq!(allocator.allocate_irq(), Some(32)); 37 /// #[cfg(target_arch = "riscv64")] 38 /// assert_eq!(allocator.allocate_irq(), Some(0)); 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 /// #[cfg(target_arch = "riscv64")] 44 /// assert_eq!(allocator.allocate_irq(), Some(1)); 45 /// assert_eq!(allocator.allocate_platform_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fff_f000))); 46 /// 47 /// ``` 48 pub struct SystemAllocator { 49 #[cfg(target_arch = "x86_64")] 50 io_address_space: AddressAllocator, 51 platform_mmio_address_space: AddressAllocator, 52 gsi_allocator: GsiAllocator, 53 } 54 55 impl SystemAllocator { 56 /// Creates a new `SystemAllocator` for managing addresses and irq numbers. 57 /// Can return `None` if `base` + `size` overflows a u64 58 /// 59 /// * `io_base` - (X86) The starting address of IO memory. 60 /// * `io_size` - (X86) The size of IO memory. 61 /// * `platform_mmio_base` - The starting address of platform MMIO memory. 62 /// * `platform_mmio_size` - The size of platform MMIO memory. 63 /// * `apics` - (X86) Vector of APIC's. 64 /// 65 pub fn new( 66 #[cfg(target_arch = "x86_64")] io_base: GuestAddress, 67 #[cfg(target_arch = "x86_64")] io_size: GuestUsize, 68 platform_mmio_base: GuestAddress, 69 platform_mmio_size: GuestUsize, 70 #[cfg(target_arch = "x86_64")] apics: Vec<GsiApic>, 71 ) -> Option<Self> { 72 Some(SystemAllocator { 73 #[cfg(target_arch = "x86_64")] 74 io_address_space: AddressAllocator::new(io_base, io_size)?, 75 platform_mmio_address_space: AddressAllocator::new( 76 platform_mmio_base, 77 platform_mmio_size, 78 )?, 79 #[cfg(target_arch = "x86_64")] 80 gsi_allocator: GsiAllocator::new(apics), 81 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 82 gsi_allocator: GsiAllocator::new(), 83 }) 84 } 85 86 /// Reserves the next available system irq number. 87 pub fn allocate_irq(&mut self) -> Option<u32> { 88 self.gsi_allocator.allocate_irq().ok() 89 } 90 91 /// Reserves the next available GSI. 92 pub fn allocate_gsi(&mut self) -> Option<u32> { 93 self.gsi_allocator.allocate_gsi().ok() 94 } 95 96 #[cfg(target_arch = "x86_64")] 97 /// Reserves a section of `size` bytes of IO address space. 98 pub fn allocate_io_addresses( 99 &mut self, 100 address: Option<GuestAddress>, 101 size: GuestUsize, 102 align_size: Option<GuestUsize>, 103 ) -> Option<GuestAddress> { 104 self.io_address_space 105 .allocate(address, size, Some(align_size.unwrap_or(0x1))) 106 } 107 108 /// Reserves a section of `size` bytes of platform MMIO address space. 109 pub fn allocate_platform_mmio_addresses( 110 &mut self, 111 address: Option<GuestAddress>, 112 size: GuestUsize, 113 align_size: Option<GuestUsize>, 114 ) -> Option<GuestAddress> { 115 self.platform_mmio_address_space.allocate( 116 address, 117 size, 118 Some(align_size.unwrap_or_else(get_page_size)), 119 ) 120 } 121 122 #[cfg(target_arch = "x86_64")] 123 /// Free an IO address range. 124 /// We can only free a range if it matches exactly an already allocated range. 125 pub fn free_io_addresses(&mut self, address: GuestAddress, size: GuestUsize) { 126 self.io_address_space.free(address, size) 127 } 128 129 /// Free a platform MMIO address range. 130 /// We can only free a range if it matches exactly an already allocated range. 131 pub fn free_platform_mmio_addresses(&mut self, address: GuestAddress, size: GuestUsize) { 132 self.platform_mmio_address_space.free(address, size) 133 } 134 } 135