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}