1db7937d4SSamuel Ortiz // Copyright 2018 The Chromium OS Authors. All rights reserved. 2db7937d4SSamuel Ortiz // Copyright © 2019 Intel Corporation 3db7937d4SSamuel Ortiz // 4db7937d4SSamuel Ortiz // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 5db7937d4SSamuel Ortiz // Use of this source code is governed by a BSD-style license that can be 6040ea543SSamuel Ortiz // found in the LICENSE-BSD-3-Clause file. 7040ea543SSamuel Ortiz // 8040ea543SSamuel Ortiz // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 9db7937d4SSamuel Ortiz 10db7937d4SSamuel Ortiz use vm_memory::{GuestAddress, GuestUsize}; 11db7937d4SSamuel Ortiz 12db7937d4SSamuel Ortiz use crate::address::AddressAllocator; 13e9488846SMichael Zhao use crate::gsi::GsiAllocator; 14e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] 15e9488846SMichael Zhao use crate::gsi::GsiApic; 165a9dd748SJianyong Wu use crate::page_size::get_page_size; 17db7937d4SSamuel Ortiz 18db7937d4SSamuel Ortiz /// Manages allocating system resources such as address space and interrupt numbers. 19db7937d4SSamuel Ortiz /// 20db7937d4SSamuel Ortiz /// # Example - Use the `SystemAddress` builder. 21db7937d4SSamuel Ortiz /// 22db7937d4SSamuel Ortiz /// ``` 2399e72be1SHenry Wang /// # #[cfg(target_arch = "x86_64")] 240a04a950SSamuel Ortiz /// # use vm_allocator::{GsiApic, SystemAllocator}; 255b715f48SRuoqing He /// # #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 2699e72be1SHenry Wang /// # use vm_allocator::SystemAllocator; 27db7937d4SSamuel Ortiz /// # use vm_memory::{Address, GuestAddress, GuestUsize}; 28db7937d4SSamuel Ortiz /// let mut allocator = SystemAllocator::new( 29*50bac169SAlyssa Ross /// GuestAddress(0x1000), 30*50bac169SAlyssa Ross /// 0x10000, 31db7937d4SSamuel Ortiz /// GuestAddress(0x10000000), 0x10000000, 3299e72be1SHenry Wang /// #[cfg(target_arch = "x86_64")] vec![GsiApic::new(5, 19)]).unwrap(); 3399e72be1SHenry Wang /// #[cfg(target_arch = "x86_64")] 34db7937d4SSamuel Ortiz /// assert_eq!(allocator.allocate_irq(), Some(5)); 3599e72be1SHenry Wang /// #[cfg(target_arch = "aarch64")] 36ff46fb69SMichael Zhao /// assert_eq!(allocator.allocate_irq(), Some(32)); 375b715f48SRuoqing He /// #[cfg(target_arch = "riscv64")] 385b715f48SRuoqing He /// assert_eq!(allocator.allocate_irq(), Some(0)); 3999e72be1SHenry Wang /// #[cfg(target_arch = "x86_64")] 40db7937d4SSamuel Ortiz /// assert_eq!(allocator.allocate_irq(), Some(6)); 4199e72be1SHenry Wang /// #[cfg(target_arch = "aarch64")] 42ff46fb69SMichael Zhao /// assert_eq!(allocator.allocate_irq(), Some(33)); 435b715f48SRuoqing He /// #[cfg(target_arch = "riscv64")] 445b715f48SRuoqing He /// assert_eq!(allocator.allocate_irq(), Some(1)); 45def98fafSRob Bradford /// assert_eq!(allocator.allocate_platform_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fff_f000))); 46db7937d4SSamuel Ortiz /// 47db7937d4SSamuel Ortiz /// ``` 48db7937d4SSamuel Ortiz pub struct SystemAllocator { 49af7cd74eSChao Peng io_address_space: AddressAllocator, 50def98fafSRob Bradford platform_mmio_address_space: AddressAllocator, 510a04a950SSamuel Ortiz gsi_allocator: GsiAllocator, 52db7937d4SSamuel Ortiz } 53db7937d4SSamuel Ortiz 54db7937d4SSamuel Ortiz impl SystemAllocator { 557bf0cc1eSPhilipp Schuster /// Creates a new `SystemAllocator` for managing addresses and irq numbers. 5696fb38a5SChao Peng /// Can return `None` if `base` + `size` overflows a u64 57db7937d4SSamuel Ortiz /// 58b5f1c912SMichael Zhao /// * `io_base` - (X86) The starting address of IO memory. 59b5f1c912SMichael Zhao /// * `io_size` - (X86) The size of IO memory. 60def98fafSRob Bradford /// * `platform_mmio_base` - The starting address of platform MMIO memory. 61def98fafSRob Bradford /// * `platform_mmio_size` - The size of platform MMIO memory. 62e9488846SMichael Zhao /// * `apics` - (X86) Vector of APIC's. 63e9488846SMichael Zhao /// new( io_base: GuestAddress, io_size: GuestUsize, platform_mmio_base: GuestAddress, platform_mmio_size: GuestUsize, #[cfg(target_arch = "x86_64")] apics: Vec<GsiApic>, ) -> Option<Self>64db7937d4SSamuel Ortiz pub fn new( 65*50bac169SAlyssa Ross io_base: GuestAddress, 66*50bac169SAlyssa Ross io_size: GuestUsize, 67def98fafSRob Bradford platform_mmio_base: GuestAddress, 68def98fafSRob Bradford platform_mmio_size: GuestUsize, 69e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] apics: Vec<GsiApic>, 70db7937d4SSamuel Ortiz ) -> Option<Self> { 71db7937d4SSamuel Ortiz Some(SystemAllocator { 7296fb38a5SChao Peng io_address_space: AddressAllocator::new(io_base, io_size)?, 73def98fafSRob Bradford platform_mmio_address_space: AddressAllocator::new( 74def98fafSRob Bradford platform_mmio_base, 75def98fafSRob Bradford platform_mmio_size, 76def98fafSRob Bradford )?, 77e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] 780a04a950SSamuel Ortiz gsi_allocator: GsiAllocator::new(apics), 795b715f48SRuoqing He #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 80e9488846SMichael Zhao gsi_allocator: GsiAllocator::new(), 81db7937d4SSamuel Ortiz }) 82db7937d4SSamuel Ortiz } 83db7937d4SSamuel Ortiz 84db7937d4SSamuel Ortiz /// Reserves the next available system irq number. allocate_irq(&mut self) -> Option<u32>85db7937d4SSamuel Ortiz pub fn allocate_irq(&mut self) -> Option<u32> { 860a04a950SSamuel Ortiz self.gsi_allocator.allocate_irq().ok() 87db7937d4SSamuel Ortiz } 880a04a950SSamuel Ortiz 890a04a950SSamuel Ortiz /// Reserves the next available GSI. allocate_gsi(&mut self) -> Option<u32>900a04a950SSamuel Ortiz pub fn allocate_gsi(&mut self) -> Option<u32> { 910a04a950SSamuel Ortiz self.gsi_allocator.allocate_gsi().ok() 92db7937d4SSamuel Ortiz } 93db7937d4SSamuel Ortiz 94db7937d4SSamuel Ortiz /// Reserves a section of `size` bytes of IO address space. allocate_io_addresses( &mut self, address: Option<GuestAddress>, size: GuestUsize, align_size: Option<GuestUsize>, ) -> Option<GuestAddress>95db7937d4SSamuel Ortiz pub fn allocate_io_addresses( 96db7937d4SSamuel Ortiz &mut self, 97af7cd74eSChao Peng address: Option<GuestAddress>, 98db7937d4SSamuel Ortiz size: GuestUsize, 9996fb38a5SChao Peng align_size: Option<GuestUsize>, 100db7937d4SSamuel Ortiz ) -> Option<GuestAddress> { 10196fb38a5SChao Peng self.io_address_space 10296fb38a5SChao Peng .allocate(address, size, Some(align_size.unwrap_or(0x1))) 103db7937d4SSamuel Ortiz } 104db7937d4SSamuel Ortiz 105def98fafSRob Bradford /// Reserves a section of `size` bytes of platform MMIO address space. allocate_platform_mmio_addresses( &mut self, address: Option<GuestAddress>, size: GuestUsize, align_size: Option<GuestUsize>, ) -> Option<GuestAddress>106def98fafSRob Bradford pub fn allocate_platform_mmio_addresses( 107db7937d4SSamuel Ortiz &mut self, 108db7937d4SSamuel Ortiz address: Option<GuestAddress>, 109db7937d4SSamuel Ortiz size: GuestUsize, 11096fb38a5SChao Peng align_size: Option<GuestUsize>, 111db7937d4SSamuel Ortiz ) -> Option<GuestAddress> { 112def98fafSRob Bradford self.platform_mmio_address_space.allocate( 11396fb38a5SChao Peng address, 11496fb38a5SChao Peng size, 115274f1aa2SMuminul Islam Some(align_size.unwrap_or_else(get_page_size)), 11696fb38a5SChao Peng ) 117db7937d4SSamuel Ortiz } 1189f247751SSamuel Ortiz 1199f247751SSamuel Ortiz /// Free an IO address range. 1209f247751SSamuel Ortiz /// We can only free a range if it matches exactly an already allocated range. free_io_addresses(&mut self, address: GuestAddress, size: GuestUsize)1219f247751SSamuel Ortiz pub fn free_io_addresses(&mut self, address: GuestAddress, size: GuestUsize) { 122af7cd74eSChao Peng self.io_address_space.free(address, size) 1239f247751SSamuel Ortiz } 1249f247751SSamuel Ortiz 125def98fafSRob Bradford /// Free a platform MMIO address range. 1269f247751SSamuel Ortiz /// We can only free a range if it matches exactly an already allocated range. free_platform_mmio_addresses(&mut self, address: GuestAddress, size: GuestUsize)127def98fafSRob Bradford pub fn free_platform_mmio_addresses(&mut self, address: GuestAddress, size: GuestUsize) { 128def98fafSRob Bradford self.platform_mmio_address_space.free(address, size) 1299f247751SSamuel Ortiz } 130db7937d4SSamuel Ortiz } 131