esp_hal/interrupt/
xtensa.rs

1//! Interrupt handling
2
3use procmacros::ram;
4use xtensa_lx::interrupt;
5#[cfg(esp32)]
6pub(crate) use xtensa_lx::interrupt::free;
7#[cfg(feature = "rt")]
8use xtensa_lx_rt::exception::Context;
9
10pub use self::vectored::*;
11use super::InterruptStatus;
12use crate::{interrupt::IsrCallback, pac, peripherals::Interrupt, system::Cpu};
13
14/// Interrupt Error
15#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum Error {
18    /// The given interrupt is not a valid interrupt
19    InvalidInterrupt,
20    /// The CPU interrupt is a reserved interrupt
21    CpuInterruptReserved,
22}
23
24/// Enumeration of available CPU interrupts
25///
26/// It's possible to create one handler per priority level. (e.g
27/// `level1_interrupt`)
28#[derive(Debug, Copy, Clone)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30#[repr(u32)]
31pub enum CpuInterrupt {
32    /// Level-triggered interrupt with priority 1.
33    Interrupt0LevelPriority1 = 0,
34    /// Level-triggered interrupt with priority 1.
35    Interrupt1LevelPriority1,
36    /// Level-triggered interrupt with priority 1.
37    Interrupt2LevelPriority1,
38    /// Level-triggered interrupt with priority 1.
39    Interrupt3LevelPriority1,
40    /// Level-triggered interrupt with priority 1.
41    Interrupt4LevelPriority1,
42    /// Level-triggered interrupt with priority 1.
43    Interrupt5LevelPriority1,
44    /// Timer 0 interrupt with priority 1.
45    Interrupt6Timer0Priority1,
46    /// Software-triggered interrupt with priority 1.
47    Interrupt7SoftwarePriority1,
48    /// Level-triggered interrupt with priority 1.
49    Interrupt8LevelPriority1,
50    /// Level-triggered interrupt with priority 1.
51    Interrupt9LevelPriority1,
52    /// Edge-triggered interrupt with priority 1.
53    Interrupt10EdgePriority1,
54    /// Profiling-related interrupt with priority 3.
55    Interrupt11ProfilingPriority3,
56    /// Level-triggered interrupt with priority 1.
57    Interrupt12LevelPriority1,
58    /// Level-triggered interrupt with priority 1.
59    Interrupt13LevelPriority1,
60    /// Non-maskable interrupt (NMI) with priority 7.
61    Interrupt14NmiPriority7,
62    /// Timer 1 interrupt with priority 3.
63    Interrupt15Timer1Priority3,
64    /// Timer 2 interrupt with priority 5.
65    Interrupt16Timer2Priority5,
66    /// Level-triggered interrupt with priority 1.
67    Interrupt17LevelPriority1,
68    /// Level-triggered interrupt with priority 1.
69    Interrupt18LevelPriority1,
70    /// Level-triggered interrupt with priority 2.
71    Interrupt19LevelPriority2,
72    /// Level-triggered interrupt with priority 2.
73    Interrupt20LevelPriority2,
74    /// Level-triggered interrupt with priority 2.
75    Interrupt21LevelPriority2,
76    /// Edge-triggered interrupt with priority 3.
77    Interrupt22EdgePriority3,
78    /// Level-triggered interrupt with priority 3.
79    Interrupt23LevelPriority3,
80    /// Level-triggered interrupt with priority 4.
81    Interrupt24LevelPriority4,
82    /// Level-triggered interrupt with priority 4.
83    Interrupt25LevelPriority4,
84    /// Level-triggered interrupt with priority 5.
85    Interrupt26LevelPriority5,
86    /// Level-triggered interrupt with priority 3.
87    Interrupt27LevelPriority3,
88    /// Edge-triggered interrupt with priority 4.
89    Interrupt28EdgePriority4,
90    /// Software-triggered interrupt with priority 3.
91    Interrupt29SoftwarePriority3,
92    /// Edge-triggered interrupt with priority 4.
93    Interrupt30EdgePriority4,
94    /// Edge-triggered interrupt with priority 5.
95    Interrupt31EdgePriority5,
96}
97
98impl CpuInterrupt {
99    fn from_u32(n: u32) -> Option<Self> {
100        if n < 32 {
101            Some(unsafe { core::mem::transmute::<u32, Self>(n) })
102        } else {
103            None
104        }
105    }
106
107    fn is_internal(self) -> bool {
108        matches!(
109            self,
110            Self::Interrupt6Timer0Priority1
111                | Self::Interrupt7SoftwarePriority1
112                | Self::Interrupt11ProfilingPriority3
113                | Self::Interrupt15Timer1Priority3
114                | Self::Interrupt16Timer2Priority5
115                | Self::Interrupt29SoftwarePriority3
116        )
117    }
118
119    fn is_peripheral(self) -> bool {
120        !self.is_internal()
121    }
122}
123
124/// The interrupts reserved by the HAL
125#[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
126pub static RESERVED_INTERRUPTS: &[u32] = &[
127    CpuInterrupt::Interrupt1LevelPriority1 as _,
128    CpuInterrupt::Interrupt19LevelPriority2 as _,
129    CpuInterrupt::Interrupt23LevelPriority3 as _,
130    CpuInterrupt::Interrupt10EdgePriority1 as _,
131    CpuInterrupt::Interrupt22EdgePriority3 as _,
132];
133
134pub(crate) fn setup_interrupts() {
135    // disable all known interrupts
136    // at least after the 2nd stage bootloader there are some interrupts enabled
137    // (e.g. UART)
138    for peripheral_interrupt in 0..255 {
139        Interrupt::try_from(peripheral_interrupt)
140            .map(|intr| {
141                #[cfg(multi_core)]
142                disable(Cpu::AppCpu, intr);
143                disable(Cpu::ProCpu, intr);
144            })
145            .ok();
146    }
147}
148
149/// Enable an interrupt by directly binding it to a available CPU interrupt
150///
151/// Unless you are sure, you most likely want to use [`enable`] instead.
152///
153/// Trying using a reserved interrupt from [`RESERVED_INTERRUPTS`] will return
154/// an error.
155pub fn enable_direct(interrupt: Interrupt, cpu_interrupt: CpuInterrupt) -> Result<(), Error> {
156    if RESERVED_INTERRUPTS.contains(&(cpu_interrupt as _)) {
157        return Err(Error::CpuInterruptReserved);
158    }
159    unsafe {
160        map(Cpu::current(), interrupt, cpu_interrupt);
161
162        xtensa_lx::interrupt::enable_mask(1 << cpu_interrupt as u32);
163    }
164    Ok(())
165}
166
167/// Assign a peripheral interrupt to an CPU interrupt
168///
169/// Note: this only maps the interrupt to the CPU interrupt. The CPU interrupt
170/// still needs to be enabled afterwards
171///
172/// # Safety
173///
174/// Do not use CPU interrupts in the [`RESERVED_INTERRUPTS`].
175pub unsafe fn map(cpu: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
176    let interrupt_number = interrupt as usize;
177    let cpu_interrupt_number = which as u32;
178    match cpu {
179        Cpu::ProCpu => unsafe {
180            (*core0_interrupt_peripheral())
181                .core_0_intr_map(interrupt_number)
182                .write(|w| w.bits(cpu_interrupt_number));
183        },
184        #[cfg(multi_core)]
185        Cpu::AppCpu => unsafe {
186            (*core1_interrupt_peripheral())
187                .core_1_intr_map(interrupt_number)
188                .write(|w| w.bits(cpu_interrupt_number));
189        },
190    }
191}
192
193/// Get cpu interrupt assigned to peripheral interrupt
194pub(crate) fn bound_cpu_interrupt_for(cpu: Cpu, interrupt: Interrupt) -> Option<CpuInterrupt> {
195    let cpu_intr = match cpu {
196        Cpu::ProCpu => unsafe {
197            (*core0_interrupt_peripheral())
198                .core_0_intr_map(interrupt as usize)
199                .read()
200                .bits()
201        },
202        #[cfg(multi_core)]
203        Cpu::AppCpu => unsafe {
204            (*core1_interrupt_peripheral())
205                .core_1_intr_map(interrupt as usize)
206                .read()
207                .bits()
208        },
209    };
210    let cpu_intr = CpuInterrupt::from_u32(cpu_intr)?;
211
212    if cpu_intr.is_peripheral() {
213        Some(cpu_intr)
214    } else {
215        None
216    }
217}
218
219/// Disable the given peripheral interrupt
220pub fn disable(core: Cpu, interrupt: Interrupt) {
221    unsafe { map(core, interrupt, CpuInterrupt::Interrupt16Timer2Priority5) }
222}
223
224/// Clear the given CPU interrupt
225pub fn clear(_core: Cpu, which: CpuInterrupt) {
226    unsafe {
227        xtensa_lx::interrupt::clear(1 << which as u32);
228    }
229}
230
231/// Get status of peripheral interrupts
232#[cfg(interrupts_status_registers = "3")]
233pub fn status(core: Cpu) -> InterruptStatus {
234    unsafe {
235        match core {
236            Cpu::ProCpu => InterruptStatus::from(
237                (*core0_interrupt_peripheral())
238                    .core_0_intr_status(0)
239                    .read()
240                    .bits(),
241                (*core0_interrupt_peripheral())
242                    .core_0_intr_status(1)
243                    .read()
244                    .bits(),
245                (*core0_interrupt_peripheral())
246                    .core_0_intr_status(2)
247                    .read()
248                    .bits(),
249            ),
250            #[cfg(multi_core)]
251            Cpu::AppCpu => InterruptStatus::from(
252                (*core1_interrupt_peripheral())
253                    .core_1_intr_status(0)
254                    .read()
255                    .bits(),
256                (*core1_interrupt_peripheral())
257                    .core_1_intr_status(1)
258                    .read()
259                    .bits(),
260                (*core1_interrupt_peripheral())
261                    .core_1_intr_status(2)
262                    .read()
263                    .bits(),
264            ),
265        }
266    }
267}
268
269/// Get status of peripheral interrupts
270#[cfg(interrupts_status_registers = "4")]
271pub fn status(core: Cpu) -> InterruptStatus {
272    unsafe {
273        match core {
274            Cpu::ProCpu => InterruptStatus::from(
275                (*core0_interrupt_peripheral())
276                    .core_0_intr_status(0)
277                    .read()
278                    .bits(),
279                (*core0_interrupt_peripheral())
280                    .core_0_intr_status(1)
281                    .read()
282                    .bits(),
283                (*core0_interrupt_peripheral())
284                    .core_0_intr_status(2)
285                    .read()
286                    .bits(),
287                (*core0_interrupt_peripheral())
288                    .core_0_intr_status(3)
289                    .read()
290                    .bits(),
291            ),
292            #[cfg(multi_core)]
293            Cpu::AppCpu => InterruptStatus::from(
294                (*core1_interrupt_peripheral())
295                    .core_1_intr_status(0)
296                    .read()
297                    .bits(),
298                (*core1_interrupt_peripheral())
299                    .core_1_intr_status(1)
300                    .read()
301                    .bits(),
302                (*core1_interrupt_peripheral())
303                    .core_1_intr_status(2)
304                    .read()
305                    .bits(),
306                (*core1_interrupt_peripheral())
307                    .core_1_intr_status(3)
308                    .read()
309                    .bits(),
310            ),
311        }
312    }
313}
314
315#[cfg(esp32)]
316unsafe fn core0_interrupt_peripheral() -> *const crate::pac::dport::RegisterBlock {
317    pac::DPORT::PTR
318}
319
320#[cfg(esp32)]
321unsafe fn core1_interrupt_peripheral() -> *const crate::pac::dport::RegisterBlock {
322    pac::DPORT::PTR
323}
324
325#[cfg(any(esp32s2, esp32s3))]
326unsafe fn core0_interrupt_peripheral() -> *const crate::pac::interrupt_core0::RegisterBlock {
327    pac::INTERRUPT_CORE0::PTR
328}
329
330#[cfg(esp32s3)]
331unsafe fn core1_interrupt_peripheral() -> *const crate::pac::interrupt_core1::RegisterBlock {
332    pac::INTERRUPT_CORE1::PTR
333}
334
335/// Get the current run level (the level below which interrupts are masked).
336pub fn current_runlevel() -> Priority {
337    let ps: u32;
338    unsafe { core::arch::asm!("rsr.ps {0}", out(reg) ps) };
339
340    let prev_interrupt_priority = ps as u8 & 0x0F;
341
342    unwrap!(Priority::try_from(prev_interrupt_priority))
343}
344
345/// Changes the current run level (the level below which interrupts are
346/// masked), and returns the previous run level.
347///
348/// # Safety
349///
350/// This function must only be used to raise the runlevel and to restore it
351/// to a previous value. It must not be used to arbitrarily lower the
352/// runlevel.
353pub(crate) unsafe fn change_current_runlevel(level: Priority) -> Priority {
354    let token: u32;
355    unsafe {
356        match level {
357            Priority::None => core::arch::asm!("rsil {0}, 0", out(reg) token),
358            Priority::Priority1 => core::arch::asm!("rsil {0}, 1", out(reg) token),
359            Priority::Priority2 => core::arch::asm!("rsil {0}, 2", out(reg) token),
360            Priority::Priority3 => core::arch::asm!("rsil {0}, 3", out(reg) token),
361        };
362    }
363
364    let prev_interrupt_priority = token as u8 & 0x0F;
365
366    unwrap!(Priority::try_from(prev_interrupt_priority))
367}
368
369mod vectored {
370    use super::*;
371
372    /// Interrupt priority levels.
373    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
374    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
375    #[repr(u8)]
376    pub enum Priority {
377        /// No priority.
378        None = 0,
379        /// Priority level 1.
380        Priority1,
381        /// Priority level 2.
382        Priority2,
383        /// Priority level 3.
384        Priority3,
385    }
386
387    impl Priority {
388        /// Maximum interrupt priority
389        pub const fn max() -> Priority {
390            Priority::Priority3
391        }
392
393        /// Minimum interrupt priority
394        pub const fn min() -> Priority {
395            Priority::Priority1
396        }
397    }
398
399    impl TryFrom<u32> for Priority {
400        type Error = Error;
401
402        fn try_from(value: u32) -> Result<Self, Self::Error> {
403            match value {
404                0 => Ok(Priority::None),
405                1 => Ok(Priority::Priority1),
406                2 => Ok(Priority::Priority2),
407                3 => Ok(Priority::Priority3),
408                _ => Err(Error::InvalidInterrupt),
409            }
410        }
411    }
412
413    impl TryFrom<u8> for Priority {
414        type Error = Error;
415
416        fn try_from(value: u8) -> Result<Self, Self::Error> {
417            Self::try_from(value as u32)
418        }
419    }
420
421    impl CpuInterrupt {
422        #[inline]
423        fn level(&self) -> Priority {
424            match self {
425                CpuInterrupt::Interrupt0LevelPriority1
426                | CpuInterrupt::Interrupt1LevelPriority1
427                | CpuInterrupt::Interrupt2LevelPriority1
428                | CpuInterrupt::Interrupt3LevelPriority1
429                | CpuInterrupt::Interrupt4LevelPriority1
430                | CpuInterrupt::Interrupt5LevelPriority1
431                | CpuInterrupt::Interrupt6Timer0Priority1
432                | CpuInterrupt::Interrupt7SoftwarePriority1
433                | CpuInterrupt::Interrupt8LevelPriority1
434                | CpuInterrupt::Interrupt9LevelPriority1
435                | CpuInterrupt::Interrupt10EdgePriority1
436                | CpuInterrupt::Interrupt12LevelPriority1
437                | CpuInterrupt::Interrupt13LevelPriority1
438                | CpuInterrupt::Interrupt17LevelPriority1
439                | CpuInterrupt::Interrupt18LevelPriority1 => Priority::Priority1,
440
441                CpuInterrupt::Interrupt19LevelPriority2
442                | CpuInterrupt::Interrupt20LevelPriority2
443                | CpuInterrupt::Interrupt21LevelPriority2 => Priority::Priority2,
444
445                CpuInterrupt::Interrupt11ProfilingPriority3
446                | CpuInterrupt::Interrupt15Timer1Priority3
447                | CpuInterrupt::Interrupt22EdgePriority3
448                | CpuInterrupt::Interrupt27LevelPriority3
449                | CpuInterrupt::Interrupt29SoftwarePriority3
450                | CpuInterrupt::Interrupt23LevelPriority3 => Priority::Priority3,
451
452                // we direct these to None because we do not support interrupts at this level
453                // through Rust
454                CpuInterrupt::Interrupt24LevelPriority4
455                | CpuInterrupt::Interrupt25LevelPriority4
456                | CpuInterrupt::Interrupt28EdgePriority4
457                | CpuInterrupt::Interrupt30EdgePriority4
458                | CpuInterrupt::Interrupt31EdgePriority5
459                | CpuInterrupt::Interrupt16Timer2Priority5
460                | CpuInterrupt::Interrupt26LevelPriority5
461                | CpuInterrupt::Interrupt14NmiPriority7 => Priority::None,
462            }
463        }
464    }
465
466    /// Get the interrupts configured for the core
467    #[inline(always)]
468    pub(crate) fn configured_interrupts(
469        core: Cpu,
470        status: InterruptStatus,
471        level: u32,
472    ) -> InterruptStatus {
473        unsafe {
474            let intr_map_base = match core {
475                Cpu::ProCpu => (*core0_interrupt_peripheral()).core_0_intr_map(0).as_ptr(),
476                #[cfg(multi_core)]
477                Cpu::AppCpu => (*core1_interrupt_peripheral()).core_1_intr_map(0).as_ptr(),
478            };
479
480            let mut res = InterruptStatus::empty();
481
482            for interrupt_nr in status.iterator() {
483                let i = interrupt_nr as isize;
484                let cpu_interrupt = intr_map_base.offset(i).read_volatile();
485                // safety: cast is safe because of repr(u32)
486                let cpu_interrupt = core::mem::transmute::<u32, CpuInterrupt>(cpu_interrupt);
487                let int_level = cpu_interrupt.level() as u32;
488
489                if int_level == level {
490                    res.set(interrupt_nr);
491                }
492            }
493
494            res
495        }
496    }
497
498    /// Enable the given peripheral interrupt
499    pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
500        enable_on_cpu(Cpu::current(), interrupt, level)
501    }
502
503    pub(crate) fn enable_on_cpu(
504        cpu: Cpu,
505        interrupt: Interrupt,
506        level: Priority,
507    ) -> Result<(), Error> {
508        let cpu_interrupt =
509            interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?;
510
511        unsafe {
512            map(cpu, interrupt, cpu_interrupt);
513
514            xtensa_lx::interrupt::enable_mask(1 << cpu_interrupt as u32);
515        }
516        Ok(())
517    }
518
519    /// Binds the given interrupt to the given handler.
520    ///
521    /// # Safety
522    ///
523    /// This will replace any previously bound interrupt handler
524    pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: IsrCallback) {
525        let ptr =
526            unsafe { &pac::__INTERRUPTS[interrupt as usize]._handler as *const _ as *mut usize };
527        unsafe {
528            ptr.write_volatile(handler.raw_value());
529        }
530    }
531
532    /// Returns the currently bound interrupt handler.
533    pub fn bound_handler(interrupt: Interrupt) -> Option<IsrCallback> {
534        unsafe {
535            let addr = pac::__INTERRUPTS[interrupt as usize]._handler as usize;
536            if addr == 0 {
537                return None;
538            }
539            Some(IsrCallback::from_raw(addr))
540        }
541    }
542
543    fn interrupt_level_to_cpu_interrupt(
544        level: Priority,
545        is_edge: bool,
546    ) -> Result<CpuInterrupt, Error> {
547        Ok(if is_edge {
548            match level {
549                Priority::None => return Err(Error::InvalidInterrupt),
550                Priority::Priority1 => CpuInterrupt::Interrupt10EdgePriority1,
551                Priority::Priority2 => return Err(Error::InvalidInterrupt),
552                Priority::Priority3 => CpuInterrupt::Interrupt22EdgePriority3,
553            }
554        } else {
555            match level {
556                Priority::None => return Err(Error::InvalidInterrupt),
557                Priority::Priority1 => CpuInterrupt::Interrupt1LevelPriority1,
558                Priority::Priority2 => CpuInterrupt::Interrupt19LevelPriority2,
559                Priority::Priority3 => CpuInterrupt::Interrupt23LevelPriority3,
560            }
561        })
562    }
563
564    // TODO use CpuInterrupt::LevelX.mask() // TODO make it const
565    #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
566    pub(crate) static CPU_INTERRUPT_LEVELS: [u32; 8] = [
567        0b_0000_0000_0000_0000_0000_0000_0000_0000, // Dummy level 0
568        0b_0000_0000_0000_0110_0011_0111_1111_1111, // Level_1
569        0b_0000_0000_0011_1000_0000_0000_0000_0000, // Level 2
570        0b_0010_1000_1100_0000_1000_1000_0000_0000, // Level 3
571        0b_0101_0011_0000_0000_0000_0000_0000_0000, // Level 4
572        0b_1000_0100_0000_0001_0000_0000_0000_0000, // Level 5
573        0b_0000_0000_0000_0000_0000_0000_0000_0000, // Level 6
574        0b_0000_0000_0000_0000_0100_0000_0000_0000, // Level 7
575    ];
576    #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
577    pub(crate) static CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000;
578    #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
579    pub(crate) static CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000;
580
581    #[cfg(esp32)]
582    pub(crate) mod chip_specific {
583        use super::*;
584        #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
585        pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from(
586            0b0000_0000_0000_0000_0000_0000_0000_0000,
587            0b1111_1100_0000_0000_0000_0000_0000_0000,
588            0b0000_0000_0000_0000_0000_0000_0000_0011,
589        );
590        #[inline]
591        pub fn interrupt_is_edge(interrupt: Interrupt) -> bool {
592            [
593                Interrupt::TG0_T0_EDGE,
594                Interrupt::TG0_T1_EDGE,
595                Interrupt::TG0_WDT_EDGE,
596                Interrupt::TG0_LACT_EDGE,
597                Interrupt::TG1_T0_EDGE,
598                Interrupt::TG1_T1_EDGE,
599                Interrupt::TG1_WDT_EDGE,
600                Interrupt::TG1_LACT_EDGE,
601            ]
602            .contains(&interrupt)
603        }
604    }
605
606    #[cfg(esp32s2)]
607    pub(crate) mod chip_specific {
608        use super::*;
609        #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
610        pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from(
611            0b0000_0000_0000_0000_0000_0000_0000_0000,
612            0b1100_0000_0000_0000_0000_0000_0000_0000,
613            0b0000_0000_0000_0000_0000_0011_1011_1111,
614        );
615        #[inline]
616        pub fn interrupt_is_edge(interrupt: Interrupt) -> bool {
617            [
618                Interrupt::TG0_T0_EDGE,
619                Interrupt::TG0_T1_EDGE,
620                Interrupt::TG0_WDT_EDGE,
621                Interrupt::TG0_LACT_EDGE,
622                Interrupt::TG1_T0_EDGE,
623                Interrupt::TG1_T1_EDGE,
624                Interrupt::TG1_WDT_EDGE,
625                Interrupt::TG1_LACT_EDGE,
626                Interrupt::SYSTIMER_TARGET0,
627                Interrupt::SYSTIMER_TARGET1,
628                Interrupt::SYSTIMER_TARGET2,
629            ]
630            .contains(&interrupt)
631        }
632    }
633
634    #[cfg(esp32s3)]
635    pub(crate) mod chip_specific {
636        use super::*;
637        #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
638        pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::empty();
639        #[inline]
640        pub fn interrupt_is_edge(_interrupt: Interrupt) -> bool {
641            false
642        }
643    }
644}
645
646#[cfg(feature = "rt")]
647mod rt {
648    use super::{vectored::*, *};
649
650    #[unsafe(no_mangle)]
651    #[ram]
652    unsafe fn __level_1_interrupt(save_frame: &mut Context) {
653        unsafe {
654            handle_interrupts::<1>(save_frame);
655        }
656    }
657
658    #[unsafe(no_mangle)]
659    #[ram]
660    unsafe fn __level_2_interrupt(save_frame: &mut Context) {
661        unsafe {
662            handle_interrupts::<2>(save_frame);
663        }
664    }
665
666    #[unsafe(no_mangle)]
667    #[ram]
668    unsafe fn __level_3_interrupt(save_frame: &mut Context) {
669        unsafe {
670            handle_interrupts::<3>(save_frame);
671        }
672    }
673
674    #[inline(always)]
675    unsafe fn handle_interrupts<const LEVEL: u32>(save_frame: &mut Context) {
676        let core = Cpu::current();
677
678        let cpu_interrupt_mask =
679            interrupt::get() & interrupt::get_mask() & CPU_INTERRUPT_LEVELS[LEVEL as usize];
680
681        if cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL != 0 {
682            // Let's handle CPU-internal interrupts (NMI, Timer, Software, Profiling).
683            // These are rarely used by the HAL.
684
685            // Mask the relevant bits
686            let cpu_interrupt_mask = cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL;
687
688            // Pick one
689            let cpu_interrupt_nr = cpu_interrupt_mask.trailing_zeros();
690
691            // If the interrupt is edge triggered, we need to clear the request on the CPU's
692            // side.
693            if ((1 << cpu_interrupt_nr) & CPU_INTERRUPT_EDGE) != 0 {
694                unsafe {
695                    interrupt::clear(1 << cpu_interrupt_nr);
696                }
697            }
698
699            if let Some(handler) = cpu_interrupt_nr_to_cpu_interrupt_handler(cpu_interrupt_nr) {
700                unsafe { handler(save_frame) };
701            }
702        } else {
703            let status = if !cfg!(esp32s3) && (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 {
704                // Next, handle edge triggered peripheral interrupts. Note that on the S3 all
705                // peripheral interrupts are level-triggered.
706
707                // If the interrupt is edge triggered, we need to clear the
708                // request on the CPU's side
709                unsafe { interrupt::clear(cpu_interrupt_mask & CPU_INTERRUPT_EDGE) };
710
711                // For edge interrupts we cannot rely on the peripherals' interrupt status
712                // registers, therefore call all registered handlers for current level.
713                chip_specific::INTERRUPT_EDGE
714            } else {
715                // Finally, check level-triggered peripheral sources.
716                // These interrupts are cleared by the peripheral.
717                status(core)
718            };
719
720            let configured_interrupts = configured_interrupts(core, status, LEVEL);
721            for interrupt_nr in configured_interrupts.iterator() {
722                let handler = unsafe { pac::__INTERRUPTS[interrupt_nr as usize]._handler };
723                let handler: fn(&mut Context) = unsafe {
724                    core::mem::transmute::<unsafe extern "C" fn(), fn(&mut Context)>(handler)
725                };
726                handler(save_frame);
727            }
728        }
729    }
730
731    #[inline]
732    pub(crate) fn cpu_interrupt_nr_to_cpu_interrupt_handler(
733        number: u32,
734    ) -> Option<unsafe extern "C" fn(save_frame: &mut Context)> {
735        use xtensa_lx_rt::*;
736        // we're fortunate that all esp variants use the same CPU interrupt layout
737        Some(match number {
738            6 => Timer0,
739            7 => Software0,
740            11 => Profiling,
741            14 => NMI,
742            15 => Timer1,
743            16 => Timer2,
744            29 => Software1,
745            _ => return None,
746        })
747    }
748
749    // Raw handlers for CPU interrupts, assembly only.
750    unsafe extern "C" {
751        fn level4_interrupt(save_frame: &mut Context);
752        fn level5_interrupt(save_frame: &mut Context);
753        #[cfg(not(all(feature = "rt", feature = "exception-handler", stack_guard_monitoring)))]
754        fn level6_interrupt(save_frame: &mut Context);
755        fn level7_interrupt(save_frame: &mut Context);
756    }
757
758    #[unsafe(no_mangle)]
759    #[unsafe(link_section = ".rwtext")]
760    unsafe fn __level_4_interrupt(save_frame: &mut Context) {
761        unsafe { level4_interrupt(save_frame) }
762    }
763
764    #[unsafe(no_mangle)]
765    #[unsafe(link_section = ".rwtext")]
766    unsafe fn __level_5_interrupt(save_frame: &mut Context) {
767        unsafe { level5_interrupt(save_frame) }
768    }
769
770    #[unsafe(no_mangle)]
771    #[unsafe(link_section = ".rwtext")]
772    unsafe fn __level_6_interrupt(save_frame: &mut Context) {
773        cfg_if::cfg_if! {
774            if #[cfg(all(feature = "rt", feature = "exception-handler", stack_guard_monitoring))] {
775                crate::exception_handler::breakpoint_interrupt(save_frame);
776            } else {
777                unsafe { level6_interrupt(save_frame) }
778            }
779        }
780    }
781
782    #[unsafe(no_mangle)]
783    #[unsafe(link_section = ".rwtext")]
784    unsafe fn __level_7_interrupt(save_frame: &mut Context) {
785        unsafe { level7_interrupt(save_frame) }
786    }
787}