diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 4bc6849d..59ba1c83 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -31,6 +31,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Replace weak definition of `_pre_init_trap` with `PROVIDE(_pre_init_trap = _default_abort)`. - Now, `_default_abort` is 4-byte aligned (required by `_pre_init_trap`) - Removed `.init.trap` section, as it is no longer required. +- Replace weak definition of `_start_trap` with `PROVIDE(_start_trap = _default_start_trap)`. +- Replace weak definition of `_setup_interrupts` with `PROVIDE(_setup_interrupts = _default_setup_interrupts)`. +- Now, `_default_start_trap` is 4-byte aligned instead of target width-aligned. ## [v0.14.0] - 2025-02-18 diff --git a/riscv-rt/link.x.in b/riscv-rt/link.x.in index 0a6e1f3a..3fc9b06d 100644 --- a/riscv-rt/link.x.in +++ b/riscv-rt/link.x.in @@ -31,10 +31,18 @@ PROVIDE(abort = _default_abort); _pre_init_trap defaults to _default_abort. Note that _pre_init_trap must be 4-byte aligned */ PROVIDE(_pre_init_trap = _default_abort); -/* Default trap entry point. The riscv-rt crate provides a weak alias of this function, - which saves caller saved registers, calls _start_trap_rust, restores caller saved registers - and then returns. Users can override this alias by defining the symbol themselves */ -EXTERN(_start_trap); +/* Default trap entry point. If not _start_trap symbol is provided, then _start_trap maps to + _default_start_trap, which saves caller saved registers, calls _start_trap_rust, restores + caller saved registers and then returns. Note that _start_trap must be 4-byte aligned */ +EXTERN(_default_start_trap); +PROVIDE(_start_trap = _default_start_trap); + +/* Default interrupt setup entry point. If not _setup_interrupts symbol is provided, then + _setup_interrupts maps to _default_setup_interrupts, which in direct mode sets the value + of the xtvec register to _start_trap and, in vectored mode, sets its value to + _vector_table and enables vectored mode. */ +EXTERN(_default_setup_interrupts); +PROVIDE(_setup_interrupts = _default_setup_interrupts); /* Default exception handler. By default, the exception handler is abort. Users can override this alias by defining the symbol themselves */ @@ -195,6 +203,9 @@ BUG(riscv-rt): start of .heap is not 4-byte aligned"); ASSERT(_pre_init_trap % 4 == 0, " BUG(riscv-rt): _pre_init_trap is not 4-byte aligned"); +ASSERT(_start_trap % 4 == 0, " +BUG(riscv-rt): _start_trap is not 4-byte aligned"); + ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), " ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region. Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'"); diff --git a/riscv-rt/macros/src/lib.rs b/riscv-rt/macros/src/lib.rs index dcffb612..4767ff16 100644 --- a/riscv-rt/macros/src/lib.rs +++ b/riscv-rt/macros/src/lib.rs @@ -475,12 +475,13 @@ pub fn llvm_arch_patch(_input: TokenStream) -> TokenStream { q.into() } -/// Generates weak `_start_trap` function in assembly. +/// Generates `_default_start_trap` function in assembly. +/// If no `_start_trap` function is defined, the linker will use this function as the default. /// /// This implementation stores all registers in the trap frame and calls `_start_trap_rust`. /// The trap frame is allocated on the stack and deallocated after the call. #[proc_macro] -pub fn weak_start_trap(_input: TokenStream) -> TokenStream { +pub fn default_start_trap(_input: TokenStream) -> TokenStream { let arch = RiscvArch::try_from_env().unwrap(); let width = arch.width(); @@ -504,9 +505,9 @@ pub fn weak_start_trap(_input: TokenStream) -> TokenStream { r#" core::arch::global_asm!( ".section .trap, \"ax\" -.align {width} -.weak _start_trap -_start_trap: +.align 4 /* Alignment required for xtvec */ +.global _default_start_trap +_default_start_trap: addi sp, sp, - {trap_size} * {width} {store} add a0, sp, zero diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index 1dfdee69..6e44b563 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -237,15 +237,16 @@ _mp_hook: j 1b 2: li a0, 1 ret", - // Default implementation of `_setup_interrupts` sets the trap vector to `_start_trap`. + // Default implementation of `_setup_interrupts` sets the trap vector to `_start_trap` in direct mode. + // In vectored mode, it sets the trap vector to `_vector_table`. // Users can override this function by defining their own `_setup_interrupts` - ".weak _setup_interrupts -_setup_interrupts:", + ".global _default_setup_interrupts +_default_setup_interrupts:", #[cfg(not(feature = "v-trap"))] - "la t0, _start_trap", // _start_trap is 16-byte aligned, so it corresponds to the Direct trap mode + "la t0, _start_trap", // _start_trap is 4-byte aligned, so it corresponds to the Direct trap mode #[cfg(feature = "v-trap")] "la t0, _vector_table - ori t0, t0, 0x1", // _vector_table is 16-byte aligned, so we must set the bit 0 to activate the Vectored trap mode + ori t0, t0, 0x1", // _vector_table is at least 4-byte aligned, so we must set the bit 0 to activate the Vectored trap mode #[cfg(feature = "s-mode")] "csrw stvec, t0", #[cfg(not(feature = "s-mode"))] @@ -253,7 +254,7 @@ _setup_interrupts:", "ret", ); -riscv_rt_macros::weak_start_trap!(); +riscv_rt_macros::default_start_trap!(); #[cfg(feature = "v-trap")] riscv_rt_macros::vectored_interrupt_trap!();