From 539bce122d8501e1dc688cad92bfa8e922a489cc Mon Sep 17 00:00:00 2001 From: Kevin Bube Date: Fri, 25 Apr 2025 18:32:47 +0200 Subject: [PATCH 1/4] Add enter_unprivileged() function This adds a function to switch to program stack and unprivileged mode. Fixes #583 --- cortex-m/src/asm.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/cortex-m/src/asm.rs b/cortex-m/src/asm.rs index 4dc1ab07..b64a1f83 100644 --- a/cortex-m/src/asm.rs +++ b/cortex-m/src/asm.rs @@ -171,6 +171,35 @@ pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 { call_asm!(__sh_syscall(nr: u32, arg: u32) -> u32) } +/// Switch to unprivileged mode. +/// +/// Sets CONTROL.SPSEL (setting the program stack to be the active +/// stack) and CONTROL.nPRIV (setting unprivileged mode), updates the +/// program stack pointer to the address in `psp`, then jumps to the +/// address in `entry`. +/// +/// # Safety +/// +/// `psp` and `entry` must point to valid stack memory and executable +/// code, respectively. `psp` must be 8 bytes aligned and point to +/// stack top as stack grows towards lower addresses. +#[cfg(cortex_m)] +#[inline(always)] +pub unsafe fn enter_unprivileged(psp: *const u32, entry: fn() -> !) -> ! { + asm!( + "mrs {tmp}, CONTROL", + "orr {tmp}, #3", + "msr PSP, {psp}", + "msr CONTROL, {tmp}", + "isb", + "bx {ent}", + tmp = in(reg) 0, + psp = in(reg) psp, + ent = in(reg) entry, + options(noreturn, nomem, nostack) + ); +} + /// Bootstrap. /// /// Clears CONTROL.SPSEL (setting the main stack to be the active stack), From 8b84fc8b83fc5a4227786cb84c766c9a512cae8b Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Wed, 27 Aug 2025 15:38:35 +0100 Subject: [PATCH 2/4] Revised enter_unprivileged safety comments. --- cortex-m/src/asm.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cortex-m/src/asm.rs b/cortex-m/src/asm.rs index b64a1f83..6814698c 100644 --- a/cortex-m/src/asm.rs +++ b/cortex-m/src/asm.rs @@ -180,9 +180,13 @@ pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 { /// /// # Safety /// -/// `psp` and `entry` must point to valid stack memory and executable -/// code, respectively. `psp` must be 8 bytes aligned and point to -/// stack top as stack grows towards lower addresses. +/// * `psp` and `entry` must point to valid stack memory and executable code, +/// respectively. +/// * `psp` must be 8 bytes aligned and point to stack top as stack grows +/// towards lower addresses. +/// * The size of the stack provided here must be large enough for your +/// program - stack overflows are obviously UB. If your processor supports +/// it, you may wish to set the `PSPLIM` register to guard against this. #[cfg(cortex_m)] #[inline(always)] pub unsafe fn enter_unprivileged(psp: *const u32, entry: fn() -> !) -> ! { From c4b0b366a2bf87450f7b924f136c1537dcb0141a Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Wed, 27 Aug 2025 15:47:09 +0100 Subject: [PATCH 3/4] Rebase removed asm import, so qualify path to asm! macro. --- cortex-m/src/asm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cortex-m/src/asm.rs b/cortex-m/src/asm.rs index 6814698c..fa5cfce5 100644 --- a/cortex-m/src/asm.rs +++ b/cortex-m/src/asm.rs @@ -190,7 +190,7 @@ pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 { #[cfg(cortex_m)] #[inline(always)] pub unsafe fn enter_unprivileged(psp: *const u32, entry: fn() -> !) -> ! { - asm!( + core::arch::asm!( "mrs {tmp}, CONTROL", "orr {tmp}, #3", "msr PSP, {psp}", From 0ea4eff5f7b3f7def852ed2ce6d86761e44440f7 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Sun, 31 Aug 2025 20:54:00 +0100 Subject: [PATCH 4/4] Update CHANGELOG.md --- cortex-m/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cortex-m/CHANGELOG.md b/cortex-m/CHANGELOG.md index 7508e6cb..34f4f4b8 100644 --- a/cortex-m/CHANGELOG.md +++ b/cortex-m/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - MSRV is 1.61 to match cortex-m-rt crate +- Add `enter_unprivileged` function to switch to unprivileged mode (on the Process Stack, or `PSP`) ## [v0.7.7] - 2023-01-03