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