359359//! If the `v-trap` feature is enabled, the trap vector is set to `_vector_table`
360360//! in vectored mode. Users can override this function by defining their own `_setup_interrupts`.
361361//!
362+ //! This function can be redefined in the following way:
363+ //!
364+ //! ``` no_run
365+ //! #[export_name = "_setup_interrupts"]
366+ //! pub fn setup_interrupts() {
367+ //! // ...
368+ //! }
369+ //! ```
370+ //!
371+ //! ## `hal_main`
372+ //!
373+ //! Internally, `riscv-rt` does not jump to the `main` function created by the user using the
374+ //! [`#[entry]`][attr-entry] attribute. Instead, it jumps to the `hal_main` function.
375+ //! The linker will map `hal_main` to `main` if the prior is not defined, which is the typical case.
376+ //! However, the `hal_main` function allows HALs to inject additional code before jumping to the
377+ //! user's `main` function. This might be useful for certain HALs that need to perform additional
378+ //! configuration before the main function is executed.
379+ //!
362380//! # Attributes
363381//!
364382//! ## Core exception handlers
@@ -552,10 +570,16 @@ pub mod exceptions;
552570pub mod interrupts;
553571
554572#[ cfg( feature = "s-mode" ) ]
555- use riscv:: register:: scause as xcause;
573+ use riscv:: register:: {
574+ scause as xcause,
575+ stvec:: { self as xtvec, Stvec as Xtvec , TrapMode } ,
576+ } ;
556577
557578#[ cfg( not( feature = "s-mode" ) ) ]
558- use riscv:: register:: mcause as xcause;
579+ use riscv:: register:: {
580+ mcause as xcause,
581+ mtvec:: { self as xtvec, Mtvec as Xtvec , TrapMode } ,
582+ } ;
559583
560584pub use riscv_pac:: * ;
561585pub use riscv_rt_macros:: { core_interrupt, entry, exception, external_interrupt} ;
@@ -571,6 +595,60 @@ pub use riscv_rt_macros::pre_init;
571595#[ doc( hidden) ]
572596pub static __ONCE__: ( ) = ( ) ;
573597
598+ /// Rust entry point (_start_rust)
599+ ///
600+ /// Configures interrupts and calls main. This function never returns.
601+ ///
602+ /// # Safety
603+ ///
604+ /// This function should not be called directly by the user, and should instead
605+ /// be invoked by the runtime implicitly.
606+ #[ cfg_attr(
607+ any( target_arch = "riscv32" , target_arch = "riscv64" ) ,
608+ link_section = ".init.rust"
609+ ) ]
610+ #[ export_name = "_start_rust" ]
611+ pub unsafe extern "C" fn start_rust ( a0 : usize , a1 : usize , a2 : usize ) -> ! {
612+ unsafe extern "Rust" {
613+ fn _setup_interrupts ( ) ;
614+ fn hal_main ( a0 : usize , a1 : usize , a2 : usize ) -> !;
615+ }
616+
617+ _setup_interrupts ( ) ;
618+ hal_main ( a0, a1, a2) ;
619+ }
620+
621+ /// Default implementation of `_setup_interrupts`.
622+ ///
623+ /// In direct mode (i.e., `v-trap` feature disabled), it sets the trap vector to `_start_trap`.
624+ /// In vectored mode ( i. e . , `v -trap` feature enabled) , it sets the trap vector to `_vector_table`.
625+ ///
626+ /// # Note
627+ ///
628+ /// Users can override this function by defining their own `_setup_interrupts` function.
629+ ///
630+ /// # Safety
631+ ///
632+ /// This function should not be called directly by the user, and should instead
633+ /// be invoked by the runtime implicitly. It is expected to be called before the main function.
634+ #[ export_name = "_default_setup_interrupts" ]
635+ pub unsafe extern "Rust" fn setup_interrupts ( ) {
636+ unsafe extern "C" {
637+ #[ cfg( not( feature = "v-trap" ) ) ]
638+ fn _start_trap ( ) ;
639+ #[ cfg( feature = "v-trap" ) ]
640+ fn _vector_table ( ) ;
641+ }
642+
643+ let xtvec_val = match ( ) {
644+ #[ cfg( not( feature = "v-trap" ) ) ]
645+ _ => Xtvec :: new ( _start_trap as usize , TrapMode :: Direct ) ,
646+ #[ cfg( feature = "v-trap" ) ]
647+ _ => Xtvec :: new ( _vector_table as usize , TrapMode :: Vectored ) ,
648+ } ;
649+ xtvec:: write ( xtvec_val) ;
650+ }
651+
574652/// Registers saved in trap handler
575653#[ repr( C ) ]
576654#[ derive( Debug ) ]
0 commit comments