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