79498281

Date: 2025-03-10 14:27:36
Score: 1
Natty:
Report link

As usual, I needed to post the question on StackOverflow to find the issue myself one minute later.

The issue was in the linker script: when I removed these two lines I've got the correct first-level handler in place, and my hardware jumped to it upon an IRQ:

_vector_table = ORIGIN(REGION_TEXT) + 0x12340;
_start_trap = ORIGIN(REGION_TEXT) + 0x12340;

Obviously, the drawback is that now I have to rely on linker to locate the handlers, but at least it works somehow. Initially I wanted it to be always at location 0x12340, so that I could put a breakpoint there without doing any math.

It turned out that if I do not define these symbols explicitly in the linker script, I can still define them as extern in my code and it works fine. Below is an example of my overloaded _setup_interrupts :

use riscv::register;

#[unsafe(no_mangle)]
pub extern "Rust" fn _setup_interrupts() {
    unsafe {
        let vectored = false;
        let mtvec = if vectored {
            unsafe extern "C" {
                fn _vector_table();
            }
            let mut mtvec = register::mtvec::Mtvec::from_bits(_vector_table as usize);
            mtvec.set_trap_mode(register::stvec::TrapMode::Vectored);
            mtvec
        } else {
            unsafe extern "C" {
                fn _start_trap();
            }
            let mut mtvec = register::mtvec::Mtvec::from_bits(_start_trap as usize);
            mtvec.set_trap_mode(register::stvec::TrapMode::Direct);
            mtvec
        };

        register::mtvec::write(mtvec);
        ...
    }
}
Reasons:
  • Blacklisted phrase (0.5): I need
  • Blacklisted phrase (1): StackOverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: Valeriy Kazantsev