Skip to content

Commit 3e499c0

Browse files
committed
Add RISCV_MTVEC_ALIGN to control the alignment of the vector table
RISC-V requires a minimum of 4 bytes, but known implementations require 64 or even 256 bytes.
1 parent b391a48 commit 3e499c0

File tree

5 files changed

+51
-93
lines changed

5 files changed

+51
-93
lines changed

riscv-rt/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Changed
1111

12-
- Ensure the `.heap` section is 4-byte aligned
12+
- Use `RISCV_MTVEC_ALIGN` to control the alignment constraint of the vector table.
13+
- Ensure the `.heap` section is 4-byte aligned.
1314
- Limit rustc cfg flags to `riscvi`, `riscvm`, `riscvf`, and `riscvd`.
1415
- Temporary use of `RISCV_RT_LLVM_ARCH_PATCH` environment variable to include the
1516
temporary patch required for avoid LLVM spurious errors.

riscv-rt/build.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ fn main() {
4747
// make sure that these env variables are not changed without notice.
4848
println!("cargo:rerun-if-env-changed=RISCV_RT_BASE_ISA");
4949
println!("cargo:rerun-if-env-changed=RISCV_RT_LLVM_ARCH_PATCH");
50+
if env::var_os("CARGO_FEATURE_V_TRAP").is_some()
51+
&& env::var_os("CARGO_FEATURE_NO_INTERRUPTS").is_none()
52+
{
53+
// This environment variable is used by the `#[riscv::pac_enum()]` call in
54+
// `src/interrupts.rs` (when `v-trap` is enabled and `no-interrupts` disabled).
55+
println!("cargo:rerun-if-env-changed=RISCV_MTVEC_ALIGN");
56+
}
5057

5158
for flag in target.rustc_flags() {
5259
// Required until target_feature risc-v is stable and in-use

riscv-rt/src/interrupts.rs

Lines changed: 16 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -7,97 +7,24 @@
77
//!
88
//! In vectored mode (i.e., `v-trap` feature enabled), interrupt dispatching is handled by hardware.
99
//! To support this mode, we provide inline assembly code that defines the interrupt vector table.
10+
//! Since the alignment constraint of this vector table is implementation-specific, it can be
11+
//! changed by setting the `RISCV_MTVEC_ALIGN` environment variable (the default is 4).
1012
//!
1113
//! # Note
1214
//!
13-
//! If your target has custom core interrupt sources, the target PAC might provide equivalent
14-
//! code to adapt for the target needs. In this case, you may need to opt out this module.
15-
//! To do so, activate the `no-interrupts` feature of the `riscv-rt` crate.
16-
17-
#[cfg(not(feature = "v-trap"))]
18-
extern "C" {
19-
fn SupervisorSoft();
20-
fn MachineSoft();
21-
fn SupervisorTimer();
22-
fn MachineTimer();
23-
fn SupervisorExternal();
24-
fn MachineExternal();
25-
}
26-
27-
/// Array with all the core interrupt handlers sorted according to their interrupt source code.
28-
///
29-
/// # Note
30-
///
31-
/// This array is necessary only in direct mode (i.e., `v-trap` feature disabled).
32-
#[cfg(not(feature = "v-trap"))]
33-
#[no_mangle]
34-
pub static __CORE_INTERRUPTS: [Option<unsafe extern "C" fn()>; 12] = [
35-
None,
36-
Some(SupervisorSoft),
37-
None,
38-
Some(MachineSoft),
39-
None,
40-
Some(SupervisorTimer),
41-
None,
42-
Some(MachineTimer),
43-
None,
44-
Some(SupervisorExternal),
45-
None,
46-
Some(MachineExternal),
47-
];
48-
49-
/// It calls the corresponding interrupt handler depending on the interrupt source code.
50-
///
51-
/// # Note
52-
///
53-
/// This function is only required in direct mode (i.e., `v-trap` feature disabled).
54-
/// In vectored mode, interrupt handler dispatching is performed directly by hardware.
55-
///
56-
/// # Safety
57-
///
58-
/// This function must be called only from the [`crate::start_trap_rust`] function.
59-
/// Do **NOT** call this function directly.
60-
#[cfg(not(feature = "v-trap"))]
61-
#[inline]
62-
#[no_mangle]
63-
pub unsafe extern "C" fn _dispatch_core_interrupt(code: usize) {
64-
extern "C" {
65-
fn DefaultHandler();
66-
}
67-
match __CORE_INTERRUPTS.get(code) {
68-
Some(Some(handler)) => handler(),
69-
_ => DefaultHandler(),
70-
}
71-
}
15+
//! If your target has custom core interrupt sources, the target PAC might provide equivalent code
16+
//! to adapt for the target needs (and is responsible for any alignment constraint). In this case,
17+
//! you may need to opt out this module. To do so, activate the `no-interrupts` feature of the
18+
//! `riscv-rt` crate.
7219
7320
// In vectored mode, we also must provide a vector table
74-
#[cfg(all(
75-
any(target_arch = "riscv32", target_arch = "riscv64"),
76-
feature = "v-trap"
77-
))]
78-
core::arch::global_asm!(
79-
r#" .section .trap, "ax"
80-
.weak _vector_table
81-
.type _vector_table, @function
82-
83-
.option push
84-
.balign 0x4 // TODO check if this is the correct alignment
85-
.option norelax
86-
.option norvc
87-
88-
_vector_table:
89-
j _start_trap // Interrupt 0 is used for exceptions
90-
j _start_SupervisorSoft_trap
91-
j _start_DefaultHandler_trap // Interrupt 2 is reserved
92-
j _start_MachineSoft_trap
93-
j _start_DefaultHandler_trap // Interrupt 4 is reserved
94-
j _start_SupervisorTimer_trap
95-
j _start_DefaultHandler_trap // Interrupt 6 is reserved
96-
j _start_MachineTimer_trap
97-
j _start_DefaultHandler_trap // Interrupt 8 is reserved
98-
j _start_SupervisorExternal_trap
99-
j _start_DefaultHandler_trap // Interrupt 10 is reserved
100-
j _start_MachineExternal_trap
101-
102-
.option pop"#
103-
);
21+
#[riscv::pac_enum(unsafe CoreInterruptNumber)]
22+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23+
enum Interrupt {
24+
SupervisorSoft = 1,
25+
MachineSoft = 3,
26+
SupervisorTimer = 5,
27+
MachineTimer = 7,
28+
SupervisorExternal = 9,
29+
MachineExternal = 11,
30+
}

