Skip to main content

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!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
12#![doc(html_logo_url = "https://docs.espressif.com/projects/rust/esp-rs-grey-bg.svg")]
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"#,
89    // Zero .dram2_uninit.bss
90    r#"
91    la a0, _dram2_uninit_bss_start
92    la a1, _dram2_uninit_bss_end
93    bge a0, a1, 2f
94    mv a3, x0
95    1:
96    sw a3, 0(a0)
97    addi a0, a0, 4
98    blt a0, a1, 1b
99    2:
100"#,
101r#"
102    ret
103
104/*
105    Move SP to a valid memory region if needed.
106*/
107
108.section .trap.start, "ax"
109.extern _pre_default_start_trap_ret
110.global _pre_default_start_trap
111_pre_default_start_trap:
112    // move SP to some safe place if it's pointing below the RAM
113    // or into .trap / .rwtext.
114    //
115    // Otherwise we won't be able to do anything reasonable
116    // (since we don't have a working stack)
117    //
118    // most probably we will just print something and halt in this case
119    // we actually can't do anything else
120    csrw mscratch, t0
121    la t0, _dram_data_start
122    bge sp, t0, 1f
123
124    // use the reserved exception cause 14 to signal we detected a stack overflow
125    li t0, 14
126    csrw mcause, t0
127
128    // set SP to the start of the stack
129    la sp, _stack_start
130    li t0, 4 // make sure stack start is in RAM
131    sub sp, sp, t0
132    andi sp, sp, -16 // Force 16-byte alignment
133
134    1:
135    csrr t0, mscratch
136
137    j _pre_default_start_trap_ret
138
139/*
140    Interrupt vector table (_vector_table)
141*/
142
143.section .trap, "ax"
144.weak _vector_table
145.type _vector_table, @function
146
147.option push
148.balign 0x100
149.option norelax
150.option norvc
151
152_vector_table:
153    j _start_trap
154    j _start_Trap1_trap
155    j _start_Trap2_trap
156    j _start_Trap3_trap
157    j _start_Trap4_trap
158    j _start_Trap5_trap
159    j _start_Trap6_trap
160    j _start_Trap7_trap
161    j _start_Trap8_trap
162    j _start_Trap9_trap
163    j _start_Trap10_trap
164    j _start_Trap11_trap
165    j _start_Trap12_trap
166    j _start_Trap13_trap
167    j _start_Trap14_trap
168    j _start_Trap15_trap
169    j _start_Trap16_trap
170    j _start_Trap17_trap
171    j _start_Trap18_trap
172    j _start_Trap19_trap
173    j _start_Trap20_trap
174    j _start_Trap21_trap
175    j _start_Trap22_trap
176    j _start_Trap23_trap
177    j _start_Trap24_trap
178    j _start_Trap25_trap
179    j _start_Trap26_trap
180    j _start_Trap27_trap
181    j _start_Trap28_trap
182    j _start_Trap29_trap
183    j _start_Trap30_trap
184    j _start_Trap31_trap
185"#,
186 #[cfg(feature = "clic-48")]
187r#"
188    j _start_Trap32_trap
189    j _start_Trap33_trap
190    j _start_Trap34_trap
191    j _start_Trap35_trap
192    j _start_Trap36_trap
193    j _start_Trap37_trap
194    j _start_Trap38_trap
195    j _start_Trap39_trap
196    j _start_Trap40_trap
197    j _start_Trap41_trap
198    j _start_Trap42_trap
199    j _start_Trap43_trap
200    j _start_Trap44_trap
201    j _start_Trap45_trap
202    j _start_Trap46_trap
203    j _start_Trap47_trap
204"#,
205r#"
206    .option pop
207"#,
208}
209
210macro_rules! define_interrupt {
211    ($num:literal, $name:ident, $fname:ident) => {
212        #[derive(Copy, Clone)]
213        struct $name;
214
215        unsafe impl riscv_rt::InterruptNumber for $name {
216            const MAX_INTERRUPT_NUMBER: usize = if cfg!(feature = "clic-48") { 47 } else { 31 };
217
218            fn number(self) -> usize {
219                $num
220            }
221
222            fn from_number(_value: usize) -> riscv_rt::result::Result<Self> {
223                Ok($name)
224            }
225        }
226
227        unsafe impl riscv_rt::CoreInterruptNumber for $name {}
228
229        #[unsafe(naked)]
230        #[unsafe(link_section = ".trap.start")]
231        #[riscv_rt::core_interrupt($name)]
232        extern "C" fn $fname() {
233            core::arch::naked_asm! {
234                concat!(
235                "
236                li a0,",$num,"
237                j handle_interrupts
238                "
239                )
240            }
241        }
242    };
243}
244
245define_interrupt!(1, Trap1, trap1);
246define_interrupt!(2, Trap2, trap2);
247define_interrupt!(3, Trap3, trap3);
248define_interrupt!(4, Trap4, trap4);
249define_interrupt!(5, Trap5, trap5);
250define_interrupt!(6, Trap6, trap6);
251define_interrupt!(7, Trap7, trap7);
252define_interrupt!(8, Trap8, trap8);
253define_interrupt!(9, Trap9, trap9);
254define_interrupt!(10, Trap10, trap10);
255define_interrupt!(11, Trap11, trap11);
256define_interrupt!(12, Trap12, trap12);
257define_interrupt!(13, Trap13, trap13);
258define_interrupt!(14, Trap14, trap14);
259define_interrupt!(15, Trap15, trap15);
260define_interrupt!(16, Trap16, trap16);
261define_interrupt!(17, Trap17, trap17);
262define_interrupt!(18, Trap18, trap18);
263define_interrupt!(19, Trap19, trap19);
264define_interrupt!(20, Trap20, trap20);
265define_interrupt!(21, Trap21, trap21);
266define_interrupt!(22, Trap22, trap22);
267define_interrupt!(23, Trap23, trap23);
268define_interrupt!(24, Trap24, trap24);
269define_interrupt!(25, Trap25, trap25);
270define_interrupt!(26, Trap26, trap26);
271define_interrupt!(27, Trap27, trap27);
272define_interrupt!(28, Trap28, trap28);
273define_interrupt!(29, Trap29, trap29);
274define_interrupt!(30, Trap30, trap30);
275define_interrupt!(31, Trap31, trap31);
276
277#[cfg(feature = "clic-48")]
278mod clic {
279    define_interrupt!(32, Trap32, trap32);
280    define_interrupt!(33, Trap33, trap33);
281    define_interrupt!(34, Trap34, trap34);
282    define_interrupt!(35, Trap35, trap35);
283    define_interrupt!(36, Trap36, trap36);
284    define_interrupt!(37, Trap37, trap37);
285    define_interrupt!(38, Trap38, trap38);
286    define_interrupt!(39, Trap39, trap39);
287    define_interrupt!(40, Trap40, trap40);
288    define_interrupt!(41, Trap41, trap41);
289    define_interrupt!(42, Trap42, trap42);
290    define_interrupt!(43, Trap43, trap43);
291    define_interrupt!(44, Trap44, trap44);
292    define_interrupt!(45, Trap45, trap45);
293    define_interrupt!(46, Trap46, trap46);
294    define_interrupt!(47, Trap47, trap47);
295}