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}