riscv/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1313

1414
### Changed
1515

16+
- Use `RISCV_MTVEC_ALIGN` to control the alignment constraint of the vector table
1617
- Simplify register macros with `cfg` field
1718
- Align assembly functions with `cortex-m`
1819
- Use CSR helper macros to define `marchid` register

riscv/macros/src/lib.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,20 @@ impl PacEnumItem {
265265
}
266266

267267
fn vector_table(&self) -> TokenStream2 {
268-
let mut asm = String::from(
268+
let align = match std::env::var("RISCV_MTVEC_ALIGN") {
269+
Ok(x) => x.parse::<u32>().ok(),
270+
Err(std::env::VarError::NotPresent) => Some(4),
271+
Err(std::env::VarError::NotUnicode(_)) => None,
272+
};
273+
let align = match align {
274+
Some(x) if x.is_power_of_two() && 4 <= x => x,
275+
_ => {
276+
return quote!(compile_error!(
277+
"RISCV_MTVEC_ALIGN is not a power of 2 (minimum 4)"
278+
))
279+
}
280+
};
281+
let mut asm = format!(
269282
r#"
270283
#[cfg(all(feature = "v-trap", any(target_arch = "riscv32", target_arch = "riscv64")))]
271284
core::arch::global_asm!("
@@ -274,7 +287,7 @@ core::arch::global_asm!("
274287
.type _vector_table, @function
275288
276289
.option push
277-
.balign 0x4 // TODO check if this is the correct alignment
290+
.balign {align}
278291
.option norelax
279292
.option norvc
280293
@@ -315,6 +328,8 @@ core::arch::global_asm!("
315328
let max_discriminant = self.max_number;
316329
let valid_matches = self.valid_matches();
317330

331+
let is_core_interrupt = matches!(attr, PacTrait::Interrupt(InterruptType::Core));
332+
318333
// Push the trait implementation
319334
res.push(quote! {
320335
unsafe impl riscv::#trait_name for #name {
@@ -350,19 +365,26 @@ core::arch::global_asm!("
350365

351366
let handlers = self.handlers(&trap_config);
352367
let interrupt_array = self.handlers_array();
368+
let cfg_v_trap = match is_core_interrupt {
369+
true => Some(quote!(#[cfg(not(feature = "v-trap"))])),
370+
false => None,
371+
};
353372

354373
// Push the interrupt handler functions and the interrupt array
355374
res.push(quote! {
375+
#cfg_v_trap
356376
extern "C" {
357377
#(#handlers;)*
358378
}
359379

380+
#cfg_v_trap
360381
#[doc(hidden)]
361382
#[no_mangle]
362383
pub static #vector_table: [Option<unsafe extern "C" fn(#(#array_signature),*)>; #max_discriminant + 1] = [
363384
#(#interrupt_array),*
364385
];
365386

387+
#cfg_v_trap
366388
#[inline]
367389
#[no_mangle]
368390
unsafe extern "C" fn #dispatch_fn_name(#(#dispatch_fn_args),*) {
@@ -378,7 +400,7 @@ core::arch::global_asm!("
378400
});
379401
}
380402

381-
if let PacTrait::Interrupt(InterruptType::Core) = attr {
403+
if is_core_interrupt {
382404
res.push(self.vector_table());
383405
}
384406

0 commit comments

Comments
 (0)