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 by features
8//! - `#[entry]` to declare the entry point of the program
9//!
10//! ## Feature Flags
11#![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;
19pub use riscv_rt::{TrapFrame, entry};
20
21#[doc(hidden)]
22#[unsafe(no_mangle)]
23pub unsafe extern "C" fn _dispatch_exception(trap_frame: &TrapFrame, _code: usize) {
24    unsafe extern "C" {
25        fn _start_trap_rust_hal(trap_frame: &TrapFrame);
26    }
27
28    unsafe {
29        _start_trap_rust_hal(trap_frame);
30    }
31}
32
33/// Parse cfg attributes inside a global_asm call.
34macro_rules! cfg_global_asm {
35    {@inner, [$($x:tt)*], } => {
36        global_asm!{$($x)*}
37    };
38    (@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
39        #[cfg($meta)]
40        cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
41        #[cfg(not($meta))]
42        cfg_global_asm!{@inner, [$($x)*], $($rest)*}
43    };
44    {@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
45        cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
46    };
47    {$($asms:tt)*} => {
48        cfg_global_asm!{@inner, [], $($asms)*}
49    };
50}
51
52cfg_global_asm! {
53    r#"
54.section .init, "ax"
55.weak __pre_init
56__pre_init:"#,
57    // Zero .rtc_fast.bss
58#[cfg(feature = "rtc-ram")]
59    r#"
60    la a0, _rtc_fast_bss_start
61    la a1, _rtc_fast_bss_end
62    bge a0, a1, 2f
63    mv a3, x0
64    1:
65    sw a3, 0(a0)
66    addi a0, a0, 4
67    blt a0, a1, 1b
68    2:
69"#,
70     // Zero .rtc_fast.persistent if the chip just powered on
71 #[cfg(feature = "rtc-ram")]
72    r#"
73    mv a0, zero
74    mv t0, ra
75    call rtc_get_reset_reason
76    mv ra, t0
77    addi a1, zero, 1
78    bne a0, a1, 2f
79    la a0, _rtc_fast_persistent_start
80    la a1, _rtc_fast_persistent_end
81    bge a0, a1, 2f
82    mv a3, x0
83    1:
84    sw a3, 0(a0)
85    addi a0, a0, 4
86    blt a0, a1, 1b
87    2:
88"#,
89r#"
90    ret
91
92/*
93    Move SP to a valid memory region if needed.
94*/
95
96.section .trap.start, "ax"
97.extern _pre_default_start_trap_ret
98.global _pre_default_start_trap
99_pre_default_start_trap:
100    // move SP to some safe place if it's pointing below the RAM
101    // or into .trap / .rwtext.
102    //
103    // Otherwise we won't be able to do anything reasonable
104    // (since we don't have a working stack)
105    //
106    // most probably we will just print something and halt in this case
107    // we actually can't do anything else
108    csrw mscratch, t0
109    la t0, _dram_data_start
110    bge sp, t0, 1f
111
112    // use the reserved exception cause 14 to signal we detected a stack overflow
113    li t0, 14
114    csrw mcause, t0
115
116    // set SP to the start of the stack
117    la sp, _stack_start
118    li t0, 4 // make sure stack start is in RAM
119    sub sp, sp, t0
120    andi sp, sp, -16 // Force 16-byte alignment
121
122    1:
123    csrr t0, mscratch
124
125    j _pre_default_start_trap_ret
126
127/*
128    Interrupt vector table (_vector_table)
129*/
130
131.section .trap, "ax"
132.weak _vector_table
133.type _vector_table, @function
134
135.option push
136.balign 0x100
137.option norelax
138.option norvc
139
140_vector_table:
141    j _start_trap
142    j _start_Trap1_trap
143    j _start_Trap2_trap
144    j _start_Trap3_trap
145    j _start_Trap4_trap
146    j _start_Trap5_trap
147    j _start_Trap6_trap
148    j _start_Trap7_trap
149    j _start_Trap8_trap
150    j _start_Trap9_trap
151    j _start_Trap10_trap
152    j _start_Trap11_trap
153    j _start_Trap12_trap
154    j _start_Trap13_trap
155    j _start_Trap14_trap
156    j _start_Trap15_trap
157    j _start_Trap16_trap
158    j _start_Trap17_trap
159    j _start_Trap18_trap
160    j _start_Trap19_trap
161    j _start_Trap20_trap
162    j _start_Trap21_trap
163    j _start_Trap22_trap
164    j _start_Trap23_trap
165    j _start_Trap24_trap
166    j _start_Trap25_trap
167    j _start_Trap26_trap
168    j _start_Trap27_trap
169    j _start_Trap28_trap
170    j _start_Trap29_trap
171    j _start_Trap30_trap
172    j _start_Trap31_trap
173.option pop
174"#,
175}
176
177macro_rules! define_interrupt {
178    ($num:literal, $name:ident, $fname:ident) => {
179        #[derive(Copy, Clone)]
180        struct $name;
181
182        unsafe impl riscv_rt::InterruptNumber for $name {
183            const MAX_INTERRUPT_NUMBER: usize = 31;
184
185            fn number(self) -> usize {
186                $num
187            }
188
189            fn from_number(_value: usize) -> riscv_rt::result::Result<Self> {
190                Ok($name)
191            }
192        }
193
194        unsafe impl riscv_rt::CoreInterruptNumber for $name {}
195
196        #[unsafe(naked)]
197        #[unsafe(link_section = ".trap.start")]
198        #[riscv_rt::core_interrupt($name)]
199        extern "C" fn $fname() {
200            core::arch::naked_asm! {
201                concat!(
202                "
203                li a0,",$num,"
204                j handle_interrupts
205                "
206                )
207            }
208        }
209    };
210}
211
212define_interrupt!(1, Trap1, trap1);
213define_interrupt!(2, Trap2, trap2);
214define_interrupt!(3, Trap3, trap3);
215define_interrupt!(4, Trap4, trap4);
216define_interrupt!(5, Trap5, trap5);
217define_interrupt!(6, Trap6, trap6);
218define_interrupt!(7, Trap7, trap7);
219define_interrupt!(8, Trap8, trap8);
220define_interrupt!(9, Trap9, trap9);
221define_interrupt!(10, Trap10, trap10);
222define_interrupt!(11, Trap11, trap11);
223define_interrupt!(12, Trap12, trap12);
224define_interrupt!(13, Trap13, trap13);
225define_interrupt!(14, Trap14, trap14);
226define_interrupt!(15, Trap15, trap15);
227define_interrupt!(16, Trap16, trap16);
228define_interrupt!(17, Trap17, trap17);
229define_interrupt!(18, Trap18, trap18);
230define_interrupt!(19, Trap19, trap19);
231define_interrupt!(20, Trap20, trap20);
232define_interrupt!(21, Trap21, trap21);
233define_interrupt!(22, Trap22, trap22);
234define_interrupt!(23, Trap23, trap23);
235define_interrupt!(24, Trap24, trap24);
236define_interrupt!(25, Trap25, trap25);
237define_interrupt!(26, Trap26, trap26);
238define_interrupt!(27, Trap27, trap27);
239define_interrupt!(28, Trap28, trap28);
240define_interrupt!(29, Trap29, trap29);
241define_interrupt!(30, Trap30, trap30);
242define_interrupt!(31, Trap31, trap31);