arm_gic_driver/
define.rs

1use core::{
2    fmt::{self, Debug, Formatter},
3    ops::Range,
4};
5
6/// Interrupt trigger type configuration.
7///
8/// Defines whether an interrupt is triggered on signal edges or levels.
9/// This affects how the GIC samples and processes the interrupt signal.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum Trigger {
12    /// Edge-triggered interrupt.
13    ///
14    /// The interrupt is triggered on a rising edge (or falling edge for active-low signals).
15    /// The interrupt becomes pending when the signal transitions and remains pending
16    /// until software handles it, regardless of the signal's current state.
17    Edge,
18    /// Level-triggered interrupt.
19    ///
20    /// The interrupt is triggered when the signal is asserted (high for active-high,
21    /// low for active-low). The interrupt remains pending as long as the signal
22    /// stays asserted and becomes inactive when the signal is deasserted.
23    Level,
24}
25
26/// Configuration for setting up an interrupt.
27///
28/// Contains all necessary information to configure an interrupt in the GIC,
29/// including its ID and trigger behavior.
30///
31/// # Examples
32///
33/// ```
34/// use arm_gic_driver::{IrqConfig, IntId, Trigger};
35///
36/// let config = IrqConfig {
37///     id: IntId::spi(42),
38///     trigger: Trigger::Level,
39/// };
40/// ```
41#[derive(Debug, Clone)]
42pub struct IrqConfig {
43    /// The interrupt ID to configure
44    pub id: IntId,
45    /// The trigger type for this interrupt
46    pub trigger: Trigger,
47}
48
49/// Interrupt ID range for Software Generated Interrupts (SGIs).
50///
51/// SGI is an interrupt generated by software writing to a GICD_SGIR register in
52/// the GIC. The system uses SGIs for interprocessor communication.
53/// Range: 0-15 (16 interrupts total)
54pub const SGI_RANGE: Range<u32> = Range { start: 0, end: 16 };
55
56/// Interrupt ID range for Private Peripheral Interrupts (PPIs).
57///
58/// PPI is a peripheral interrupt that is specific to a single processor.
59/// Each CPU core has its own set of PPIs that cannot be routed to other cores.
60/// Range: 16-31 (16 interrupts total)
61pub const PPI_RANGE: Range<u32> = Range { start: 16, end: 32 };
62
63/// Interrupt ID range for Shared Peripheral Interrupts (SPIs).
64///
65/// SPI is a peripheral interrupt that the Distributor can route to any of a
66/// specified combination of processors. These are used for system-wide peripherals.
67/// Range: 32-1019 (988 interrupts total)
68pub const SPI_RANGE: Range<u32> = Range {
69    start: 32,
70    end: 1020,
71};
72
73/// Interrupt ID range for special interrupt IDs.
74///
75/// These interrupt IDs are reserved for special purposes and are not
76/// used for regular interrupt handling.
77/// Range: 1020-1023 (4 special values)
78pub const SPECIAL_RANGE: Range<u32> = Range {
79    start: 1020,
80    end: 1024,
81};
82
83/// An interrupt identifier (INTID) for the GIC.
84///
85/// Represents a unique interrupt ID that can be used with the GIC hardware.
86/// The GIC supports different types of interrupts based on the ID range:
87///
88/// - SGI (0-15): Software Generated Interrupts for inter-processor communication
89/// - PPI (16-31): Private Peripheral Interrupts specific to each CPU core  
90/// - SPI (32-1019): Shared Peripheral Interrupts that can be routed to any CPU
91/// - Special (1020-1023): Reserved interrupt IDs for special purposes
92///
93/// # Examples
94///
95/// ```
96/// use arm_gic_driver::IntId;
97///
98/// // Create different types of interrupt IDs
99/// let sgi = IntId::sgi(1);      // SGI #1
100/// let ppi = IntId::ppi(2);      // PPI #2 (actual ID will be 18)
101/// let spi = IntId::spi(42);     // SPI #42 (actual ID will be 74)
102///
103/// // Check interrupt type
104/// assert!(sgi.is_sgi());
105/// assert!(ppi.is_private());
106/// assert!(!spi.is_private());
107/// ```
108#[derive(Copy, Clone, Eq, Ord, PartialOrd, PartialEq)]
109pub struct IntId(u32);
110
111impl IntId {
112    /// Create a new `IntId` from a raw interrupt ID.
113    ///
114    /// # Arguments
115    ///
116    /// * `id` - The raw interrupt ID value
117    ///
118    /// # Safety
119    ///
120    /// The caller must ensure that `id` represents a valid interrupt ID
121    /// according to the GIC specification. Invalid IDs may cause undefined
122    /// behavior when used with GIC operations.
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use arm_gic_driver::IntId;
128    ///
129    /// // Create from a known valid interrupt ID
130    /// let intid = unsafe { IntId::raw(32) }; // SPI #0
131    /// ```
132    pub const unsafe fn raw(id: u32) -> Self {
133        Self(id)
134    }
135
136    /// Create an interrupt ID for a Software Generated Interrupt.
137    ///
138    /// SGIs are used for inter-processor communication and are always
139    /// private to the target CPU core.
140    ///
141    /// # Arguments
142    ///
143    /// * `sgi` - SGI number (0-15)
144    ///
145    /// # Panics
146    ///
147    /// Panics if `sgi` is greater than or equal to 16.
148    ///
149    /// # Examples
150    ///
151    /// ```
152    /// use arm_gic_driver::IntId;
153    ///
154    /// let sgi1 = IntId::sgi(1);
155    /// assert_eq!(sgi1.to_u32(), 1);
156    /// assert!(sgi1.is_sgi());
157    /// ```
158    pub const fn sgi(sgi: u32) -> Self {
159        assert!(sgi < SGI_RANGE.end);
160        Self(sgi)
161    }
162
163    /// Create an interrupt ID for a Private Peripheral Interrupt.
164    ///
165    /// PPIs are peripheral interrupts that are private to each CPU core.
166    /// The actual interrupt ID will be `ppi + 16`.
167    ///
168    /// # Arguments
169    ///
170    /// * `ppi` - PPI number (0-15, gets mapped to interrupt IDs 16-31)
171    ///
172    /// # Panics
173    ///
174    /// Panics if `ppi` is greater than or equal to 16.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// use arm_gic_driver::IntId;
180    ///
181    /// let ppi2 = IntId::ppi(2);
182    /// assert_eq!(ppi2.to_u32(), 18); // 16 + 2
183    /// assert!(ppi2.is_private());
184    /// ```
185    pub const fn ppi(ppi: u32) -> Self {
186        assert!(ppi < PPI_RANGE.end - PPI_RANGE.start);
187        Self(PPI_RANGE.start + ppi)
188    }
189
190    /// Create an interrupt ID for a Shared Peripheral Interrupt.
191    ///
192    /// SPIs are peripheral interrupts that can be routed to any CPU core.
193    /// The actual interrupt ID will be `spi + 32`.
194    ///
195    /// # Arguments
196    ///
197    /// * `spi` - SPI number (0-987, gets mapped to interrupt IDs 32-1019)
198    ///
199    /// # Panics
200    ///
201    /// Panics if `spi` would result in an interrupt ID >= 1020.
202    ///
203    /// # Examples
204    ///
205    /// ```
206    /// use arm_gic_driver::IntId;
207    ///
208    /// let spi42 = IntId::spi(42);
209    /// assert_eq!(spi42.to_u32(), 74); // 32 + 42
210    /// assert!(!spi42.is_private());
211    /// ```
212    pub const fn spi(spi: u32) -> Self {
213        assert!(spi < SPECIAL_RANGE.start);
214        Self(SPI_RANGE.start + spi)
215    }
216
217    /// Check if this interrupt ID is for a Software Generated Interrupt.
218    ///
219    /// # Returns
220    ///
221    /// `true` if this is an SGI (ID 0-15), `false` otherwise.
222    ///
223    /// # Examples
224    ///
225    /// ```
226    /// use arm_gic_driver::IntId;
227    ///
228    /// assert!(IntId::sgi(5).is_sgi());
229    /// assert!(!IntId::ppi(5).is_sgi());
230    /// ```
231    pub fn is_sgi(&self) -> bool {
232        SGI_RANGE.contains(&self.0)
233    }
234
235    /// Check if this interrupt ID is private to a CPU core.
236    ///
237    /// Private interrupts include both SGIs (0-15) and PPIs (16-31).
238    /// These interrupts cannot be routed between different CPU cores.
239    ///
240    /// # Returns
241    ///
242    /// `true` if this is a private interrupt (SGI or PPI), `false` for SPIs.
243    ///
244    /// # Examples
245    ///
246    /// ```
247    /// use arm_gic_driver::IntId;
248    ///
249    /// assert!(IntId::sgi(1).is_private());   // SGI
250    /// assert!(IntId::ppi(5).is_private());   // PPI
251    /// assert!(!IntId::spi(42).is_private()); // SPI
252    /// ```
253    pub fn is_private(&self) -> bool {
254        self.0 < SPI_RANGE.start
255    }
256
257    /// Get the raw interrupt ID as a u32 value.
258    ///
259    /// # Returns
260    ///
261    /// The interrupt ID as used by the GIC hardware.
262    ///
263    /// # Examples
264    ///
265    /// ```
266    /// use arm_gic_driver::IntId;
267    ///
268    /// let spi = IntId::spi(10);
269    /// assert_eq!(spi.to_u32(), 42); // 32 + 10
270    /// ```
271    pub const fn to_u32(self) -> u32 {
272        self.0
273    }
274
275    /// Check if this interrupt ID is in the special range.
276    ///
277    /// Special interrupt IDs (1020-1023) are reserved for specific purposes
278    /// and are not used for regular interrupt handling.
279    ///
280    /// # Returns
281    ///
282    /// `true` if this is a special interrupt ID, `false` otherwise.
283    ///
284    /// # Examples
285    ///
286    /// ```
287    /// use arm_gic_driver::IntId;
288    ///
289    /// let special = unsafe { IntId::raw(1023) };
290    /// assert!(special.is_special());
291    ///
292    /// let normal = IntId::spi(10);
293    /// assert!(!normal.is_special());
294    /// ```
295    pub fn is_special(&self) -> bool {
296        SPECIAL_RANGE.contains(&self.0)
297    }
298}
299
300impl Debug for IntId {
301    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
302        match self.0 {
303            0..16 => write!(f, "SGI {}", self.0 - SGI_RANGE.start),
304            16..32 => write!(f, "PPI {}", self.0 - PPI_RANGE.start),
305            32..1020 => write!(f, "SPI {}", self.0 - SPI_RANGE.start),
306            1020..1024 => write!(f, "Special IntId{}", self.0),
307            _ => write!(f, "Invalid IntId{}", self.0),
308        }
309    }
310}
311
312impl From<IntId> for u32 {
313    fn from(intid: IntId) -> Self {
314        intid.0
315    }
316}