xref: /cloud-hypervisor/hypervisor/src/kvm/riscv64/aia.rs (revision 6e4bf843837089b84662c83d2e6354655275f539)
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