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#[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 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#[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#[derive(Debug, Default, Clone, Copy)]
77#[repr(C)]
78pub struct TrapFrame {
79 pub ra: usize,
82 pub t0: usize,
84 pub t1: usize,
86 pub t2: usize,
88 pub t3: usize,
90 pub t4: usize,
92 pub t5: usize,
94 pub t6: usize,
96 pub a0: usize,
99 pub a1: usize,
102 pub a2: usize,
105 pub a3: usize,
108 pub a4: usize,
111 pub a5: usize,
114 pub a6: usize,
117 pub a7: usize,
120 pub s0: usize,
122 pub s1: usize,
124 pub s2: usize,
126 pub s3: usize,
128 pub s4: usize,
130 pub s5: usize,
132 pub s6: usize,
134 pub s7: usize,
136 pub s8: usize,
138 pub s9: usize,
140 pub s10: usize,
142 pub s11: usize,
144 pub gp: usize,
146 pub tp: usize,
149 pub sp: usize,
151 pub pc: usize,
154 pub mstatus: usize,
157 pub mcause: usize,
160 pub mtval: usize,
163}
164
165#[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 continue;
209 }
210}
211
212#[doc(hidden)]
213#[unsafe(no_mangle)]
214#[allow(unused_variables, non_snake_case)]
215pub fn DefaultInterruptHandler() {
216 loop {
217 continue;
220 }
221}
222
223#[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#[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
304macro_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 #[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 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 r#"
731 jalr ra, ra #jump to label loaded in _start_trapx
732 "#,
733 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}