1c5774685SRuoqing He // Copyright © 2024 Institute of Software, CAS. All rights reserved. 2c5774685SRuoqing He // 3c5774685SRuoqing He // SPDX-License-Identifier: Apache-2.0 4c5774685SRuoqing He 5c5774685SRuoqing He use std::any::Any; 6c5774685SRuoqing He 7c5774685SRuoqing He use kvm_ioctls::DeviceFd; 8c5774685SRuoqing He use serde::{Deserialize, Serialize}; 9c5774685SRuoqing He 10c5774685SRuoqing He use crate::arch::riscv64::aia::{Error, Result, Vaia, VaiaConfig}; 11c5774685SRuoqing He use crate::device::HypervisorDeviceError; 12c5774685SRuoqing He use crate::kvm::KvmVm; 13c5774685SRuoqing He use crate::Vm; 14c5774685SRuoqing He 15c5774685SRuoqing He pub struct KvmAiaImsics { 16c5774685SRuoqing He /// The KVM device for the Aia 17c5774685SRuoqing He device: DeviceFd, 18c5774685SRuoqing He 19c5774685SRuoqing He /// AIA APLIC address 20c5774685SRuoqing He aplic_addr: u64, 21c5774685SRuoqing He 22c5774685SRuoqing He /// AIA IMSIC address 23c5774685SRuoqing He imsic_addr: u64, 24c5774685SRuoqing He 25c5774685SRuoqing He /// Number of CPUs handled by the device 269006013cSRuoqing He vcpu_count: u32, 27c5774685SRuoqing He } 28c5774685SRuoqing He 29c5774685SRuoqing He #[derive(Clone, Default, Serialize, Deserialize)] 30c5774685SRuoqing He pub struct AiaImsicsState {} 31c5774685SRuoqing He 32c5774685SRuoqing He impl KvmAiaImsics { 33c5774685SRuoqing He /// Device trees specific constants version() -> u3234c5774685SRuoqing He fn version() -> u32 { 35c5774685SRuoqing He kvm_bindings::kvm_device_type_KVM_DEV_TYPE_RISCV_AIA 36c5774685SRuoqing He } 37c5774685SRuoqing He 38c5774685SRuoqing He /// Setup the device-specific attributes init_device_attributes(&mut self, nr_irqs: u32) -> Result<()>39c5774685SRuoqing He fn init_device_attributes(&mut self, nr_irqs: u32) -> Result<()> { 40c5774685SRuoqing He // AIA part attributes 41c5774685SRuoqing He // Getting the working mode of RISC-V AIA, defaults to EMUL, passible 42c5774685SRuoqing He // variants are EMUL, HW_ACCL, AUTO 43c5774685SRuoqing He let mut aia_mode = kvm_bindings::KVM_DEV_RISCV_AIA_MODE_EMUL; 44c5774685SRuoqing He Self::get_device_attribute( 45c5774685SRuoqing He &self.device, 46c5774685SRuoqing He kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG, 47c5774685SRuoqing He u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_MODE), 48c5774685SRuoqing He &mut aia_mode as *mut u32 as u64, 49c5774685SRuoqing He 0, 50c5774685SRuoqing He )?; 51c5774685SRuoqing He 52c5774685SRuoqing He // Report AIA MODE 53c5774685SRuoqing He 54c5774685SRuoqing He // Setting up the number of wired interrupt sources 55c5774685SRuoqing He Self::set_device_attribute( 56c5774685SRuoqing He &self.device, 57c5774685SRuoqing He kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG, 58c5774685SRuoqing He u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_SRCS), 59c5774685SRuoqing He &nr_irqs as *const u32 as u64, 60c5774685SRuoqing He 0, 61c5774685SRuoqing He )?; 62c5774685SRuoqing He 63c5774685SRuoqing He // Getting the number of ids 64c5774685SRuoqing He let mut aia_nr_ids: u32 = 0; 65c5774685SRuoqing He Self::get_device_attribute( 66c5774685SRuoqing He &self.device, 67c5774685SRuoqing He kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG, 68c5774685SRuoqing He u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_IDS), 69c5774685SRuoqing He &mut aia_nr_ids as *mut u32 as u64, 70c5774685SRuoqing He 0, 71c5774685SRuoqing He )?; 72c5774685SRuoqing He 73c5774685SRuoqing He // Report NR_IDS 74c5774685SRuoqing He 75c5774685SRuoqing He // Setting up hart_bits 769006013cSRuoqing He let max_hart_index = self.vcpu_count as u64 - 1; 77c5774685SRuoqing He let hart_bits = std::cmp::max(64 - max_hart_index.leading_zeros(), 1); 78c5774685SRuoqing He Self::set_device_attribute( 79c5774685SRuoqing He &self.device, 80c5774685SRuoqing He kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG, 81c5774685SRuoqing He u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_HART_BITS), 82c5774685SRuoqing He &hart_bits as *const u32 as u64, 83c5774685SRuoqing He 0, 84c5774685SRuoqing He )?; 85c5774685SRuoqing He 86c5774685SRuoqing He // Designate addresses of APLIC and IMSICS 87c5774685SRuoqing He 88c5774685SRuoqing He // Setting up RISC-V APLIC 89c5774685SRuoqing He Self::set_device_attribute( 90c5774685SRuoqing He &self.device, 91c5774685SRuoqing He kvm_bindings::KVM_DEV_RISCV_AIA_GRP_ADDR, 92c5774685SRuoqing He u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_ADDR_APLIC), 93c5774685SRuoqing He &self.aplic_addr as *const u64 as u64, 94c5774685SRuoqing He 0, 95c5774685SRuoqing He )?; 96c5774685SRuoqing He 97c5774685SRuoqing He // Helpers to calculate address and attribute of IMSIC of each vCPU 989006013cSRuoqing He let riscv_imsic_addr_of = |cpu_index: u32| -> u64 { 999006013cSRuoqing He self.imsic_addr + (cpu_index * kvm_bindings::KVM_DEV_RISCV_IMSIC_SIZE) as u64 1009006013cSRuoqing He }; 101cf463b88SRuoqing He let riscv_imsic_attr_of = |cpu_index: u32| -> u64 { cpu_index as u64 + 1 }; 102c5774685SRuoqing He 103c5774685SRuoqing He // Setting up RISC-V IMSICs 104c5774685SRuoqing He for cpu_index in 0..self.vcpu_count { 105c5774685SRuoqing He let cpu_imsic_addr = riscv_imsic_addr_of(cpu_index); 106c5774685SRuoqing He Self::set_device_attribute( 107c5774685SRuoqing He &self.device, 108c5774685SRuoqing He kvm_bindings::KVM_DEV_RISCV_AIA_GRP_ADDR, 109c5774685SRuoqing He riscv_imsic_attr_of(cpu_index), 110c5774685SRuoqing He &cpu_imsic_addr as *const u64 as u64, 111c5774685SRuoqing He 0, 112c5774685SRuoqing He )?; 113c5774685SRuoqing He } 114c5774685SRuoqing He 115c5774685SRuoqing He // Finalizing the AIA device 116c5774685SRuoqing He Self::set_device_attribute( 117c5774685SRuoqing He &self.device, 118c5774685SRuoqing He kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CTRL, 119c5774685SRuoqing He u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CTRL_INIT), 120c5774685SRuoqing He 0, 121c5774685SRuoqing He 0, 122c5774685SRuoqing He ) 123c5774685SRuoqing He } 124c5774685SRuoqing He 125c5774685SRuoqing He /// Create a KVM Vaia device create_device(vm: &KvmVm) -> Result<DeviceFd>126c5774685SRuoqing He fn create_device(vm: &KvmVm) -> Result<DeviceFd> { 127c5774685SRuoqing He let mut aia_device = kvm_bindings::kvm_create_device { 128c5774685SRuoqing He type_: Self::version(), 129c5774685SRuoqing He fd: 0, 130c5774685SRuoqing He flags: 0, 131c5774685SRuoqing He }; 132c5774685SRuoqing He 133c5774685SRuoqing He let device_fd = vm 134c5774685SRuoqing He .create_device(&mut aia_device) 135c5774685SRuoqing He .map_err(Error::CreateAia)?; 136c5774685SRuoqing He 137c5774685SRuoqing He // We know for sure this is a KVM fd 138c5774685SRuoqing He Ok(device_fd.to_kvm().unwrap()) 139c5774685SRuoqing He } 140c5774685SRuoqing He 141c5774685SRuoqing He /// Get an AIA device attribute get_device_attribute( device: &DeviceFd, group: u32, attr: u64, addr: u64, flags: u32, ) -> Result<()>142c5774685SRuoqing He fn get_device_attribute( 143c5774685SRuoqing He device: &DeviceFd, 144c5774685SRuoqing He group: u32, 145c5774685SRuoqing He attr: u64, 146c5774685SRuoqing He addr: u64, 147c5774685SRuoqing He flags: u32, 148c5774685SRuoqing He ) -> Result<()> { 149c5774685SRuoqing He let mut attr = kvm_bindings::kvm_device_attr { 150c5774685SRuoqing He flags, 151c5774685SRuoqing He group, 152c5774685SRuoqing He attr, 153c5774685SRuoqing He addr, 154c5774685SRuoqing He }; 155c5774685SRuoqing He // SAFETY: attr.addr is safe to write to. 156c5774685SRuoqing He unsafe { 157c5774685SRuoqing He device.get_device_attr(&mut attr).map_err(|e| { 158c5774685SRuoqing He Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into())) 159c5774685SRuoqing He }) 160c5774685SRuoqing He } 161c5774685SRuoqing He } 162c5774685SRuoqing He 163c5774685SRuoqing He /// Set an AIA device attribute set_device_attribute( device: &DeviceFd, group: u32, attr: u64, addr: u64, flags: u32, ) -> Result<()>164c5774685SRuoqing He fn set_device_attribute( 165c5774685SRuoqing He device: &DeviceFd, 166c5774685SRuoqing He group: u32, 167c5774685SRuoqing He attr: u64, 168c5774685SRuoqing He addr: u64, 169c5774685SRuoqing He flags: u32, 170c5774685SRuoqing He ) -> Result<()> { 171c5774685SRuoqing He let attr = kvm_bindings::kvm_device_attr { 172c5774685SRuoqing He flags, 173c5774685SRuoqing He group, 174c5774685SRuoqing He attr, 175c5774685SRuoqing He addr, 176c5774685SRuoqing He }; 177c5774685SRuoqing He device.set_device_attr(&attr).map_err(|e| { 178c5774685SRuoqing He Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())) 179c5774685SRuoqing He }) 180c5774685SRuoqing He } 181c5774685SRuoqing He 182c5774685SRuoqing He /// Method to initialize the AIA device new(vm: &dyn Vm, config: VaiaConfig) -> Result<KvmAiaImsics>183c5774685SRuoqing He pub fn new(vm: &dyn Vm, config: VaiaConfig) -> Result<KvmAiaImsics> { 184c5774685SRuoqing He // This is inside KVM module 185c5774685SRuoqing He let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?"); 186c5774685SRuoqing He 187c5774685SRuoqing He let vaia = Self::create_device(vm)?; 188c5774685SRuoqing He 189c5774685SRuoqing He let mut aia_device = KvmAiaImsics { 190c5774685SRuoqing He device: vaia, 191c5774685SRuoqing He vcpu_count: config.vcpu_count, 192c5774685SRuoqing He aplic_addr: config.aplic_addr, 193c5774685SRuoqing He imsic_addr: config.imsic_addr, 194c5774685SRuoqing He }; 195c5774685SRuoqing He 196c5774685SRuoqing He aia_device.init_device_attributes(config.nr_irqs)?; 197c5774685SRuoqing He 198c5774685SRuoqing He Ok(aia_device) 199c5774685SRuoqing He } 200c5774685SRuoqing He } 201c5774685SRuoqing He 202c5774685SRuoqing He impl Vaia for KvmAiaImsics { aplic_compatibility(&self) -> &str203c5774685SRuoqing He fn aplic_compatibility(&self) -> &str { 204c5774685SRuoqing He "riscv,aplic" 205c5774685SRuoqing He } 206c5774685SRuoqing He aplic_properties(&self) -> [u32; 4]2079006013cSRuoqing He fn aplic_properties(&self) -> [u32; 4] { 2089006013cSRuoqing He [ 2099006013cSRuoqing He 0, 2109006013cSRuoqing He self.aplic_addr as u32, 2119006013cSRuoqing He 0, 2129006013cSRuoqing He kvm_bindings::KVM_DEV_RISCV_APLIC_SIZE, 2139006013cSRuoqing He ] 214c5774685SRuoqing He } 215c5774685SRuoqing He imsic_compatibility(&self) -> &str216c5774685SRuoqing He fn imsic_compatibility(&self) -> &str { 217c5774685SRuoqing He "riscv,imsics" 218c5774685SRuoqing He } 219c5774685SRuoqing He imsic_properties(&self) -> [u32; 4]2209006013cSRuoqing He fn imsic_properties(&self) -> [u32; 4] { 2219006013cSRuoqing He [ 2229006013cSRuoqing He 0, 2239006013cSRuoqing He self.imsic_addr as u32, 2249006013cSRuoqing He 0, 2259006013cSRuoqing He kvm_bindings::KVM_DEV_RISCV_IMSIC_SIZE * self.vcpu_count, 2269006013cSRuoqing He ] 227c5774685SRuoqing He } 228c5774685SRuoqing He vcpu_count(&self) -> u322299006013cSRuoqing He fn vcpu_count(&self) -> u32 { 230c5774685SRuoqing He self.vcpu_count 231c5774685SRuoqing He } 232c5774685SRuoqing He msi_compatible(&self) -> bool233c5774685SRuoqing He fn msi_compatible(&self) -> bool { 234c5774685SRuoqing He true 235c5774685SRuoqing He } 236c5774685SRuoqing He as_any_concrete_mut(&mut self) -> &mut dyn Any237c5774685SRuoqing He fn as_any_concrete_mut(&mut self) -> &mut dyn Any { 238c5774685SRuoqing He self 239c5774685SRuoqing He } 240c5774685SRuoqing He 241c5774685SRuoqing He /// Save the state of AIA. state(&self) -> Result<AiaImsicsState>242c5774685SRuoqing He fn state(&self) -> Result<AiaImsicsState> { 243c5774685SRuoqing He unimplemented!() 244c5774685SRuoqing He } 245c5774685SRuoqing He 246c5774685SRuoqing He /// Restore the state of AIA_IMSICs. set_state(&mut self, _state: &AiaImsicsState) -> Result<()>247c5774685SRuoqing He fn set_state(&mut self, _state: &AiaImsicsState) -> Result<()> { 248c5774685SRuoqing He unimplemented!() 249c5774685SRuoqing He } 250c5774685SRuoqing He } 251c5774685SRuoqing He 252c5774685SRuoqing He #[cfg(test)] 253c5774685SRuoqing He mod tests { 254c5774685SRuoqing He use crate::arch::riscv64::aia::VaiaConfig; 255c5774685SRuoqing He use crate::kvm::KvmAiaImsics; 256c5774685SRuoqing He create_test_vaia_config() -> VaiaConfig257c5774685SRuoqing He fn create_test_vaia_config() -> VaiaConfig { 258c5774685SRuoqing He VaiaConfig { 259c5774685SRuoqing He vcpu_count: 1, 260c5774685SRuoqing He aplic_addr: 0xd000000, 261c5774685SRuoqing He imsic_addr: 0x2800000, 262c5774685SRuoqing He nr_irqs: 256, 263c5774685SRuoqing He } 264c5774685SRuoqing He } 265c5774685SRuoqing He 266c5774685SRuoqing He #[test] test_create_aia()267c5774685SRuoqing He fn test_create_aia() { 268c5774685SRuoqing He let hv = crate::new().unwrap(); 269c5774685SRuoqing He let vm = hv.create_vm().unwrap(); 270*3509b5bfSRuoqing He let _vcpu = vm.create_vcpu(0, None).unwrap(); 271c5774685SRuoqing He 272c5774685SRuoqing He assert!(KvmAiaImsics::new(&*vm, create_test_vaia_config()).is_ok()); 273c5774685SRuoqing He } 274c5774685SRuoqing He } 275