arm_gic/lib.rs
1// Copyright 2023 The arm-gic Authors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Driver for the Arm Generic Interrupt Controller version 2, 3 or 4, on aarch64.
5//!
6//! This top level module contains functions that are not specific to any particular interrupt
7//! controller, as support for other GIC versions may be added in future.
8//!
9//! # Example
10//!
11//! Using a GICv3 on a single-core aarch64 system:
12//!
13//! ```no_run
14//! use arm_gic::{
15//! IntId,
16//! UniqueMmioPointer,
17//! gicv3::{
18//! GicCpuInterface, GicV3, SgiTarget, SgiTargetGroup,
19//! registers::{Gicd, GicrSgi},
20//! },
21//! irq_enable,
22//! };
23//! use core::ptr::NonNull;
24//!
25//! // Base addresses of the GICv3 distributor and redistributor.
26//! const GICD_BASE_ADDRESS: *mut Gicd = 0x800_0000 as _;
27//! const GICR_BASE_ADDRESS: *mut GicrSgi = 0x80A_0000 as _;
28//!
29//! let gicd = unsafe { UniqueMmioPointer::new(NonNull::new(GICD_BASE_ADDRESS).unwrap()) };
30//! let gicr = unsafe { NonNull::new(GICR_BASE_ADDRESS).unwrap() };
31//!
32//! // Initialise the GIC.
33//! let mut gic = unsafe { GicV3::new(gicd, gicr, 1, false) };
34//! gic.setup(0);
35//!
36//! // Configure an SGI and then send it to ourself.
37//! let sgi_intid = IntId::sgi(3);
38//! GicCpuInterface::set_priority_mask(0xff);
39//! gic.set_interrupt_priority(sgi_intid, Some(0), 0x80);
40//! gic.enable_interrupt(sgi_intid, Some(0), true);
41//! irq_enable();
42//! GicCpuInterface::send_sgi(
43//! sgi_intid,
44//! SgiTarget::List {
45//! affinity3: 0,
46//! affinity2: 0,
47//! affinity1: 0,
48//! target_list: 0b1,
49//! },
50//! SgiTargetGroup::CurrentGroup1,
51//! );
52//! ```
53
54#![cfg_attr(not(any(test, feature = "fakes")), no_std)]
55#![deny(clippy::undocumented_unsafe_blocks)]
56#![deny(unsafe_op_in_unsafe_fn)]
57
58pub mod gicv2;
59pub mod gicv3;
60#[cfg(any(test, feature = "fakes", target_arch = "aarch64", target_arch = "arm"))]
61mod sysreg;
62
63pub use safe_mmio::UniqueMmioPointer;
64
65#[cfg(feature = "fakes")]
66pub use sysreg::fake as sysreg_fake;
67#[cfg(feature = "fakes")]
68pub use sysreg::fake::{irq_disable, irq_enable, wfi};
69
70#[cfg(all(target_arch = "aarch64", not(feature = "fakes")))]
71use core::arch::asm;
72use core::fmt::{Debug, Formatter, Result};
73
74/// The trigger configuration for an interrupt.
75#[derive(Copy, Clone, Debug, Eq, PartialEq)]
76pub enum Trigger {
77 /// The interrupt is edge triggered.
78 Edge,
79 /// The interrupt is level triggered.
80 Level,
81}
82
83/// An interrupt ID.
84#[derive(Copy, Clone, Eq, Ord, PartialOrd, PartialEq)]
85pub struct IntId(u32);
86
87impl IntId {
88 /// Special interrupt ID returned when running at EL3 and the interrupt should be handled at
89 /// S-EL2 or S-EL1.
90 pub const SPECIAL_SECURE: Self = Self(1020);
91
92 /// Special interrupt ID returned when running at EL3 and the interrupt should be handled at
93 /// (non-secure) EL2 or EL1.
94 pub const SPECIAL_NONSECURE: Self = Self(1021);
95
96 /// Special interrupt ID returned when the interrupt is a non-maskable interrupt.
97 pub const SPECIAL_NMI: Self = Self(1022);
98
99 /// Special interrupt ID returned when there is no pending interrupt of sufficient priority for
100 /// the current security state and interrupt group.
101 pub const SPECIAL_NONE: Self = Self(1023);
102
103 /// The maximum number of SPIs which may be supported.
104 pub const MAX_SPI_COUNT: u32 = Self::SPECIAL_START - Self::SPI_START;
105
106 /// The number of Software Generated Interrupts.
107 pub const SGI_COUNT: u32 = Self::PPI_START - Self::SGI_START;
108
109 /// The number of (non-extended) Private Peripheral Interrupts.
110 pub const PPI_COUNT: u32 = Self::SPI_START - Self::PPI_START;
111
112 /// The maximum number of extended Private Peripheral Interrupts which may be supported.
113 pub const MAX_EPPI_COUNT: u32 = Self::EPPI_END - Self::EPPI_START;
114
115 /// The maximum number of extended Shared Peripheral Interrupts which may be supported.
116 pub const MAX_ESPI_COUNT: u32 = Self::ESPI_END - Self::ESPI_START;
117
118 /// The ID of the first Software Generated Interrupt.
119 const SGI_START: u32 = 0;
120
121 /// The ID of the first Private Peripheral Interrupt.
122 const PPI_START: u32 = 16;
123
124 /// The ID of the first Shared Peripheral Interrupt.
125 const SPI_START: u32 = 32;
126
127 /// The first special interrupt ID.
128 const SPECIAL_START: u32 = 1020;
129
130 /// One more than the last special interrupt ID.
131 const SPECIAL_END: u32 = 1024;
132
133 /// The first extended Private Peripheral Interrupt.
134 const EPPI_START: u32 = 1056;
135
136 /// One more than the last extended Private Peripheral Interrupt.
137 const EPPI_END: u32 = 1120;
138
139 /// The first extended Shared Peripheral Interrupt.
140 const ESPI_START: u32 = 4096;
141
142 /// One more than the last extended Shared Peripheral Interrupt.
143 const ESPI_END: u32 = 5120;
144
145 /// The first Locality-specific Peripheral Interrupt.
146 const LPI_START: u32 = 8192;
147
148 /// Returns the interrupt ID for the given Software Generated Interrupt.
149 pub const fn sgi(sgi: u32) -> Self {
150 assert!(sgi < Self::SGI_COUNT);
151 Self(Self::SGI_START + sgi)
152 }
153
154 /// Returns the interrupt ID for the given Private Peripheral Interrupt.
155 pub const fn ppi(ppi: u32) -> Self {
156 assert!(ppi < Self::PPI_COUNT);
157 Self(Self::PPI_START + ppi)
158 }
159
160 /// Returns the interrupt ID for the given Shared Peripheral Interrupt.
161 pub const fn spi(spi: u32) -> Self {
162 assert!(spi < Self::MAX_SPI_COUNT);
163 Self(Self::SPI_START + spi)
164 }
165
166 /// Returns the interrupt ID for the given extended Private Peripheral Interrupt.
167 pub const fn eppi(eppi: u32) -> Self {
168 assert!(eppi < Self::MAX_EPPI_COUNT);
169 Self(Self::EPPI_START + eppi)
170 }
171
172 /// Returns the interrupt ID for the given extended Shared Peripheral Interrupt.
173 pub const fn espi(espi: u32) -> Self {
174 assert!(espi < Self::MAX_ESPI_COUNT);
175 Self(Self::ESPI_START + espi)
176 }
177
178 /// Returns the interrupt ID for the given Locality-specific Peripheral Interrupt.
179 pub const fn lpi(lpi: u32) -> Self {
180 Self(Self::LPI_START + lpi)
181 }
182
183 /// Returns whether this interrupt ID is for a Software Generated Interrupt.
184 pub const fn is_sgi(self) -> bool {
185 self.0 < Self::PPI_START
186 }
187
188 /// Returns whether this interrupt ID is for a Private Peripheral Interrupt.
189 pub const fn is_ppi(self) -> bool {
190 Self::PPI_START <= self.0 && self.0 < Self::SPI_START
191 }
192
193 /// Returns whether this interrupt ID is for an Extended Private Peripheral Interrupt.
194 pub const fn is_eppi(self) -> bool {
195 Self::EPPI_START <= self.0 && self.0 < Self::EPPI_END
196 }
197
198 /// Returns whether this interrupt ID is for a Shared Peripheral Interrupt.
199 pub const fn is_spi(self) -> bool {
200 Self::SPI_START <= self.0 && self.0 < Self::SPECIAL_START
201 }
202
203 /// Returns whether this interrupt ID is for an Extended Shared Peripheral Interrupt.
204 pub const fn is_espi(self) -> bool {
205 Self::ESPI_START <= self.0 && self.0 < Self::ESPI_END
206 }
207
208 /// Returns whether this interrupt ID is private to a core, i.e. it is an SGI, PPI or EPPI.
209 pub const fn is_private(self) -> bool {
210 self.is_sgi() || self.is_ppi() || self.is_eppi()
211 }
212
213 /// Returns SGI index or `None` if it is not an SGI interrupt ID.
214 pub const fn sgi_index(self) -> Option<u32> {
215 if self.is_sgi() {
216 Some(self.0 - Self::SGI_START)
217 } else {
218 None
219 }
220 }
221
222 /// Maps SGI, PPI and EPPI interrupt IDs into a continuous index range starting from 0,
223 /// making it ideal for indexing redistributor registers.
224 pub const fn private_index(self) -> Option<usize> {
225 if self.is_sgi() || self.is_ppi() {
226 Some(self.0 as usize)
227 } else if self.is_eppi() {
228 // EPPI
229 Some((self.0 - IntId::EPPI_START + IntId::SGI_COUNT + IntId::PPI_COUNT) as usize)
230 } else {
231 None
232 }
233 }
234
235 /// Returns ESPI index or `None` if it is not an ESPI interrupt ID.
236 pub const fn espi_index(self) -> Option<usize> {
237 if self.is_espi() {
238 Some((self.0 - Self::ESPI_START) as usize)
239 } else {
240 None
241 }
242 }
243
244 // TODO: Change this to return a Range<IntId> once core::iter::Step is stabilised.
245 /// Returns an array of all interrupt Ids that are private to a core, i.e. SGIs and PPIs.
246 pub fn private() -> impl Iterator<Item = IntId> {
247 let sgis = (0..Self::SGI_COUNT).map(Self::sgi);
248 let ppis = (0..Self::PPI_COUNT).map(Self::ppi);
249
250 sgis.chain(ppis)
251 }
252
253 // TODO: Change this to return a Range<IntId> once core::iter::Step is stabilised.
254 /// Returns an array of all SPI Ids.
255 pub fn spis() -> impl Iterator<Item = IntId> {
256 (0..Self::MAX_SPI_COUNT).map(Self::spi)
257 }
258}
259
260impl Debug for IntId {
261 fn fmt(&self, f: &mut Formatter) -> Result {
262 if self.0 < Self::PPI_START {
263 write!(f, "SGI {}", self.0 - Self::SGI_START)
264 } else if self.0 < Self::SPI_START {
265 write!(f, "PPI {}", self.0 - Self::PPI_START)
266 } else if self.0 < Self::SPECIAL_START {
267 write!(f, "SPI {}", self.0 - Self::SPI_START)
268 } else if self.0 < Self::SPECIAL_END {
269 write!(f, "Special IntId {}", self.0)
270 } else if self.0 < Self::EPPI_START {
271 write!(f, "Reserved IntId {}", self.0)
272 } else if self.0 < Self::EPPI_END {
273 write!(f, "EPPI {}", self.0 - Self::EPPI_START)
274 } else if self.0 < Self::ESPI_START {
275 write!(f, "Reserved IntId {}", self.0)
276 } else if self.0 < Self::ESPI_END {
277 write!(f, "ESPI {}", self.0 - Self::ESPI_START)
278 } else if self.0 < Self::LPI_START {
279 write!(f, "Reserved IntId {}", self.0)
280 } else {
281 write!(f, "LPI {}", self.0 - Self::LPI_START)
282 }
283 }
284}
285
286impl From<IntId> for u32 {
287 fn from(intid: IntId) -> Self {
288 intid.0
289 }
290}
291
292/// Disables debug, SError, IRQ and FIQ exceptions.
293#[cfg(all(target_arch = "aarch64", not(feature = "fakes")))]
294pub fn irq_disable() {
295 // SAFETY: Writing to this system register doesn't access memory in any way.
296 unsafe {
297 asm!("msr DAIFSet, #0xf", options(nomem, nostack));
298 }
299}
300
301/// Enables debug, SError, IRQ and FIQ exceptions.
302#[cfg(all(target_arch = "aarch64", not(feature = "fakes")))]
303pub fn irq_enable() {
304 // SAFETY: Writing to this system register doesn't access memory in any way.
305 unsafe {
306 asm!("msr DAIFClr, #0xf", options(nomem, nostack));
307 }
308}
309
310/// Waits for an interrupt.
311#[cfg(all(target_arch = "aarch64", not(feature = "fakes")))]
312pub fn wfi() {
313 // SAFETY: This doesn't access memory in any way.
314 unsafe {
315 asm!("wfi", options(nomem, nostack));
316 }
317}