Skip to content

Hard fault on debug compilation #583

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kevinbube opened this issue Mar 23, 2025 · 5 comments · May be fixed by #594
Open

Hard fault on debug compilation #583

kevinbube opened this issue Mar 23, 2025 · 5 comments · May be fixed by #594

Comments

@kevinbube
Copy link

Hello all,
I am experimenting with an STM32F303 and try to enter unprivileged mode with program stack pointer set. I use the following minimal example:

#![no_std]
#![no_main]

use panic_halt as _;
use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln;
use stm32f3xx_hal::prelude::*;
                    
#[entry]
fn entry() -> ! {
    extern "C" {
        static _user_stack_start: u32;
    }

    // set unprivileged stack
    unsafe {
        let stack_addr = &_user_stack_start as *const u32 as u32;
        cortex_m::register::psp::write(stack_addr)
    };
    
    let mut ctrl_reg = cortex_m::register::control::read();
    ctrl_reg.set_npriv(cortex_m::register::control::Npriv::Unprivileged);
    ctrl_reg.set_spsel(cortex_m::register::control::Spsel::Psp);

    // enter unprivileged mode
    unsafe { cortex_m::register::control::write(ctrl_reg) };

    main();
}

fn main() -> ! {
    hprintln!("hello");

    loop {}
}

On a debug build this causes a hard fault at control::write(). On release build it works fine. I guess this is because the compiler does not inline the call on debug and the function crashes on return as it fails to pop the return address from the stack, which changed from MSP to PSP.

Maybe #[inline(always)] is necessary for control::write()?

@jannic
Copy link
Member

jannic commented Apr 15, 2025

Even if #[inline(always)] helps in this case (I didn't try it), it can't be a correct solution, as you can't rely on inlining for correctness: https://doc.rust-lang.org/stable/reference/attributes/codegen.html?highlight=inline#the-inline-attribute clearly documents that the compiler is not required to actually inline the function, even with #[inline(always)].

The conclusion may be that you can't change the stack using cortex_m::register::control::write.

@BartMassey
Copy link
Member

Needs a macro, sounds like.

@adamgreig
Copy link
Member

Hm, yea, maybe a macro-by-example could emit the inline asm needed. That's probably nicer than just saying everyone has to use asm directly. It would still have to be used pretty carefully though.

Certainly I don't see how we can usefully have this method as a normal function today, and now that inline asm is stable the justification from the time ("it's impossible to do this otherwise in stable rust; at least the function works in release mode") doesn't hold up.

@jonathanpallant
Copy link
Contributor

jonathanpallant commented Apr 16, 2025

I need this to run a particular proprietary RTOS. I suspect the correct solution is an argument given to the entry attribute macro.

Edit: That or a macro! that takes a function to call as an argument.

@kevinbube
Copy link
Author

kevinbube commented Apr 21, 2025 via email

kevinbube added a commit to kevinbube/cortex-m that referenced this issue Apr 25, 2025
This adds a function to switch to program stack and unprivileged mode.

Fixes rust-embedded#583
@kevinbube kevinbube linked a pull request Apr 25, 2025 that will close this issue
kevinbube added a commit to kevinbube/cortex-m that referenced this issue Apr 25, 2025
This adds a function to switch to program stack and unprivileged mode.

Fixes rust-embedded#583
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants