esp_riscv_rt/
lib.rs

1//! Minimal startup/runtime for RISC-V CPUs from Espressif.
2//!
3//! ## Features
4//!
5//! This crate provides:
6//!
7//! - Before main initialization of the `.bss` and `.data` sections controlled
8//!   by features
9//! - `#[entry]` to declare the entry point of the program
10//!
11//! ## Feature Flags
12#![doc = document_features::document_features!()]
13#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
14#![deny(missing_docs)]
15#![no_std]
16
17use core::arch::global_asm;
18
19pub use riscv;
20use riscv::register::{
21    mcause,
22    mtvec::{self, TrapMode},
23};
24pub use riscv_rt_macros::{entry, pre_init};
25
26pub use self::Interrupt as interrupt;
27
28#[export_name = "error: esp-riscv-rt appears more than once in the dependency graph"]
29#[doc(hidden)]
30pub static __ONCE__: () = ();
31
32extern "C" {
33    // Boundaries of the .bss section
34    static mut _bss_end: u32;
35    static mut _bss_start: u32;
36
37    // Boundaries of the .data section
38    static mut _data_end: u32;
39    static mut _data_start: u32;
40
41    // Initial values of the .data section (stored in Flash)
42    static _sidata: u32;
43}
44
45/// Rust entry point (_start_rust)
46///
47/// Zeros bss section, initializes data section and calls main. This function
48/// never returns.
49///
50/// # Safety
51///
52/// This function should not be called directly by the user, and should instead
53/// be invoked by the runtime implicitly.
54#[link_section = ".init.rust"]
55#[export_name = "_start_rust"]
56pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
57    extern "Rust" {
58        fn hal_main(a0: usize, a1: usize, a2: usize) -> !;
59
60        fn __post_init();
61
62        fn _setup_interrupts();
63
64    }
65
66    __post_init();
67
68    _setup_interrupts();
69
70    hal_main(a0, a1, a2);
71}
72
73/// Registers saved in trap handler
74#[derive(Debug, Default, Clone, Copy)]
75#[repr(C)]
76pub struct TrapFrame {
77    /// Return address, stores the address to return to after a function call or
78    /// interrupt.
79    pub ra: usize,
80    /// Temporary register t0, used for intermediate values.
81    pub t0: usize,
82    /// Temporary register t1, used for intermediate values.
83    pub t1: usize,
84    /// Temporary register t2, used for intermediate values.
85    pub t2: usize,
86    /// Temporary register t3, used for intermediate values.
87    pub t3: usize,
88    /// Temporary register t4, used for intermediate values.
89    pub t4: usize,
90    /// Temporary register t5, used for intermediate values.
91    pub t5: usize,
92    /// Temporary register t6, used for intermediate values.
93    pub t6: usize,
94    /// Argument register a0, typically used to pass the first argument to a
95    /// function.
96    pub a0: usize,
97    /// Argument register a1, typically used to pass the second argument to a
98    /// function.
99    pub a1: usize,
100    /// Argument register a2, typically used to pass the third argument to a
101    /// function.
102    pub a2: usize,
103    /// Argument register a3, typically used to pass the fourth argument to a
104    /// function.
105    pub a3: usize,
106    /// Argument register a4, typically used to pass the fifth argument to a
107    /// function.
108    pub a4: usize,
109    /// Argument register a5, typically used to pass the sixth argument to a
110    /// function.
111    pub a5: usize,
112    /// Argument register a6, typically used to pass the seventh argument to a
113    /// function.
114    pub a6: usize,
115    /// Argument register a7, typically used to pass the eighth argument to a
116    /// function.
117    pub a7: usize,
118    /// Saved register s0, used to hold values across function calls.
119    pub s0: usize,
120    /// Saved register s1, used to hold values across function calls.
121    pub s1: usize,
122    /// Saved register s2, used to hold values across function calls.
123    pub s2: usize,
124    /// Saved register s3, used to hold values across function calls.
125    pub s3: usize,
126    /// Saved register s4, used to hold values across function calls.
127    pub s4: usize,
128    /// Saved register s5, used to hold values across function calls.
129    pub s5: usize,
130    /// Saved register s6, used to hold values across function calls.
131    pub s6: usize,
132    /// Saved register s7, used to hold values across function calls.
133    pub s7: usize,
134    /// Saved register s8, used to hold values across function calls.
135    pub s8: usize,
136    /// Saved register s9, used to hold values across function calls.
137    pub s9: usize,
138    /// Saved register s10, used to hold values across function calls.
139    pub s10: usize,
140    /// Saved register s11, used to hold values across function calls.
141    pub s11: usize,
142    /// Global pointer register, holds the address of the global data area.
143    pub gp: usize,
144    /// Thread pointer register, holds the address of the thread-local storage
145    /// area.
146    pub tp: usize,
147    /// Stack pointer register, holds the address of the top of the stack.
148    pub sp: usize,
149    /// Program counter, stores the address of the next instruction to be
150    /// executed.
151    pub pc: usize,
152    /// Machine status register, holds the current status of the processor,
153    /// including interrupt enable bits and privilege mode.
154    pub mstatus: usize,
155    /// Machine cause register, contains the reason for the trap (e.g.,
156    /// exception or interrupt number).
157    pub mcause: usize,
158    /// Machine trap value register, contains additional information about the
159    /// trap (e.g., faulting address).
160    pub mtval: usize,
161}
162
163/// Trap entry point rust (_start_trap_rust)
164///
165/// `scause`/`mcause` is read to determine the cause of the trap. XLEN-1 bit
166/// indicates if it's an interrupt or an exception. The result is examined and
167/// ExceptionHandler or one of the core interrupt handlers is called.
168///
169/// # Safety
170///
171/// This function should not be called directly by the user, and should instead
172/// be invoked by the runtime implicitly.
173#[link_section = ".trap.rust"]
174#[export_name = "_start_trap_rust"]
175pub unsafe extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
176    extern "C" {
177        fn ExceptionHandler(trap_frame: &TrapFrame);
178        fn DefaultHandler();
179    }
180
181    unsafe {
182        let cause = mcause::read();
183
184        if cause.is_exception() {
185            ExceptionHandler(&*trap_frame)
186        } else if cause.code() < __INTERRUPTS.len() {
187            let h = &__INTERRUPTS[cause.code()];
188            if h.reserved == 0 {
189                DefaultHandler();
190            } else {
191                (h.handler)();
192            }
193        } else {
194            DefaultHandler();
195        }
196    }
197}
198
199#[doc(hidden)]
200#[no_mangle]
201#[allow(unused_variables, non_snake_case)]
202pub fn DefaultExceptionHandler(trap_frame: &TrapFrame) -> ! {
203    loop {
204        // Prevent this from turning into a UDF instruction
205        // see rust-lang/rust#28728 for details
206        continue;
207    }
208}
209
210#[doc(hidden)]
211#[no_mangle]
212#[allow(unused_variables, non_snake_case)]
213pub fn DefaultInterruptHandler() {
214    loop {
215        // Prevent this from turning into a UDF instruction
216        // see rust-lang/rust#28728 for details
217        continue;
218    }
219}
220
221// Interrupts
222#[doc(hidden)]
223pub enum Interrupt {
224    UserSoft,
225    SupervisorSoft,
226    MachineSoft,
227    UserTimer,
228    SupervisorTimer,
229    MachineTimer,
230    UserExternal,
231    SupervisorExternal,
232    MachineExternal,
233}
234
235extern "C" {
236    fn UserSoft();
237    fn SupervisorSoft();
238    fn MachineSoft();
239    fn UserTimer();
240    fn SupervisorTimer();
241    fn MachineTimer();
242    fn UserExternal();
243    fn SupervisorExternal();
244    fn MachineExternal();
245}
246
247#[doc(hidden)]
248pub union Vector {
249    pub handler: unsafe extern "C" fn(),
250    pub reserved: usize,
251}
252
253#[doc(hidden)]
254#[no_mangle]
255pub static __INTERRUPTS: [Vector; 12] = [
256    Vector { handler: UserSoft },
257    Vector {
258        handler: SupervisorSoft,
259    },
260    Vector { reserved: 0 },
261    Vector {
262        handler: MachineSoft,
263    },
264    Vector { handler: UserTimer },
265    Vector {
266        handler: SupervisorTimer,
267    },
268    Vector { reserved: 0 },
269    Vector {
270        handler: MachineTimer,
271    },
272    Vector {
273        handler: UserExternal,
274    },
275    Vector {
276        handler: SupervisorExternal,
277    },
278    Vector { reserved: 0 },
279    Vector {
280        handler: MachineExternal,
281    },
282];
283
284#[doc(hidden)]
285#[no_mangle]
286#[rustfmt::skip]
287pub unsafe extern "Rust" fn default_post_init() {}
288
289/// Default implementation of `_setup_interrupts` that sets `mtvec`/`stvec` to a
290/// trap handler address.
291#[doc(hidden)]
292#[no_mangle]
293#[rustfmt::skip]
294pub unsafe extern "Rust" fn default_setup_interrupts() {
295    extern "C" {
296        fn _start_trap();
297    }
298
299    mtvec::write(_start_trap as usize, TrapMode::Direct);
300}
301
302/// Parse cfg attributes inside a global_asm call.
303macro_rules! cfg_global_asm {
304    {@inner, [$($x:tt)*], } => {
305        global_asm!{$($x)*}
306    };
307    (@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
308        #[cfg($meta)]
309        cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
310        #[cfg(not($meta))]
311        cfg_global_asm!{@inner, [$($x)*], $($rest)*}
312    };
313    {@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
314        cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
315    };
316    {$($asms:tt)*} => {
317        cfg_global_asm!{@inner, [], $($asms)*}
318    };
319}
320
321cfg_global_asm! {
322    r#"
323/*
324    Entry point of all programs (_start).
325
326    It initializes DWARF call frame information, the stack pointer, the
327    frame pointer (needed for closures to work in start_rust) and the global
328    pointer. Then it calls _start_rust.
329*/
330
331.section .init, "ax"
332.global _start
333
334_start:
335    /* Jump to the absolute address defined by the linker script. */
336    lui ra, %hi(_abs_start)
337    jr %lo(_abs_start)(ra)
338
339_abs_start:
340    .option norelax
341    .cfi_startproc
342    .cfi_undefined ra
343"#,
344#[cfg(feature = "has-mie-mip")]
345    r#"
346    csrw mie, 0
347    csrw mip, 0
348"#,
349    r#"
350    la a0, _bss_start
351    la a1, _bss_end
352    bge a0, a1, 2f
353    mv a3, x0
354    1:
355    sw a3, 0(a0)
356    addi a0, a0, 4
357    blt a0, a1, 1b
358    2:
359"#,
360#[cfg(feature = "rtc-ram")]
361    r#"
362    la a0, _rtc_fast_bss_start
363    la a1, _rtc_fast_bss_end
364    bge a0, a1, 2f
365    mv a3, x0
366    1:
367    sw a3, 0(a0)
368    addi a0, a0, 4
369    blt a0, a1, 1b
370    2:
371"#,
372    // Zero .rtc_fast.persistent iff the chip just powered on
373#[cfg(feature = "rtc-ram")]
374    r#"
375    mv a0, zero
376    call rtc_get_reset_reason
377    addi a1, zero, 1
378    bne a0, a1, 2f
379    la a0, _rtc_fast_persistent_start
380    la a1, _rtc_fast_persistent_end
381    bge a0, a1, 2f
382    mv a3, x0
383    1:
384    sw a3, 0(a0)
385    addi a0, a0, 4
386    blt a0, a1, 1b
387    2:
388"#,
389    r#"
390    li  x1, 0
391    li  x2, 0
392    li  x3, 0
393    li  x4, 0
394    li  x5, 0
395    li  x6, 0
396    li  x7, 0
397    li  x8, 0
398    li  x9, 0
399    li  x10,0
400    li  x11,0
401    li  x12,0
402    li  x13,0
403    li  x14,0
404    li  x15,0
405    li  x16,0
406    li  x17,0
407    li  x18,0
408    li  x19,0
409    li  x20,0
410    li  x21,0
411    li  x22,0
412    li  x23,0
413    li  x24,0
414    li  x25,0
415    li  x26,0
416    li  x27,0
417    li  x28,0
418    li  x29,0
419    li  x30,0
420    li  x31,0
421
422    .option push
423    .option norelax
424    la gp, __global_pointer$
425    .option pop
426
427    // Check hart ID
428    csrr t2, mhartid
429    lui t0, %hi(_max_hart_id)
430    add t0, t0, %lo(_max_hart_id)
431    bgtu t2, t0, abort
432
433    // Allocate stack
434    la sp, _stack_start
435    li t0, 4 // make sure stack start is in RAM
436    sub sp, sp, t0
437    andi sp, sp, -16 // Force 16-byte alignment
438
439    // Set frame pointer
440    add s0, sp, zero
441
442    jal zero, _start_rust
443
444    .cfi_endproc
445
446/*
447    Trap entry points (_start_trap, _start_trapN for N in 1..=31)
448
449    The default implementation saves all registers to the stack and calls
450    _start_trap_rust, then restores all saved registers before `mret`
451*/
452.section .trap, "ax"
453.weak _start_trap  /* Exceptions call into _start_trap in vectored mode */
454.weak _start_trap1
455.weak _start_trap2
456.weak _start_trap3
457.weak _start_trap4
458.weak _start_trap5
459.weak _start_trap6
460.weak _start_trap7
461.weak _start_trap8
462.weak _start_trap9
463.weak _start_trap10
464.weak _start_trap11
465.weak _start_trap12
466.weak _start_trap13
467.weak _start_trap14
468.weak _start_trap15
469.weak _start_trap16
470.weak _start_trap17
471.weak _start_trap18
472.weak _start_trap19
473.weak _start_trap20
474.weak _start_trap21
475.weak _start_trap22
476.weak _start_trap23
477.weak _start_trap24
478.weak _start_trap25
479.weak _start_trap26
480.weak _start_trap27
481.weak _start_trap28
482.weak _start_trap29
483.weak _start_trap30
484.weak _start_trap31
485"#,
486r#"
487_start_trap: // Handle exceptions in vectored mode
488    // move SP to some save place if it's pointing below the RAM
489    // otherwise we won't be able to do anything reasonable
490    // (since we don't have a working stack)
491    //
492    // most probably we will just print something and halt in this case
493    // we actually can't do anything else
494    csrw mscratch, t0
495    la t0, _dram_origin
496    bge sp, t0, 1f
497
498    // use the reserved exception cause 14 to signal we detected a stack overflow
499    li t0, 14
500    csrw mcause, t0
501
502    // set SP to the start of the stack
503    la sp, _stack_start
504    li t0, 4 // make sure stack start is in RAM
505    sub sp, sp, t0
506    andi sp, sp, -16 // Force 16-byte alignment
507
508    1:
509    csrr t0, mscratch
510    // now SP is in RAM - continue
511
512    addi sp, sp, -40*4
513    sw ra, 0(sp)
514    la ra, _start_trap_rust_hal /* Load the HAL trap handler */
515    j _start_trap_direct
516_start_trap1:
517    addi sp, sp, -40*4
518    sw ra, 0(sp)
519    la ra, interrupt1
520    j _start_trap_direct
521_start_trap2:
522    addi sp, sp, -40*4
523    sw ra, 0(sp)
524    la ra, interrupt2
525    j _start_trap_direct
526_start_trap3:
527    addi sp, sp, -40*4
528    sw ra, 0(sp)
529    la ra, interrupt3
530    j _start_trap_direct
531_start_trap4:
532    addi sp, sp, -40*4
533    sw ra, 0(sp)
534    la ra, interrupt4
535    j _start_trap_direct
536_start_trap5:
537    addi sp, sp, -40*4
538    sw ra, 0(sp)
539    la ra, interrupt5
540    j _start_trap_direct
541_start_trap6:
542    addi sp, sp, -40*4
543    sw ra, 0(sp)
544    la ra, interrupt6
545    j _start_trap_direct
546_start_trap7:
547    addi sp, sp, -40*4
548    sw ra, 0(sp)
549    la ra, interrupt7
550    j _start_trap_direct
551_start_trap8:
552    addi sp, sp, -40*4
553    sw ra, 0(sp)
554    la ra, interrupt8
555    j _start_trap_direct
556_start_trap9:
557    addi sp, sp, -40*4
558    sw ra, 0(sp)
559    la ra, interrupt9
560    j _start_trap_direct
561_start_trap10:
562    addi sp, sp, -40*4
563    sw ra, 0(sp)
564    la ra, interrupt10
565    j _start_trap_direct
566_start_trap11:
567    addi sp, sp, -40*4
568    sw ra, 0(sp)
569    la ra, interrupt11
570    j _start_trap_direct
571_start_trap12:
572    addi sp, sp, -40*4
573    sw ra, 0(sp)
574    la ra, interrupt12
575    j _start_trap_direct
576_start_trap13:
577    addi sp, sp, -40*4
578    sw ra, 0(sp)
579    la ra, interrupt13
580    j _start_trap_direct
581_start_trap14:
582    addi sp, sp, -40*4
583    sw ra, 0(sp)
584    la ra, interrupt14
585    j _start_trap_direct
586_start_trap15:
587    addi sp, sp, -40*4
588    sw ra, 0(sp)
589    la ra, interrupt15
590    j _start_trap_direct
591_start_trap16:
592    addi sp, sp, -40*4
593    sw ra, 0(sp)
594    la ra, interrupt16
595    j _start_trap_direct
596_start_trap17:
597    addi sp, sp, -40*4
598    sw ra, 0(sp)
599    la ra, interrupt17
600    j _start_trap_direct
601_start_trap18:
602    addi sp, sp, -40*4
603    sw ra, 0(sp)
604    la ra, interrupt18
605    j _start_trap_direct
606_start_trap19:
607    addi sp, sp, -40*4
608    sw ra, 0(sp)
609    la ra, interrupt19
610    j _start_trap_direct
611_start_trap20:
612    addi sp, sp, -40*4
613    sw ra, 0(sp)
614    la ra, interrupt20
615    j _start_trap_direct
616_start_trap21:
617    addi sp, sp, -40*4
618    sw ra, 0(sp)
619    la ra, interrupt21
620    j _start_trap_direct
621_start_trap22:
622    addi sp, sp, -40*4
623    sw ra, 0(sp)
624    la ra, interrupt22
625    j _start_trap_direct
626_start_trap23:
627    addi sp, sp, -40*4
628    sw ra, 0(sp)
629    la ra, interrupt23
630    j _start_trap_direct
631_start_trap24:
632    addi sp, sp, -40*4
633    sw ra, 0(sp)
634    la ra, interrupt24
635    j _start_trap_direct
636_start_trap25:
637    addi sp, sp, -40*4
638    sw ra, 0(sp)
639    la ra, interrupt25
640    j _start_trap_direct
641_start_trap26:
642    addi sp, sp, -40*4
643    sw ra, 0(sp)
644    la ra, interrupt26
645    j _start_trap_direct
646_start_trap27:
647    addi sp, sp, -40*4
648    sw ra, 0(sp)
649    la ra, interrupt27
650    j _start_trap_direct
651_start_trap28:
652    addi sp, sp, -40*4
653    sw ra, 0(sp)
654    la ra, interrupt28
655    j _start_trap_direct
656_start_trap29:
657    addi sp, sp, -40*4
658    sw ra, 0(sp)
659    la ra, interrupt29
660    j _start_trap_direct
661_start_trap30:
662    addi sp, sp, -40*4
663    sw ra, 0(sp)
664    la ra, interrupt30
665    j _start_trap_direct
666_start_trap31:
667    addi sp, sp, -40*4
668    sw ra, 0(sp)
669    la ra, interrupt31
670    j _start_trap_direct
671la ra, _start_trap_rust_hal /* this runs on exception, use regular fault handler */
672_start_trap_direct:
673"#,
674r#"
675    sw t0, 1*4(sp)
676    sw t1, 2*4(sp)
677    sw t2, 3*4(sp)
678    sw t3, 4*4(sp)
679    sw t4, 5*4(sp)
680    sw t5, 6*4(sp)
681    sw t6, 7*4(sp)
682    sw a0, 8*4(sp)
683    sw a1, 9*4(sp)
684    sw a2, 10*4(sp)
685    sw a3, 11*4(sp)
686    sw a4, 12*4(sp)
687    sw a5, 13*4(sp)
688    sw a6, 14*4(sp)
689    sw a7, 15*4(sp)
690    sw s0, 16*4(sp)
691    sw s1, 17*4(sp)
692    sw s2, 18*4(sp)
693    sw s3, 19*4(sp)
694    sw s4, 20*4(sp)
695    sw s5, 21*4(sp)
696    sw s6, 22*4(sp)
697    sw s7, 23*4(sp)
698    sw s8, 24*4(sp)
699    sw s9, 25*4(sp)
700    sw s10, 26*4(sp)
701    sw s11, 27*4(sp)
702    sw gp, 28*4(sp)
703    sw tp, 29*4(sp)
704    csrrs t1, mepc, x0
705    sw t1, 31*4(sp)
706    csrrs t1, mstatus, x0
707    sw t1, 32*4(sp)
708    csrrs t1, mcause, x0
709    sw t1, 33*4(sp)
710    csrrs t1, mtval, x0
711    sw t1, 34*4(sp)
712
713    addi s0, sp, 40*4
714    sw s0, 30*4(sp)
715
716    add a0, sp, zero
717    "#,
718    // store current priority, set threshold, enable interrupts
719    r#"
720    addi sp, sp, -16 #build stack
721    sw ra, 0(sp)
722    jal ra, _handle_priority
723    lw ra, 0(sp)
724    sw a0, 0(sp) #reuse old stack, a0 is return of _handle_priority
725    addi a0, sp, 16 #the proper stack pointer is an argument to the HAL handler
726    "#,
727    // jump to handler loaded in direct handler
728    r#"
729    jalr ra, ra #jump to label loaded in _start_trapx
730    "#,
731    // restore threshold
732    r#"
733    lw a0, 0(sp) #load stored priority
734    jal ra, _restore_priority
735    addi sp, sp, 16 #pop
736    "#,
737    r#"
738    lw t1, 31*4(sp)
739    csrrw x0, mepc, t1
740
741    lw t1, 32*4(sp)
742    csrrw x0, mstatus, t1
743
744    lw ra, 0*4(sp)
745    lw t0, 1*4(sp)
746    lw t1, 2*4(sp)
747    lw t2, 3*4(sp)
748    lw t3, 4*4(sp)
749    lw t4, 5*4(sp)
750    lw t5, 6*4(sp)
751    lw t6, 7*4(sp)
752    lw a0, 8*4(sp)
753    lw a1, 9*4(sp)
754    lw a2, 10*4(sp)
755    lw a3, 11*4(sp)
756    lw a4, 12*4(sp)
757    lw a5, 13*4(sp)
758    lw a6, 14*4(sp)
759    lw a7, 15*4(sp)
760    lw s0, 16*4(sp)
761    lw s1, 17*4(sp)
762    lw s2, 18*4(sp)
763    lw s3, 19*4(sp)
764    lw s4, 20*4(sp)
765    lw s5, 21*4(sp)
766    lw s6, 22*4(sp)
767    lw s7, 23*4(sp)
768    lw s8, 24*4(sp)
769    lw s9, 25*4(sp)
770    lw s10, 26*4(sp)
771    lw s11, 27*4(sp)
772    lw gp, 28*4(sp)
773    lw tp, 29*4(sp)
774    lw sp, 30*4(sp)
775
776    # SP was restored from the original SP
777    mret
778
779/* Make sure there is an abort when linking */
780.section .text.abort
781.globl abort
782abort:
783    j abort
784
785/*
786    Interrupt vector table (_vector_table)
787*/
788
789.section .trap, "ax"
790.weak _vector_table
791.type _vector_table, @function
792
793.option push
794.balign 0x100
795.option norelax
796.option norvc
797
798_vector_table:
799    j _start_trap
800    j _start_trap1
801    j _start_trap2
802    j _start_trap3
803    j _start_trap4
804    j _start_trap5
805    j _start_trap6
806    j _start_trap7
807    j _start_trap8
808    j _start_trap9
809    j _start_trap10
810    j _start_trap11
811    j _start_trap12
812    j _start_trap13
813    j _start_trap14
814    j _start_trap15
815    j _start_trap16
816    j _start_trap17
817    j _start_trap18
818    j _start_trap19
819    j _start_trap20
820    j _start_trap21
821    j _start_trap22
822    j _start_trap23
823    j _start_trap24
824    j _start_trap25
825    j _start_trap26
826    j _start_trap27
827    j _start_trap28
828    j _start_trap29
829    j _start_trap30
830    j _start_trap31
831.option pop
832"#,
833r#"
834#this is required for the linking step, these symbols for in-use interrupts should always be overwritten by the user.
835.section .trap, "ax"
836// See https://github.com/esp-rs/esp-hal/issues/1326 and https://reviews.llvm.org/D98762
837// and yes, this all has to go on one line... *sigh*.
838.lto_discard interrupt1, interrupt2, interrupt3, interrupt4, interrupt5, interrupt6, interrupt7, interrupt8, interrupt9, interrupt10, interrupt11, interrupt12, interrupt13, interrupt14, interrupt15, interrupt16, interrupt17, interrupt18, interrupt19, interrupt20, interrupt21, interrupt22, interrupt23, interrupt24, interrupt25, interrupt26, interrupt27, interrupt28, interrupt29, interrupt30, interrupt31
839.weak interrupt1
840.weak interrupt2
841.weak interrupt3
842.weak interrupt4
843.weak interrupt5
844.weak interrupt6
845.weak interrupt7
846.weak interrupt8
847.weak interrupt9
848.weak interrupt10
849.weak interrupt11
850.weak interrupt12
851.weak interrupt13
852.weak interrupt14
853.weak interrupt15
854.weak interrupt16
855.weak interrupt17
856.weak interrupt18
857.weak interrupt19
858.weak interrupt20
859.weak interrupt21
860.weak interrupt22
861.weak interrupt23
862.weak interrupt24
863.weak interrupt25
864.weak interrupt26
865.weak interrupt27
866.weak interrupt28
867.weak interrupt29
868.weak interrupt30
869.weak interrupt31
870"#,
871}