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