1#![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 static mut _bss_end: u32;
35 static mut _bss_start: u32;
36
37 static mut _data_end: u32;
39 static mut _data_start: u32;
40
41 static _sidata: u32;
43}
44
45#[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#[derive(Debug, Default, Clone, Copy)]
75#[repr(C)]
76pub struct TrapFrame {
77 pub ra: usize,
80 pub t0: usize,
82 pub t1: usize,
84 pub t2: usize,
86 pub t3: usize,
88 pub t4: usize,
90 pub t5: usize,
92 pub t6: usize,
94 pub a0: usize,
97 pub a1: usize,
100 pub a2: usize,
103 pub a3: usize,
106 pub a4: usize,
109 pub a5: usize,
112 pub a6: usize,
115 pub a7: usize,
118 pub s0: usize,
120 pub s1: usize,
122 pub s2: usize,
124 pub s3: usize,
126 pub s4: usize,
128 pub s5: usize,
130 pub s6: usize,
132 pub s7: usize,
134 pub s8: usize,
136 pub s9: usize,
138 pub s10: usize,
140 pub s11: usize,
142 pub gp: usize,
144 pub tp: usize,
147 pub sp: usize,
149 pub pc: usize,
152 pub mstatus: usize,
155 pub mcause: usize,
158 pub mtval: usize,
161}
162
163#[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 continue;
207 }
208}
209
210#[doc(hidden)]
211#[no_mangle]
212#[allow(unused_variables, non_snake_case)]
213pub fn DefaultInterruptHandler() {
214 loop {
215 continue;
218 }
219}
220
221#[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#[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
302macro_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 #[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 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 r#"
729 jalr ra, ra #jump to label loaded in _start_trapx
730 "#,
731 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}