Skip to content
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

riscv-rt: Add mtvec-align features for the vector table alignment #259

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

ia0
Copy link
Contributor

@ia0 ia0 commented Jan 20, 2025

The RISC-V Privileged Specification (version 1.11) for mtvec CSR says:

The value in the BASE field must always be aligned on a 4-byte boundary, and the MODE setting may
impose additional alignment constraints on the value in the BASE field.
[...]
An implementation may have different alignment constraints for different modes. In particular,
MODE=Vectored may have stricter alignment constraints than MODE=Direct.

The Ibex Reference Guide for mtvec CSR says1:

The trap-vector base address, always aligned to 256 bytes

Other implementations have yet other alignment constraints (see #259 (comment)).

This PR introduces the mtvec-align-{16,64,256} cargo features to let users choose the alignment constraint appropriate to their implementation.

Footnotes

  1. https://ibex-core.readthedocs.io/en/latest/03_reference/cs_registers.html#machine-trap-vector-base-address-mtvec

@ia0 ia0 requested a review from a team as a code owner January 20, 2025 13:46
The RISC-V Privileged Specification (version 1.11) for mtvec CSR says:
> The value in the BASE field must always be aligned on a 4-byte boundary, and the MODE setting may
> impose additional alignment constraints on the value in the BASE field.
> [...]
> An implementation may have different alignment constraints for different modes. In particular,
> MODE=Vectored may have stricter alignment constraints than MODE=Direct.

The Ibex Reference Guide for mtvec CSR says[^1]:
> The trap-vector base address, always aligned to 256 bytes

I'm not sure how we can parametrize mtvec alignment without cargo features, so this PR simply uses
the stricter alignment. If a cargo feature is preferred, I can add `mtvec-align-256`. Note that
multiple `mtvec-align-N` features are additive because the stricter one wins.

[^1]: https://ibex-core.readthedocs.io/en/latest/03_reference/cs_registers.html#machine-trap-vector-base-address-mtvec
@hegza
Copy link

hegza commented Jan 20, 2025

Truly, each interrupt controller has its own alignment requirements. For instance, the riscv-fast-interrupt specification (CLIC) specifies 4-byte alignment in CLINT mode and 64-byte alignment in CLIC mode.

This has been an issue for us at https://github.com/soc-hub-fi/atalanta working on an Ibex-based CPU design as well, as not being able to parameterize this forces us to flag out & write the trap vector ourselves. I'd be in favor of a flag such as mtvec-align-256, though I don't know if that scales nicely.

@romancardenas
Copy link
Contributor

I think the best approach is using a linker symbol, such as _heap_size, for instance. By default, the symbol should be 4. PACs can overwrite it according to their particular needs.

The linker script should check that the alignment is a power of 2, I guess (and greater than 4)

Copy link
Contributor

@rmsyn rmsyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how we can parametrize mtvec alignment without cargo features, so this PR simply uses the stricter alignment.

One possibility is to use const generics to parameterize the Mtvec::set_address function directly, or offer another Mtvec::set_address_aligned<const N: usize>.

Something like:

impl Mtvec {
    pub fn set_address_aligned<const N: usize>(&mut self, address: usize) {
        // check alignment does not violate spec requirements
        const _: () = assert!(N >= 4);
        const _: () = assert_eq!(N % 4, 0);
        const MASK: usize = usize::MAX & !((1usize << N) - 1);

        self.set_address(address & MASK);
    }
}

The above could also obviously be made into a fallible try_set_address_aligned, just used this one for brevity.


For the actual alignment of the trap vector function, I think @romancardenas approach is the right way to go.

riscv-rt/src/interrupts.rs Outdated Show resolved Hide resolved
@ia0
Copy link
Contributor Author

ia0 commented Jan 21, 2025

I'd be in favor of a flag such as mtvec-align-256, though I don't know if that scales nicely.

It kind of scales thanks to the cfg_global_asm! macro (which I had to move to crate-level). However, this has an impact on compile time since this expands the macro multiple times. But that's similar to what's done in riscv-rt/src/asm.rs anyway.

I used the values 4 (default), 16, 64, and 256, since 4, 64, and 256 are used, and 16 is the missing power of 2 with an even exponent.

I think the best approach is using a linker symbol, such as _heap_size, for instance.

I don't think this works? .balign takes an absolute expression. Feel free to demonstrate what you had in mind with a PR if I misunderstood it.

One possibility is to use const generics to parameterize the Mtvec::set_address function directly

This seems unrelated. This PR is about letting users configure the alignment of the vector table in riscv-rt. What you mention seems to be a functionality of riscv and already too late, since the problem is compile-time, not runtime.

@ia0 ia0 requested a review from rmsyn January 21, 2025 10:09
#[allow(unused_macros)]
macro_rules! cfg_global_asm {
{@inner, [$($x:tt)*], } => {
core::arch::global_asm!{$($x)*}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I moved this from src/asm.rs and did 2 changes:

  • Fully qualify core::arch::global_asm!()
  • All unused_macros since it's only used on riscv32, riscv64, or without no-interrupts.

@ia0 ia0 changed the title riscv-rt: Align _vector_table to 256 instead of 4 riscv-rt: Add mtvec-align features for the vector table alignment Jan 21, 2025
@romancardenas
Copy link
Contributor

romancardenas commented Jan 21, 2025

Perhaps another option is using a procedural macro with environment variables (e.g., RISCV_RT_MTVEC_ALIGN). Something like this:

"cargo:rustc-env=RISCV_RT_LLVM_ARCH_PATCH={}",

PACs would set the mtvec alignment as part of their build.rs script. Then, the riscv-rt-macros would generate the assembly code for the table according to that table. If the environment variable is not defined, the default alignment is 4.
The macro can check that the alignment is a power of 2, or any check that we consider necessary.

(I'm not against the approach of this PR, but I'd rather have something more configurable that would not potentially lead to more features etc.)

@romancardenas
Copy link
Contributor

THe riscv-macros crate already provides a similar macro:

.balign 0x4 // TODO check if this is the correct alignment

We can make a new version of this macro that also allows to define the alignment of the vector table and use it in riscv-rt,

@romancardenas
Copy link
Contributor

The good thing about the riscv-macros macro is that it serves for custom core interrupt enumeration, not only the enumeration provided by the RISC-V standard

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 this pull request may close these issues.

4 participants