From 1ff3edfb35a68afdbcfba26f48a29da91a4c9351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Thu, 7 Aug 2025 13:33:02 +0200 Subject: [PATCH 1/5] Add `pre-default-start-trap` feature --- riscv-rt/Cargo.toml | 1 + riscv-rt/macros/Cargo.toml | 1 + riscv-rt/macros/src/lib.rs | 11 +++++++++++ riscv-rt/src/lib.rs | 9 +++++++++ 4 files changed, 22 insertions(+) diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index b6a3f83d..28c57bf9 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -46,3 +46,4 @@ no-xie-xip = [] device = [] memory = [] defmt = ["dep:defmt"] +pre-default-start-trap = ["riscv-rt-macros/pre-default-start-trap"] diff --git a/riscv-rt/macros/Cargo.toml b/riscv-rt/macros/Cargo.toml index 29be4502..837cfcaf 100644 --- a/riscv-rt/macros/Cargo.toml +++ b/riscv-rt/macros/Cargo.toml @@ -25,3 +25,4 @@ syn = { version = "2.0", features = ["extra-traits", "full"] } s-mode = [] v-trap = [] u-boot = [] +pre-default-start-trap = [] diff --git a/riscv-rt/macros/src/lib.rs b/riscv-rt/macros/src/lib.rs index d174a9bb..9c0ca2b2 100644 --- a/riscv-rt/macros/src/lib.rs +++ b/riscv-rt/macros/src/lib.rs @@ -606,6 +606,16 @@ pub fn default_start_trap(_input: TokenStream) -> TokenStream { #[cfg(not(feature = "s-mode"))] let ret = "mret"; + let pre_default_start_trap = if cfg!(feature = "pre-default-start-trap") { + r#" + j _pre_default_start_trap +.global _pre_default_start_trap_ret +_pre_default_start_trap_ret: + "# + } else { + "" + }; + format!( r#" core::arch::global_asm!( @@ -613,6 +623,7 @@ core::arch::global_asm!( .balign 4 /* Alignment required for xtvec */ .global _default_start_trap _default_start_trap: + {pre_default_start_trap} addi sp, sp, - {trap_size} * {width} {store} add a0, sp, zero diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index f15f2aa4..314e4680 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -598,6 +598,15 @@ //! because when booting from elf, U-boot passes `argc` and `argv`. This feature also implies `single-hart`. //! The only way to get boot-hart is through fdt, so other harts initialization is up to you. //! +//! ## `pre-default-start-trap` +//! +//! This provides a mechanism to execute custom code prior to `default_start_trap`. +//! +//! To use it, the user must define a symbol named `_pre_default_start_trap`, which the system will jump to. +//! After executing the custom code, control should return by jumping to `_pre_default_start_trap_ret`. +//! +//! It is expected that the custom code does not clobber any registers. +//! //! [attr-entry]: attr.entry.html //! [attr-exception]: attr.exception.html //! [attr-external-interrupt]: attr.external_interrupt.html From 0e2120191ae0693c8fbf0f2e1d5917fdcd877589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Thu, 7 Aug 2025 13:34:23 +0200 Subject: [PATCH 2/5] Changelog --- riscv-rt/CHANGELOG.md | 2 +- riscv-rt/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 3ce8123c..d816a0f3 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). linker will place this new section in `REGION_BSS`. - Additional feature `no-xie-xip` to work on chips without the XIE and XIP CSRs (e.g. ESP32-C2, ESP32-C3) - Additional feature `defmt` which will implement `defmt::Format` on certain types - +- Additional feature `pre-default-start-trap` to execute custom code before `_default_start_trap` ### Changed - `main` function no longer needs to be close to `_start`. A linker script may copy diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index 314e4680..f89b4905 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -600,7 +600,7 @@ //! //! ## `pre-default-start-trap` //! -//! This provides a mechanism to execute custom code prior to `default_start_trap`. +//! This provides a mechanism to execute custom code prior to `_default_start_trap`. //! //! To use it, the user must define a symbol named `_pre_default_start_trap`, which the system will jump to. //! After executing the custom code, control should return by jumping to `_pre_default_start_trap_ret`. From da689e8eb228d151be90dba5e7d655d0d67724ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Thu, 7 Aug 2025 14:20:30 +0200 Subject: [PATCH 3/5] Add example usage --- riscv-rt/src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index f89b4905..86db1692 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -607,6 +607,40 @@ //! //! It is expected that the custom code does not clobber any registers. //! +//! ### Example +//! +//! ```rust,no_run +//! core::arch::global_asm!( +//! r#" +//! .section .trap.start, "ax" +//! .extern _pre_default_start_trap_ret +//! .global _pre_default_start_trap +//! +//! // with the pre-default-start-trap feature enabled this code is executed before +//! // the code in _default_start_trap +//! _pre_default_start_trap: +//! // move SP to some save place if it's pointing below the RAM +//! // otherwise we won't be able to do anything reasonable +//! // (since we don't have a useable stack otherwise) +//! // +//! // most probably we will just print something and halt in this case +//! // we actually can't do anything else +//! csrw mscratch, t0 +//! la t0, _dram_origin +//! bge sp, t0, 1f +//! +//! // set SP to the start of the stack +//! la sp, _stack_start +//! +//! 1: +//! // remember to not clobber any registers, restore t0 from mscratch +//! csrr t0, mscratch +//! +//! // jump back to continue with _default_start_trap +//! j _pre_default_start_trap_ret +//! "# +//! ); +//! ``` //! [attr-entry]: attr.entry.html //! [attr-exception]: attr.exception.html //! [attr-external-interrupt]: attr.external_interrupt.html From ed2c6f05c12285403145288a3ef9d4984aeb38b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Fri, 8 Aug 2025 10:23:11 +0200 Subject: [PATCH 4/5] Align usage example with other examples --- riscv-rt/src/lib.rs | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index 86db1692..d21fa5f9 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -612,29 +612,14 @@ //! ```rust,no_run //! core::arch::global_asm!( //! r#" -//! .section .trap.start, "ax" -//! .extern _pre_default_start_trap_ret -//! .global _pre_default_start_trap +//! .section .trap.start, "ax" +//! .extern _pre_default_start_trap_ret +//! .global _pre_default_start_trap //! -//! // with the pre-default-start-trap feature enabled this code is executed before -//! // the code in _default_start_trap //! _pre_default_start_trap: -//! // move SP to some save place if it's pointing below the RAM -//! // otherwise we won't be able to do anything reasonable -//! // (since we don't have a useable stack otherwise) -//! // -//! // most probably we will just print something and halt in this case -//! // we actually can't do anything else -//! csrw mscratch, t0 -//! la t0, _dram_origin -//! bge sp, t0, 1f -//! -//! // set SP to the start of the stack -//! la sp, _stack_start -//! -//! 1: -//! // remember to not clobber any registers, restore t0 from mscratch -//! csrr t0, mscratch +//! +//! // your code goes here remember to not clobber any registers, +//! // use mscratch to retain a single register if needed //! //! // jump back to continue with _default_start_trap //! j _pre_default_start_trap_ret From 429ba4bc7bdd16d67e073b5599253b3b391f8dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Fri, 8 Aug 2025 11:31:26 +0200 Subject: [PATCH 5/5] Add some details to the docs --- riscv-rt/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index d21fa5f9..4c3b79b5 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -605,8 +605,12 @@ //! To use it, the user must define a symbol named `_pre_default_start_trap`, which the system will jump to. //! After executing the custom code, control should return by jumping to `_pre_default_start_trap_ret`. //! +//! It's recommended to place the code in the `.trap.start` section to make sure it's reachable from `_default_start_trap`. +//! //! It is expected that the custom code does not clobber any registers. //! +//! Please note that your code won't be run for interrupts in vectored mode. +//! //! ### Example //! //! ```rust,no_run