916 lines
19 KiB
Rust
916 lines
19 KiB
Rust
//! Minimal startup / runtime for RISC-V CPUs from Espressif
|
|
//!
|
|
//! # Minimum Supported Rust Version (MSRV)
|
|
//!
|
|
//! This crate is guaranteed to compile on stable Rust 1.60 and up. It *might*
|
|
//! compile with older versions but that may change in any new patch release.
|
|
//!
|
|
//! # Features
|
|
//!
|
|
//! This crate provides:
|
|
//!
|
|
//! - Before main initialization of the `.bss` and `.data` sections controlled
|
|
//! by features
|
|
//! - `#[entry]` to declare the entry point of the program
|
|
|
|
// NOTE: Adapted from riscv-rt/src/lib.rs
|
|
#![no_std]
|
|
|
|
use core::arch::global_asm;
|
|
|
|
pub use riscv;
|
|
use riscv::register::{
|
|
mcause,
|
|
mtvec::{self, TrapMode},
|
|
};
|
|
pub use riscv_rt_macros::{entry, pre_init};
|
|
|
|
pub use self::Interrupt as interrupt;
|
|
|
|
#[export_name = "error: esp-riscv-rt appears more than once in the dependency graph"]
|
|
#[doc(hidden)]
|
|
pub static __ONCE__: () = ();
|
|
|
|
extern "C" {
|
|
// Boundaries of the .bss section
|
|
static mut _bss_end: u32;
|
|
static mut _bss_start: u32;
|
|
|
|
// Boundaries of the .data section
|
|
static mut _data_end: u32;
|
|
static mut _data_start: u32;
|
|
|
|
// Initial values of the .data section (stored in Flash)
|
|
static _sidata: u32;
|
|
}
|
|
|
|
/// Rust entry point (_start_rust)
|
|
///
|
|
/// Zeros bss section, initializes data section and calls main. This function
|
|
/// never returns.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This function should not be called directly by the user, and should instead
|
|
/// be invoked by the runtime implicitly.
|
|
#[link_section = ".init.rust"]
|
|
#[export_name = "_start_rust"]
|
|
pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
|
|
extern "Rust" {
|
|
// This symbol will be provided by the user via `#[entry]`
|
|
fn main(a0: usize, a1: usize, a2: usize) -> !;
|
|
|
|
fn __post_init();
|
|
|
|
fn _setup_interrupts();
|
|
|
|
}
|
|
|
|
__post_init();
|
|
|
|
_setup_interrupts();
|
|
|
|
main(a0, a1, a2);
|
|
}
|
|
|
|
/// Registers saved in trap handler
|
|
#[allow(missing_docs)]
|
|
#[derive(Debug, Default, Clone, Copy)]
|
|
#[repr(C)]
|
|
pub struct TrapFrame {
|
|
pub ra: usize,
|
|
pub t0: usize,
|
|
pub t1: usize,
|
|
pub t2: usize,
|
|
pub t3: usize,
|
|
pub t4: usize,
|
|
pub t5: usize,
|
|
pub t6: usize,
|
|
pub a0: usize,
|
|
pub a1: usize,
|
|
pub a2: usize,
|
|
pub a3: usize,
|
|
pub a4: usize,
|
|
pub a5: usize,
|
|
pub a6: usize,
|
|
pub a7: usize,
|
|
pub s0: usize,
|
|
pub s1: usize,
|
|
pub s2: usize,
|
|
pub s3: usize,
|
|
pub s4: usize,
|
|
pub s5: usize,
|
|
pub s6: usize,
|
|
pub s7: usize,
|
|
pub s8: usize,
|
|
pub s9: usize,
|
|
pub s10: usize,
|
|
pub s11: usize,
|
|
pub gp: usize,
|
|
pub tp: usize,
|
|
pub sp: usize,
|
|
pub pc: usize,
|
|
pub mstatus: usize,
|
|
pub mcause: usize,
|
|
pub mtval: usize,
|
|
}
|
|
|
|
/// Trap entry point rust (_start_trap_rust)
|
|
///
|
|
/// `scause`/`mcause` is read to determine the cause of the trap. XLEN-1 bit
|
|
/// indicates if it's an interrupt or an exception. The result is examined and
|
|
/// ExceptionHandler or one of the core interrupt handlers is called.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This function should not be called directly by the user, and should instead
|
|
/// be invoked by the runtime implicitly.
|
|
#[link_section = ".trap.rust"]
|
|
#[export_name = "_start_trap_rust"]
|
|
pub unsafe extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
|
|
extern "C" {
|
|
fn ExceptionHandler(trap_frame: &TrapFrame);
|
|
fn DefaultHandler();
|
|
}
|
|
|
|
unsafe {
|
|
let cause = mcause::read();
|
|
|
|
if cause.is_exception() {
|
|
ExceptionHandler(&*trap_frame)
|
|
} else if cause.code() < __INTERRUPTS.len() {
|
|
let h = &__INTERRUPTS[cause.code()];
|
|
if h.reserved == 0 {
|
|
DefaultHandler();
|
|
} else {
|
|
(h.handler)();
|
|
}
|
|
} else {
|
|
DefaultHandler();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
#[no_mangle]
|
|
#[allow(unused_variables, non_snake_case)]
|
|
pub fn DefaultExceptionHandler(trap_frame: &TrapFrame) -> ! {
|
|
loop {
|
|
// Prevent this from turning into a UDF instruction
|
|
// see rust-lang/rust#28728 for details
|
|
continue;
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
#[no_mangle]
|
|
#[allow(unused_variables, non_snake_case)]
|
|
pub fn DefaultInterruptHandler() {
|
|
loop {
|
|
// Prevent this from turning into a UDF instruction
|
|
// see rust-lang/rust#28728 for details
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Interrupts
|
|
#[doc(hidden)]
|
|
pub enum Interrupt {
|
|
UserSoft,
|
|
SupervisorSoft,
|
|
MachineSoft,
|
|
UserTimer,
|
|
SupervisorTimer,
|
|
MachineTimer,
|
|
UserExternal,
|
|
SupervisorExternal,
|
|
MachineExternal,
|
|
}
|
|
|
|
extern "C" {
|
|
fn UserSoft();
|
|
fn SupervisorSoft();
|
|
fn MachineSoft();
|
|
fn UserTimer();
|
|
fn SupervisorTimer();
|
|
fn MachineTimer();
|
|
fn UserExternal();
|
|
fn SupervisorExternal();
|
|
fn MachineExternal();
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub union Vector {
|
|
pub handler: unsafe extern "C" fn(),
|
|
pub reserved: usize,
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
#[no_mangle]
|
|
pub static __INTERRUPTS: [Vector; 12] = [
|
|
Vector { handler: UserSoft },
|
|
Vector {
|
|
handler: SupervisorSoft,
|
|
},
|
|
Vector { reserved: 0 },
|
|
Vector {
|
|
handler: MachineSoft,
|
|
},
|
|
Vector { handler: UserTimer },
|
|
Vector {
|
|
handler: SupervisorTimer,
|
|
},
|
|
Vector { reserved: 0 },
|
|
Vector {
|
|
handler: MachineTimer,
|
|
},
|
|
Vector {
|
|
handler: UserExternal,
|
|
},
|
|
Vector {
|
|
handler: SupervisorExternal,
|
|
},
|
|
Vector { reserved: 0 },
|
|
Vector {
|
|
handler: MachineExternal,
|
|
},
|
|
];
|
|
|
|
#[doc(hidden)]
|
|
#[no_mangle]
|
|
#[rustfmt::skip]
|
|
pub unsafe extern "Rust" fn default_post_init() {}
|
|
|
|
/// Default implementation of `_setup_interrupts` that sets `mtvec`/`stvec` to a
|
|
/// trap handler address.
|
|
#[doc(hidden)]
|
|
#[no_mangle]
|
|
#[rustfmt::skip]
|
|
pub unsafe extern "Rust" fn default_setup_interrupts() {
|
|
extern "C" {
|
|
fn _start_trap();
|
|
}
|
|
|
|
mtvec::write(_start_trap as usize, TrapMode::Direct);
|
|
}
|
|
|
|
/// Parse cfg attributes inside a global_asm call.
|
|
macro_rules! cfg_global_asm {
|
|
{@inner, [$($x:tt)*], } => {
|
|
global_asm!{$($x)*}
|
|
};
|
|
(@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
|
|
#[cfg($meta)]
|
|
cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
|
|
#[cfg(not($meta))]
|
|
cfg_global_asm!{@inner, [$($x)*], $($rest)*}
|
|
};
|
|
{@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
|
|
cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
|
|
};
|
|
{$($asms:tt)*} => {
|
|
cfg_global_asm!{@inner, [], $($asms)*}
|
|
};
|
|
}
|
|
|
|
cfg_global_asm! {
|
|
r#"
|
|
/*
|
|
Entry point of all programs (_start).
|
|
|
|
It initializes DWARF call frame information, the stack pointer, the
|
|
frame pointer (needed for closures to work in start_rust) and the global
|
|
pointer. Then it calls _start_rust.
|
|
*/
|
|
|
|
.section .init, "ax"
|
|
.global _start
|
|
|
|
_start:
|
|
/* Jump to the absolute address defined by the linker script. */
|
|
lui ra, %hi(_abs_start)
|
|
jr %lo(_abs_start)(ra)
|
|
|
|
_abs_start:
|
|
.option norelax
|
|
.cfi_startproc
|
|
.cfi_undefined ra
|
|
"#,
|
|
#[cfg(feature = "has-mie-mip")]
|
|
r#"
|
|
csrw mie, 0
|
|
csrw mip, 0
|
|
"#,
|
|
#[cfg(feature = "zero-bss")]
|
|
r#"
|
|
la a0, _bss_start
|
|
la a1, _bss_end
|
|
bge a0, a1, 2f
|
|
mv a3, x0
|
|
1:
|
|
sw a3, 0(a0)
|
|
addi a0, a0, 4
|
|
blt a0, a1, 1b
|
|
2:
|
|
"#,
|
|
#[cfg(feature = "zero-rtc-fast-bss")]
|
|
r#"
|
|
la a0, _rtc_fast_bss_start
|
|
la a1, _rtc_fast_bss_end
|
|
bge a0, a1, 2f
|
|
mv a3, x0
|
|
1:
|
|
sw a3, 0(a0)
|
|
addi a0, a0, 4
|
|
blt a0, a1, 1b
|
|
2:
|
|
"#,
|
|
#[cfg(feature = "init-data")]
|
|
r#"
|
|
la a0, _data_start
|
|
la a1, _data_end
|
|
bge a0, a1, 2f
|
|
la a2, _sidata
|
|
1:
|
|
lw a3, 0(a2)
|
|
sw a3, 0(a0)
|
|
addi a0, a0, 4
|
|
addi a2, a2, 4
|
|
blt a0, a1, 1b
|
|
2:
|
|
"#,
|
|
#[cfg(feature = "init-rw-text")]
|
|
r#"
|
|
la a0, _srwtext
|
|
la a1, _erwtext
|
|
bge a0, a1, 2f
|
|
la a2, _irwtext
|
|
1:
|
|
lw a3, 0(a2)
|
|
sw a3, 0(a0)
|
|
addi a0, a0, 4
|
|
addi a2, a2, 4
|
|
blt a0, a1, 1b
|
|
2:
|
|
"#,
|
|
#[cfg(feature = "init-rtc-fast-data")]
|
|
r#"
|
|
la a0, _rtc_fast_data_start
|
|
la a1, _rtc_fast_data_end
|
|
bge a0, a1, 2f
|
|
la a2, _irtc_fast_data
|
|
1:
|
|
lw a3, 0(a2)
|
|
sw a3, 0(a0)
|
|
addi a0, a0, 4
|
|
addi a2, a2, 4
|
|
blt a0, a1, 1b
|
|
2:
|
|
"#,
|
|
#[cfg(feature = "init-rtc-fast-text")]
|
|
r#"
|
|
la a0, _srtc_fast_text
|
|
la a1, _ertc_fast_text
|
|
bge a0, a1, 2f
|
|
la a2, _irtc_fast_text
|
|
1:
|
|
lw a3, 0(a2)
|
|
sw a3, 0(a0)
|
|
addi a0, a0, 4
|
|
addi a2, a2, 4
|
|
blt a0, a1, 1b
|
|
2:
|
|
"#,
|
|
r#"
|
|
li x1, 0
|
|
li x2, 0
|
|
li x3, 0
|
|
li x4, 0
|
|
li x5, 0
|
|
li x6, 0
|
|
li x7, 0
|
|
li x8, 0
|
|
li x9, 0
|
|
li x10,0
|
|
li x11,0
|
|
li x12,0
|
|
li x13,0
|
|
li x14,0
|
|
li x15,0
|
|
li x16,0
|
|
li x17,0
|
|
li x18,0
|
|
li x19,0
|
|
li x20,0
|
|
li x21,0
|
|
li x22,0
|
|
li x23,0
|
|
li x24,0
|
|
li x25,0
|
|
li x26,0
|
|
li x27,0
|
|
li x28,0
|
|
li x29,0
|
|
li x30,0
|
|
li x31,0
|
|
|
|
.option push
|
|
.option norelax
|
|
la gp, __global_pointer$
|
|
.option pop
|
|
|
|
// Check hart ID
|
|
csrr t2, mhartid
|
|
lui t0, %hi(_max_hart_id)
|
|
add t0, t0, %lo(_max_hart_id)
|
|
bgtu t2, t0, abort
|
|
|
|
// Allocate stack
|
|
la sp, _stack_start
|
|
lui t0, 16
|
|
sub sp, sp, t0
|
|
|
|
// Set frame pointer
|
|
add s0, sp, zero
|
|
|
|
jal zero, _start_rust
|
|
|
|
.cfi_endproc
|
|
|
|
/*
|
|
Trap entry points (_start_trap, _start_trapN for N in 1..=31)
|
|
|
|
The default implementation saves all registers to the stack and calls
|
|
_start_trap_rust, then restores all saved registers before `mret`
|
|
*/
|
|
.section .trap, "ax"
|
|
.weak _start_trap
|
|
.weak _start_trap1
|
|
.weak _start_trap2
|
|
.weak _start_trap3
|
|
.weak _start_trap4
|
|
.weak _start_trap5
|
|
.weak _start_trap6
|
|
.weak _start_trap7
|
|
.weak _start_trap8
|
|
.weak _start_trap9
|
|
.weak _start_trap10
|
|
.weak _start_trap11
|
|
.weak _start_trap12
|
|
.weak _start_trap13
|
|
.weak _start_trap14
|
|
.weak _start_trap15
|
|
.weak _start_trap16
|
|
.weak _start_trap17
|
|
.weak _start_trap18
|
|
.weak _start_trap19
|
|
.weak _start_trap20
|
|
.weak _start_trap21
|
|
.weak _start_trap22
|
|
.weak _start_trap23
|
|
.weak _start_trap24
|
|
.weak _start_trap25
|
|
.weak _start_trap26
|
|
.weak _start_trap27
|
|
.weak _start_trap28
|
|
.weak _start_trap29
|
|
.weak _start_trap30
|
|
.weak _start_trap31
|
|
"#,
|
|
#[cfg(feature="direct-vectoring")]
|
|
r#"
|
|
_start_trap1:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_1_handler
|
|
j _start_trap_direct
|
|
_start_trap2:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_2_handler
|
|
j _start_trap_direct
|
|
_start_trap3:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_3_handler
|
|
j _start_trap_direct
|
|
_start_trap4:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_4_handler
|
|
j _start_trap_direct
|
|
_start_trap5:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_5_handler
|
|
j _start_trap_direct
|
|
_start_trap6:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_6_handler
|
|
j _start_trap_direct
|
|
_start_trap7:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_7_handler
|
|
j _start_trap_direct
|
|
_start_trap8:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_8_handler
|
|
j _start_trap_direct
|
|
_start_trap9:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_9_handler
|
|
j _start_trap_direct
|
|
_start_trap10:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_10_handler
|
|
j _start_trap_direct
|
|
_start_trap11:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_11_handler
|
|
j _start_trap_direct
|
|
_start_trap12:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_12_handler
|
|
j _start_trap_direct
|
|
_start_trap13:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_13_handler
|
|
j _start_trap_direct
|
|
_start_trap14:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_14_handler
|
|
j _start_trap_direct
|
|
_start_trap15:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_15_handler
|
|
j _start_trap_direct
|
|
_start_trap16:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_16_handler
|
|
j _start_trap_direct
|
|
_start_trap17:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_17_handler
|
|
j _start_trap_direct
|
|
_start_trap18:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_18_handler
|
|
j _start_trap_direct
|
|
_start_trap19:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_19_handler
|
|
j _start_trap_direct
|
|
_start_trap20:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_20_handler
|
|
j _start_trap_direct
|
|
_start_trap21:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_21_handler
|
|
j _start_trap_direct
|
|
_start_trap22:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_22_handler
|
|
j _start_trap_direct
|
|
_start_trap23:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_23_handler
|
|
j _start_trap_direct
|
|
_start_trap24:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_24_handler
|
|
j _start_trap_direct
|
|
_start_trap25:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_25_handler
|
|
j _start_trap_direct
|
|
_start_trap26:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_26_handler
|
|
j _start_trap_direct
|
|
_start_trap27:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_27_handler
|
|
j _start_trap_direct
|
|
_start_trap28:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_28_handler
|
|
j _start_trap_direct
|
|
_start_trap29:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_29_handler
|
|
j _start_trap_direct
|
|
_start_trap30:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_30_handler
|
|
j _start_trap_direct
|
|
_start_trap31:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0(sp)
|
|
la ra, cpu_int_31_handler
|
|
j _start_trap_direct
|
|
"#,
|
|
#[cfg(not(feature="direct-vectoring"))]
|
|
r#"
|
|
_start_trap1:
|
|
_start_trap2:
|
|
_start_trap3:
|
|
_start_trap4:
|
|
_start_trap5:
|
|
_start_trap6:
|
|
_start_trap7:
|
|
_start_trap8:
|
|
_start_trap9:
|
|
_start_trap10:
|
|
_start_trap11:
|
|
_start_trap12:
|
|
_start_trap13:
|
|
_start_trap14:
|
|
_start_trap15:
|
|
_start_trap16:
|
|
_start_trap17:
|
|
_start_trap18:
|
|
_start_trap19:
|
|
_start_trap20:
|
|
_start_trap21:
|
|
_start_trap22:
|
|
_start_trap23:
|
|
_start_trap24:
|
|
_start_trap25:
|
|
_start_trap26:
|
|
_start_trap27:
|
|
_start_trap28:
|
|
_start_trap29:
|
|
_start_trap30:
|
|
_start_trap31:
|
|
|
|
"#,
|
|
r#"
|
|
_start_trap:
|
|
addi sp, sp, -40*4
|
|
sw ra, 0*4(sp)"#,
|
|
#[cfg(feature="direct-vectoring")] //for the directly vectored handlers the above is stacked beforehand
|
|
r#"
|
|
la ra, _start_trap_rust_hal #this runs on exception, use regular fault handler
|
|
_start_trap_direct:
|
|
"#,
|
|
r#"
|
|
sw t0, 1*4(sp)
|
|
sw t1, 2*4(sp)
|
|
sw t2, 3*4(sp)
|
|
sw t3, 4*4(sp)
|
|
sw t4, 5*4(sp)
|
|
sw t5, 6*4(sp)
|
|
sw t6, 7*4(sp)
|
|
sw a0, 8*4(sp)
|
|
sw a1, 9*4(sp)
|
|
sw a2, 10*4(sp)
|
|
sw a3, 11*4(sp)
|
|
sw a4, 12*4(sp)
|
|
sw a5, 13*4(sp)
|
|
sw a6, 14*4(sp)
|
|
sw a7, 15*4(sp)
|
|
sw s0, 16*4(sp)
|
|
sw s1, 17*4(sp)
|
|
sw s2, 18*4(sp)
|
|
sw s3, 19*4(sp)
|
|
sw s4, 20*4(sp)
|
|
sw s5, 21*4(sp)
|
|
sw s6, 22*4(sp)
|
|
sw s7, 23*4(sp)
|
|
sw s8, 24*4(sp)
|
|
sw s9, 25*4(sp)
|
|
sw s10, 26*4(sp)
|
|
sw s11, 27*4(sp)
|
|
sw gp, 28*4(sp)
|
|
sw tp, 29*4(sp)
|
|
csrrs t1, mepc, x0
|
|
sw t1, 31*4(sp)
|
|
csrrs t1, mstatus, x0
|
|
sw t1, 32*4(sp)
|
|
csrrs t1, mcause, x0
|
|
sw t1, 33*4(sp)
|
|
csrrs t1, mtval, x0
|
|
sw t1, 34*4(sp)
|
|
|
|
addi s0, sp, 40*4
|
|
sw s0, 30*4(sp)
|
|
|
|
add a0, sp, zero
|
|
"#,
|
|
#[cfg(all(feature="interrupt-preemption", feature="direct-vectoring"))] //store current priority, set threshold, enable interrupts
|
|
r#"
|
|
addi sp, sp, -4 #build stack
|
|
sw ra, 0(sp)
|
|
jal ra, _handle_priority
|
|
lw ra, 0(sp)
|
|
sw a0, 0(sp) #reuse old stack, a0 is return of _handle_priority
|
|
addi a0, sp, 4 #the proper stack pointer is an argument to the HAL handler
|
|
"#,
|
|
#[cfg(not(feature="direct-vectoring"))] //jump to HAL handler
|
|
r#"
|
|
jal ra, _start_trap_rust_hal
|
|
"#,
|
|
#[cfg(feature="direct-vectoring")] //jump to handler loaded in direct handler
|
|
r#"
|
|
jalr ra, ra #jump to label loaded in _start_trapx
|
|
"#,
|
|
#[cfg(all(feature="interrupt-preemption", feature="direct-vectoring"))] //restore threshold
|
|
r#"
|
|
lw a0, 0(sp) #load stored priority
|
|
jal ra, _restore_priority
|
|
addi sp, sp, 4 #pop
|
|
"#,
|
|
r#"
|
|
lw t1, 31*4(sp)
|
|
csrrw x0, mepc, t1
|
|
|
|
lw t1, 32*4(sp)
|
|
csrrw x0, mstatus, t1
|
|
|
|
lw ra, 0*4(sp)
|
|
lw t0, 1*4(sp)
|
|
lw t1, 2*4(sp)
|
|
lw t2, 3*4(sp)
|
|
lw t3, 4*4(sp)
|
|
lw t4, 5*4(sp)
|
|
lw t5, 6*4(sp)
|
|
lw t6, 7*4(sp)
|
|
lw a0, 8*4(sp)
|
|
lw a1, 9*4(sp)
|
|
lw a2, 10*4(sp)
|
|
lw a3, 11*4(sp)
|
|
lw a4, 12*4(sp)
|
|
lw a5, 13*4(sp)
|
|
lw a6, 14*4(sp)
|
|
lw a7, 15*4(sp)
|
|
lw s0, 16*4(sp)
|
|
lw s1, 17*4(sp)
|
|
lw s2, 18*4(sp)
|
|
lw s3, 19*4(sp)
|
|
lw s4, 20*4(sp)
|
|
lw s5, 21*4(sp)
|
|
lw s6, 22*4(sp)
|
|
lw s7, 23*4(sp)
|
|
lw s8, 24*4(sp)
|
|
lw s9, 25*4(sp)
|
|
lw s10, 26*4(sp)
|
|
lw s11, 27*4(sp)
|
|
lw gp, 28*4(sp)
|
|
lw tp, 29*4(sp)
|
|
lw sp, 30*4(sp)
|
|
|
|
# SP was restored from the original SP
|
|
mret
|
|
|
|
/* Make sure there is an abort when linking */
|
|
.section .text.abort
|
|
.globl abort
|
|
abort:
|
|
j abort
|
|
|
|
/*
|
|
Interrupt vector table (_vector_table)
|
|
*/
|
|
|
|
.section .trap, "ax"
|
|
.weak _vector_table
|
|
.type _vector_table, @function
|
|
|
|
.option push
|
|
.balign 0x100
|
|
.option norelax
|
|
.option norvc
|
|
|
|
_vector_table:
|
|
j _start_trap
|
|
j _start_trap1
|
|
j _start_trap2
|
|
j _start_trap3
|
|
j _start_trap4
|
|
j _start_trap5
|
|
j _start_trap6
|
|
j _start_trap7
|
|
j _start_trap8
|
|
j _start_trap9
|
|
j _start_trap10
|
|
j _start_trap11
|
|
j _start_trap12
|
|
j _start_trap13
|
|
j _start_trap14
|
|
j _start_trap15
|
|
j _start_trap16
|
|
j _start_trap17
|
|
j _start_trap18
|
|
j _start_trap19
|
|
j _start_trap20
|
|
j _start_trap21
|
|
j _start_trap22
|
|
j _start_trap23
|
|
j _start_trap24
|
|
j _start_trap25
|
|
j _start_trap26
|
|
j _start_trap27
|
|
j _start_trap28
|
|
j _start_trap29
|
|
j _start_trap30
|
|
j _start_trap31
|
|
|
|
.option pop
|
|
"#,
|
|
#[cfg(feature="direct-vectoring")]
|
|
r#"
|
|
#this is required for the linking step, these symbols for in-use interrupts should always be overwritten by the user.
|
|
.section .trap, "ax"
|
|
.weak cpu_int_1_handler
|
|
.weak cpu_int_2_handler
|
|
.weak cpu_int_3_handler
|
|
.weak cpu_int_4_handler
|
|
.weak cpu_int_5_handler
|
|
.weak cpu_int_6_handler
|
|
.weak cpu_int_7_handler
|
|
.weak cpu_int_8_handler
|
|
.weak cpu_int_9_handler
|
|
.weak cpu_int_10_handler
|
|
.weak cpu_int_11_handler
|
|
.weak cpu_int_12_handler
|
|
.weak cpu_int_13_handler
|
|
.weak cpu_int_14_handler
|
|
.weak cpu_int_15_handler
|
|
.weak cpu_int_16_handler
|
|
.weak cpu_int_17_handler
|
|
.weak cpu_int_18_handler
|
|
.weak cpu_int_19_handler
|
|
.weak cpu_int_20_handler
|
|
.weak cpu_int_21_handler
|
|
.weak cpu_int_22_handler
|
|
.weak cpu_int_23_handler
|
|
.weak cpu_int_24_handler
|
|
.weak cpu_int_25_handler
|
|
.weak cpu_int_26_handler
|
|
.weak cpu_int_27_handler
|
|
.weak cpu_int_28_handler
|
|
.weak cpu_int_29_handler
|
|
.weak cpu_int_30_handler
|
|
.weak cpu_int_31_handler
|
|
cpu_int_1_handler:
|
|
cpu_int_2_handler:
|
|
cpu_int_3_handler:
|
|
cpu_int_4_handler:
|
|
cpu_int_5_handler:
|
|
cpu_int_6_handler:
|
|
cpu_int_7_handler:
|
|
cpu_int_8_handler:
|
|
cpu_int_9_handler:
|
|
cpu_int_10_handler:
|
|
cpu_int_11_handler:
|
|
cpu_int_12_handler:
|
|
cpu_int_13_handler:
|
|
cpu_int_14_handler:
|
|
cpu_int_15_handler:
|
|
cpu_int_16_handler:
|
|
cpu_int_17_handler:
|
|
cpu_int_18_handler:
|
|
cpu_int_19_handler:
|
|
cpu_int_20_handler:
|
|
cpu_int_21_handler:
|
|
cpu_int_22_handler:
|
|
cpu_int_23_handler:
|
|
cpu_int_24_handler:
|
|
cpu_int_25_handler:
|
|
cpu_int_26_handler:
|
|
cpu_int_27_handler:
|
|
cpu_int_28_handler:
|
|
cpu_int_29_handler:
|
|
cpu_int_30_handler:
|
|
cpu_int_31_handler:
|
|
la ra, abort #abort since proper handler is not defined, this could also just load the default _start_trap_rust_hal address and let the hal handle it.
|
|
jr ra
|
|
"#,
|
|
}
|