xref: /aosp_15_r20/external/crosvm/devices/src/irqchip/kvm/aarch64.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
8*bb4ee6a4SAndroid Build Coastguard Worker use base::errno_result;
9*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_ref;
10*bb4ee6a4SAndroid Build Coastguard Worker use base::Result;
11*bb4ee6a4SAndroid Build Coastguard Worker use base::SafeDescriptor;
12*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::kvm::KvmVcpu;
13*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::kvm::KvmVm;
14*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::DeviceKind;
15*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::IrqRoute;
16*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Vm;
17*bb4ee6a4SAndroid Build Coastguard Worker use kvm_sys::*;
18*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqChip;
21*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqChipAArch64;
22*bb4ee6a4SAndroid Build Coastguard Worker 
23*bb4ee6a4SAndroid Build Coastguard Worker /// Default ARM routing table.  AARCH64_GIC_NR_SPIS pins go to VGIC.
kvm_default_irq_routing_table() -> Vec<IrqRoute>24*bb4ee6a4SAndroid Build Coastguard Worker fn kvm_default_irq_routing_table() -> Vec<IrqRoute> {
25*bb4ee6a4SAndroid Build Coastguard Worker     let mut routes: Vec<IrqRoute> = Vec::new();
26*bb4ee6a4SAndroid Build Coastguard Worker 
27*bb4ee6a4SAndroid Build Coastguard Worker     for i in 0..AARCH64_GIC_NR_SPIS {
28*bb4ee6a4SAndroid Build Coastguard Worker         routes.push(IrqRoute::gic_irq_route(i));
29*bb4ee6a4SAndroid Build Coastguard Worker     }
30*bb4ee6a4SAndroid Build Coastguard Worker 
31*bb4ee6a4SAndroid Build Coastguard Worker     routes
32*bb4ee6a4SAndroid Build Coastguard Worker }
33*bb4ee6a4SAndroid Build Coastguard Worker 
34*bb4ee6a4SAndroid Build Coastguard Worker /// IrqChip implementation where the entire IrqChip is emulated by KVM.
35*bb4ee6a4SAndroid Build Coastguard Worker ///
36*bb4ee6a4SAndroid Build Coastguard Worker /// This implementation will use the KVM API to create and configure the in-kernel irqchip.
37*bb4ee6a4SAndroid Build Coastguard Worker pub struct KvmKernelIrqChip {
38*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) vm: KvmVm,
39*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) vcpus: Arc<Mutex<Vec<Option<KvmVcpu>>>>,
40*bb4ee6a4SAndroid Build Coastguard Worker     vgic: SafeDescriptor,
41*bb4ee6a4SAndroid Build Coastguard Worker     device_kind: DeviceKind,
42*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) routes: Arc<Mutex<Vec<IrqRoute>>>,
43*bb4ee6a4SAndroid Build Coastguard Worker }
44*bb4ee6a4SAndroid Build Coastguard Worker 
45*bb4ee6a4SAndroid Build Coastguard Worker // These constants indicate the address space used by the ARM vGIC.
46*bb4ee6a4SAndroid Build Coastguard Worker const AARCH64_GIC_DIST_SIZE: u64 = 0x10000;
47*bb4ee6a4SAndroid Build Coastguard Worker const AARCH64_GIC_CPUI_SIZE: u64 = 0x20000;
48*bb4ee6a4SAndroid Build Coastguard Worker 
49*bb4ee6a4SAndroid Build Coastguard Worker // These constants indicate the placement of the GIC registers in the physical
50*bb4ee6a4SAndroid Build Coastguard Worker // address space.
51*bb4ee6a4SAndroid Build Coastguard Worker const AARCH64_GIC_DIST_BASE: u64 = 0x40000000 - AARCH64_GIC_DIST_SIZE;
52*bb4ee6a4SAndroid Build Coastguard Worker const AARCH64_GIC_CPUI_BASE: u64 = AARCH64_GIC_DIST_BASE - AARCH64_GIC_CPUI_SIZE;
53*bb4ee6a4SAndroid Build Coastguard Worker const AARCH64_GIC_REDIST_SIZE: u64 = 0x20000;
54*bb4ee6a4SAndroid Build Coastguard Worker 
55*bb4ee6a4SAndroid Build Coastguard Worker // This is the minimum number of SPI interrupts aligned to 32 + 32 for the
56*bb4ee6a4SAndroid Build Coastguard Worker // PPI (16) and GSI (16).
57*bb4ee6a4SAndroid Build Coastguard Worker pub const AARCH64_GIC_NR_IRQS: u32 = 64;
58*bb4ee6a4SAndroid Build Coastguard Worker // Number of SPIs (32), which is the NR_IRQS (64) minus the number of PPIs (16) and GSIs (16)
59*bb4ee6a4SAndroid Build Coastguard Worker pub const AARCH64_GIC_NR_SPIS: u32 = 32;
60*bb4ee6a4SAndroid Build Coastguard Worker 
61*bb4ee6a4SAndroid Build Coastguard Worker impl KvmKernelIrqChip {
62*bb4ee6a4SAndroid Build Coastguard Worker     /// Construct a new KvmKernelIrqchip.
new(vm: KvmVm, num_vcpus: usize) -> Result<KvmKernelIrqChip>63*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(vm: KvmVm, num_vcpus: usize) -> Result<KvmKernelIrqChip> {
64*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_if_addr: u64 = AARCH64_GIC_CPUI_BASE;
65*bb4ee6a4SAndroid Build Coastguard Worker         let dist_if_addr: u64 = AARCH64_GIC_DIST_BASE;
66*bb4ee6a4SAndroid Build Coastguard Worker         let redist_addr: u64 = dist_if_addr - (AARCH64_GIC_REDIST_SIZE * num_vcpus as u64);
67*bb4ee6a4SAndroid Build Coastguard Worker         let raw_cpu_if_addr = &cpu_if_addr as *const u64;
68*bb4ee6a4SAndroid Build Coastguard Worker         let raw_dist_if_addr = &dist_if_addr as *const u64;
69*bb4ee6a4SAndroid Build Coastguard Worker         let raw_redist_addr = &redist_addr as *const u64;
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker         let cpu_if_attr = kvm_device_attr {
72*bb4ee6a4SAndroid Build Coastguard Worker             group: KVM_DEV_ARM_VGIC_GRP_ADDR,
73*bb4ee6a4SAndroid Build Coastguard Worker             attr: KVM_VGIC_V2_ADDR_TYPE_CPU as u64,
74*bb4ee6a4SAndroid Build Coastguard Worker             addr: raw_cpu_if_addr as u64,
75*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
76*bb4ee6a4SAndroid Build Coastguard Worker         };
77*bb4ee6a4SAndroid Build Coastguard Worker         let redist_attr = kvm_device_attr {
78*bb4ee6a4SAndroid Build Coastguard Worker             group: KVM_DEV_ARM_VGIC_GRP_ADDR,
79*bb4ee6a4SAndroid Build Coastguard Worker             attr: KVM_VGIC_V3_ADDR_TYPE_REDIST as u64,
80*bb4ee6a4SAndroid Build Coastguard Worker             addr: raw_redist_addr as u64,
81*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
82*bb4ee6a4SAndroid Build Coastguard Worker         };
83*bb4ee6a4SAndroid Build Coastguard Worker         let mut dist_attr = kvm_device_attr {
84*bb4ee6a4SAndroid Build Coastguard Worker             group: KVM_DEV_ARM_VGIC_GRP_ADDR,
85*bb4ee6a4SAndroid Build Coastguard Worker             addr: raw_dist_if_addr as u64,
86*bb4ee6a4SAndroid Build Coastguard Worker             attr: 0,
87*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
88*bb4ee6a4SAndroid Build Coastguard Worker         };
89*bb4ee6a4SAndroid Build Coastguard Worker 
90*bb4ee6a4SAndroid Build Coastguard Worker         let (vgic, device_kind, cpu_redist_attr, dist_attr_attr) =
91*bb4ee6a4SAndroid Build Coastguard Worker             match vm.create_device(DeviceKind::ArmVgicV3) {
92*bb4ee6a4SAndroid Build Coastguard Worker                 Err(_) => (
93*bb4ee6a4SAndroid Build Coastguard Worker                     vm.create_device(DeviceKind::ArmVgicV2)?,
94*bb4ee6a4SAndroid Build Coastguard Worker                     DeviceKind::ArmVgicV2,
95*bb4ee6a4SAndroid Build Coastguard Worker                     cpu_if_attr,
96*bb4ee6a4SAndroid Build Coastguard Worker                     KVM_VGIC_V2_ADDR_TYPE_DIST as u64,
97*bb4ee6a4SAndroid Build Coastguard Worker                 ),
98*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(vgic) => (
99*bb4ee6a4SAndroid Build Coastguard Worker                     vgic,
100*bb4ee6a4SAndroid Build Coastguard Worker                     DeviceKind::ArmVgicV3,
101*bb4ee6a4SAndroid Build Coastguard Worker                     redist_attr,
102*bb4ee6a4SAndroid Build Coastguard Worker                     KVM_VGIC_V3_ADDR_TYPE_DIST as u64,
103*bb4ee6a4SAndroid Build Coastguard Worker                 ),
104*bb4ee6a4SAndroid Build Coastguard Worker             };
105*bb4ee6a4SAndroid Build Coastguard Worker         dist_attr.attr = dist_attr_attr;
106*bb4ee6a4SAndroid Build Coastguard Worker 
107*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
108*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we allocated the struct that's being passed in
109*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&vgic, KVM_SET_DEVICE_ATTR, &cpu_redist_attr) };
110*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 {
111*bb4ee6a4SAndroid Build Coastguard Worker             return errno_result();
112*bb4ee6a4SAndroid Build Coastguard Worker         }
113*bb4ee6a4SAndroid Build Coastguard Worker 
114*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
115*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we allocated the struct that's being passed in
116*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&vgic, KVM_SET_DEVICE_ATTR, &dist_attr) };
117*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 {
118*bb4ee6a4SAndroid Build Coastguard Worker             return errno_result();
119*bb4ee6a4SAndroid Build Coastguard Worker         }
120*bb4ee6a4SAndroid Build Coastguard Worker 
121*bb4ee6a4SAndroid Build Coastguard Worker         // We need to tell the kernel how many irqs to support with this vgic
122*bb4ee6a4SAndroid Build Coastguard Worker         let nr_irqs: u32 = AARCH64_GIC_NR_IRQS;
123*bb4ee6a4SAndroid Build Coastguard Worker         let nr_irqs_ptr = &nr_irqs as *const u32;
124*bb4ee6a4SAndroid Build Coastguard Worker         let nr_irqs_attr = kvm_device_attr {
125*bb4ee6a4SAndroid Build Coastguard Worker             group: KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
126*bb4ee6a4SAndroid Build Coastguard Worker             attr: 0,
127*bb4ee6a4SAndroid Build Coastguard Worker             addr: nr_irqs_ptr as u64,
128*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
129*bb4ee6a4SAndroid Build Coastguard Worker         };
130*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
131*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we allocated the struct that's being passed in
132*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&vgic, KVM_SET_DEVICE_ATTR, &nr_irqs_attr) };
133*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 {
134*bb4ee6a4SAndroid Build Coastguard Worker             return errno_result();
135*bb4ee6a4SAndroid Build Coastguard Worker         }
136*bb4ee6a4SAndroid Build Coastguard Worker 
137*bb4ee6a4SAndroid Build Coastguard Worker         Ok(KvmKernelIrqChip {
138*bb4ee6a4SAndroid Build Coastguard Worker             vm,
139*bb4ee6a4SAndroid Build Coastguard Worker             vcpus: Arc::new(Mutex::new((0..num_vcpus).map(|_| None).collect())),
140*bb4ee6a4SAndroid Build Coastguard Worker             vgic,
141*bb4ee6a4SAndroid Build Coastguard Worker             device_kind,
142*bb4ee6a4SAndroid Build Coastguard Worker             routes: Arc::new(Mutex::new(kvm_default_irq_routing_table())),
143*bb4ee6a4SAndroid Build Coastguard Worker         })
144*bb4ee6a4SAndroid Build Coastguard Worker     }
145*bb4ee6a4SAndroid Build Coastguard Worker 
146*bb4ee6a4SAndroid Build Coastguard Worker     /// Attempt to create a shallow clone of this aarch64 KvmKernelIrqChip instance.
arch_try_clone(&self) -> Result<Self>147*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) fn arch_try_clone(&self) -> Result<Self> {
148*bb4ee6a4SAndroid Build Coastguard Worker         Ok(KvmKernelIrqChip {
149*bb4ee6a4SAndroid Build Coastguard Worker             vm: self.vm.try_clone()?,
150*bb4ee6a4SAndroid Build Coastguard Worker             vcpus: self.vcpus.clone(),
151*bb4ee6a4SAndroid Build Coastguard Worker             vgic: self.vgic.try_clone()?,
152*bb4ee6a4SAndroid Build Coastguard Worker             device_kind: self.device_kind,
153*bb4ee6a4SAndroid Build Coastguard Worker             routes: self.routes.clone(),
154*bb4ee6a4SAndroid Build Coastguard Worker         })
155*bb4ee6a4SAndroid Build Coastguard Worker     }
156*bb4ee6a4SAndroid Build Coastguard Worker }
157*bb4ee6a4SAndroid Build Coastguard Worker 
158*bb4ee6a4SAndroid Build Coastguard Worker impl IrqChipAArch64 for KvmKernelIrqChip {
try_box_clone(&self) -> Result<Box<dyn IrqChipAArch64>>159*bb4ee6a4SAndroid Build Coastguard Worker     fn try_box_clone(&self) -> Result<Box<dyn IrqChipAArch64>> {
160*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Box::new(self.try_clone()?))
161*bb4ee6a4SAndroid Build Coastguard Worker     }
162*bb4ee6a4SAndroid Build Coastguard Worker 
as_irq_chip(&self) -> &dyn IrqChip163*bb4ee6a4SAndroid Build Coastguard Worker     fn as_irq_chip(&self) -> &dyn IrqChip {
164*bb4ee6a4SAndroid Build Coastguard Worker         self
165*bb4ee6a4SAndroid Build Coastguard Worker     }
166*bb4ee6a4SAndroid Build Coastguard Worker 
as_irq_chip_mut(&mut self) -> &mut dyn IrqChip167*bb4ee6a4SAndroid Build Coastguard Worker     fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip {
168*bb4ee6a4SAndroid Build Coastguard Worker         self
169*bb4ee6a4SAndroid Build Coastguard Worker     }
170*bb4ee6a4SAndroid Build Coastguard Worker 
get_vgic_version(&self) -> DeviceKind171*bb4ee6a4SAndroid Build Coastguard Worker     fn get_vgic_version(&self) -> DeviceKind {
172*bb4ee6a4SAndroid Build Coastguard Worker         self.device_kind
173*bb4ee6a4SAndroid Build Coastguard Worker     }
174*bb4ee6a4SAndroid Build Coastguard Worker 
snapshot(&self, _cpus_num: usize) -> anyhow::Result<serde_json::Value>175*bb4ee6a4SAndroid Build Coastguard Worker     fn snapshot(&self, _cpus_num: usize) -> anyhow::Result<serde_json::Value> {
176*bb4ee6a4SAndroid Build Coastguard Worker         if self.device_kind == DeviceKind::ArmVgicV3 {
177*bb4ee6a4SAndroid Build Coastguard Worker             let save_gic_attr = kvm_device_attr {
178*bb4ee6a4SAndroid Build Coastguard Worker                 group: KVM_DEV_ARM_VGIC_GRP_CTRL,
179*bb4ee6a4SAndroid Build Coastguard Worker                 attr: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES as u64,
180*bb4ee6a4SAndroid Build Coastguard Worker                 addr: 0,
181*bb4ee6a4SAndroid Build Coastguard Worker                 flags: 0,
182*bb4ee6a4SAndroid Build Coastguard Worker             };
183*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
184*bb4ee6a4SAndroid Build Coastguard Worker             // Safe because we allocated the struct that's being passed in
185*bb4ee6a4SAndroid Build Coastguard Worker             // Safe because the device interrupts get stored in guest memory
186*bb4ee6a4SAndroid Build Coastguard Worker             let ret = unsafe { ioctl_with_ref(&self.vgic, KVM_SET_DEVICE_ATTR, &save_gic_attr) };
187*bb4ee6a4SAndroid Build Coastguard Worker             if ret != 0 {
188*bb4ee6a4SAndroid Build Coastguard Worker                 return errno_result()
189*bb4ee6a4SAndroid Build Coastguard Worker                     .context("ioctl KVM_SET_DEVICE_ATTR for save_gic_attr failed.")?;
190*bb4ee6a4SAndroid Build Coastguard Worker             }
191*bb4ee6a4SAndroid Build Coastguard Worker         }
192*bb4ee6a4SAndroid Build Coastguard Worker         Ok(serde_json::Value::Null)
193*bb4ee6a4SAndroid Build Coastguard Worker     }
194*bb4ee6a4SAndroid Build Coastguard Worker 
restore(&mut self, _data: serde_json::Value, _vcpus_num: usize) -> anyhow::Result<()>195*bb4ee6a4SAndroid Build Coastguard Worker     fn restore(&mut self, _data: serde_json::Value, _vcpus_num: usize) -> anyhow::Result<()> {
196*bb4ee6a4SAndroid Build Coastguard Worker         // SAVE_PENDING_TABLES operation wrote the pending tables into guest memory.
197*bb4ee6a4SAndroid Build Coastguard Worker         // Assumption is that no work is necessary on restore of IrqChip.
198*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
199*bb4ee6a4SAndroid Build Coastguard Worker     }
200*bb4ee6a4SAndroid Build Coastguard Worker 
finalize(&self) -> Result<()>201*bb4ee6a4SAndroid Build Coastguard Worker     fn finalize(&self) -> Result<()> {
202*bb4ee6a4SAndroid Build Coastguard Worker         let init_gic_attr = kvm_device_attr {
203*bb4ee6a4SAndroid Build Coastguard Worker             group: KVM_DEV_ARM_VGIC_GRP_CTRL,
204*bb4ee6a4SAndroid Build Coastguard Worker             attr: KVM_DEV_ARM_VGIC_CTRL_INIT as u64,
205*bb4ee6a4SAndroid Build Coastguard Worker             addr: 0,
206*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
207*bb4ee6a4SAndroid Build Coastguard Worker         };
208*bb4ee6a4SAndroid Build Coastguard Worker 
209*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
210*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we allocated the struct that's being passed in
211*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.vgic, KVM_SET_DEVICE_ATTR, &init_gic_attr) };
212*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 {
213*bb4ee6a4SAndroid Build Coastguard Worker             return errno_result();
214*bb4ee6a4SAndroid Build Coastguard Worker         }
215*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
216*bb4ee6a4SAndroid Build Coastguard Worker     }
217*bb4ee6a4SAndroid Build Coastguard Worker }
218