Skip to content

Commit 8f1920d

Browse files
committed
Add interrupts and exceptions to link.x only when required
1 parent 95cfb90 commit 8f1920d

File tree

6 files changed

+88
-55
lines changed

6 files changed

+88
-55
lines changed

riscv-rt/CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Linker file now refers to standard exceptions and interrupts only when the
13+
`no-exceptions` and `no-interrupts` features are disabled, respectively.
14+
This is achieved by substituting `${INCLUDE_LINKER_FILES}` with the contents
15+
of `exceptions.x` and/or `interrupts.x`.
16+
1017
## [v0.14.0] - 2025-02-18
1118

1219
### Changed

riscv-rt/build.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,24 @@ fn add_linker_script(arch_width: u32) -> io::Result<()> {
1111
let mut content = fs::read_to_string("link.x.in")?;
1212
content = content.replace("${ARCH_WIDTH}", &arch_width.to_string());
1313

14-
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
14+
// Get target-dependent linker configuration and replace ${INCLUDE_LINKER_FILES} with it
15+
let mut include_content = String::new();
16+
17+
// If no-exceptions is disabled, include the exceptions.x files
18+
if env::var_os("CARGO_FEATURE_NO_EXCEPTIONS").is_none() {
19+
let exceptions_content = fs::read_to_string("exceptions.x")?;
20+
include_content.push_str(&(exceptions_content + "\n"));
21+
}
22+
// If no-interrupts is disabled, include the interrupts.x files
23+
if env::var_os("CARGO_FEATURE_NO_INTERRUPTS").is_none() {
24+
let interrupts_content = fs::read_to_string("interrupts.x")?;
25+
include_content.push_str(&(interrupts_content + "\n"));
26+
}
27+
28+
content = content.replace("${INCLUDE_LINKER_FILES}", &include_content);
1529

1630
// Put the linker script somewhere the linker can find it
31+
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
1732
fs::write(out_dir.join("link.x"), content)?;
1833
println!("cargo:rustc-link-search={}", out_dir.display());
1934
println!("cargo:rerun-if-changed=link.x");

riscv-rt/exceptions.x

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* # EXCEPTION HANDLERS DESCRIBED IN THE STANDARD RISC-V ISA
2+
3+
If the `no-exceptions` feature is DISABLED, this file will be included in link.x.in.
4+
If the `no-exceptions` feature is ENABLED, this file will be ignored.
5+
*/
6+
7+
/* It is possible to define a special handler for each exception type.
8+
By default, all exceptions are handled by ExceptionHandler. However,
9+
users can override these alias by defining the symbol themselves */
10+
PROVIDE(InstructionMisaligned = ExceptionHandler);
11+
PROVIDE(InstructionFault = ExceptionHandler);
12+
PROVIDE(IllegalInstruction = ExceptionHandler);
13+
PROVIDE(Breakpoint = ExceptionHandler);
14+
PROVIDE(LoadMisaligned = ExceptionHandler);
15+
PROVIDE(LoadFault = ExceptionHandler);
16+
PROVIDE(StoreMisaligned = ExceptionHandler);
17+
PROVIDE(StoreFault = ExceptionHandler);
18+
PROVIDE(UserEnvCall = ExceptionHandler);
19+
PROVIDE(SupervisorEnvCall = ExceptionHandler);
20+
PROVIDE(MachineEnvCall = ExceptionHandler);
21+
PROVIDE(InstructionPageFault = ExceptionHandler);
22+
PROVIDE(LoadPageFault = ExceptionHandler);
23+
PROVIDE(StorePageFault = ExceptionHandler);

riscv-rt/interrupts.x

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* # CORE INTERRUPT HANDLERS DESCRIBED IN THE STANDARD RISC-V ISA
2+
3+
If the `no-interrupts` feature is DISABLED, this file will be included in link.x.in.
4+
If the `no-interrupts` feature is ENABLED, this file will be ignored.
5+
*/
6+
7+
/* It is possible to define a special handler for each interrupt type.
8+
By default, all interrupts are handled by DefaultHandler. However, users can
9+
override these alias by defining the symbol themselves */
10+
PROVIDE(SupervisorSoft = DefaultHandler);
11+
PROVIDE(MachineSoft = DefaultHandler);
12+
PROVIDE(SupervisorTimer = DefaultHandler);
13+
PROVIDE(MachineTimer = DefaultHandler);
14+
PROVIDE(SupervisorExternal = DefaultHandler);
15+
PROVIDE(MachineExternal = DefaultHandler);
16+
17+
/* When vectored trap mode is enabled, each interrupt source must implement its own
18+
trap entry point. By default, all interrupts start in _DefaultHandler_trap.
19+
However, users can override these alias by defining the symbol themselves */
20+
PROVIDE(_start_SupervisorSoft_trap = _start_DefaultHandler_trap);
21+
PROVIDE(_start_MachineSoft_trap = _start_DefaultHandler_trap);
22+
PROVIDE(_start_SupervisorTimer_trap = _start_DefaultHandler_trap);
23+
PROVIDE(_start_MachineTimer_trap = _start_DefaultHandler_trap);
24+
PROVIDE(_start_SupervisorExternal_trap = _start_DefaultHandler_trap);
25+
PROVIDE(_start_MachineExternal_trap = _start_DefaultHandler_trap);

riscv-rt/link.x.in

+14-54
Original file line numberDiff line numberDiff line change
@@ -22,73 +22,33 @@
2222
means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`.
2323
*/
2424

25-
PROVIDE(_stext = ORIGIN(REGION_TEXT));
26-
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
27-
PROVIDE(_max_hart_id = 0);
28-
PROVIDE(_hart_stack_size = 2K);
29-
PROVIDE(_heap_size = 0);
30-
31-
/** TRAP ENTRY POINTS **/
32-
3325
/* Default trap entry point. The riscv-rt crate provides a weak alias of this function,
3426
which saves caller saved registers, calls _start_trap_rust, restores caller saved registers
3527
and then returns. Users can override this alias by defining the symbol themselves */
3628
EXTERN(_start_trap);
3729

38-
/* Default interrupt trap entry point. When vectored trap mode is enabled,
39-
the riscv-rt crate provides an implementation of this function, which saves caller saved
40-
registers, calls the the DefaultHandler ISR, restores caller saved registers and returns. */
41-
PROVIDE(_start_DefaultHandler_trap = _start_trap);
42-
43-
/* When vectored trap mode is enabled, each interrupt source must implement its own
44-
trap entry point. By default, all interrupts start in _start_trap. However, users can
45-
override these alias by defining the symbol themselves */
46-
PROVIDE(_start_SupervisorSoft_trap = _start_DefaultHandler_trap);
47-
PROVIDE(_start_MachineSoft_trap = _start_DefaultHandler_trap);
48-
PROVIDE(_start_SupervisorTimer_trap = _start_DefaultHandler_trap);
49-
PROVIDE(_start_MachineTimer_trap = _start_DefaultHandler_trap);
50-
PROVIDE(_start_SupervisorExternal_trap = _start_DefaultHandler_trap);
51-
PROVIDE(_start_MachineExternal_trap = _start_DefaultHandler_trap);
52-
53-
/** EXCEPTION HANDLERS **/
54-
5530
/* Default exception handler. The riscv-rt crate provides a weak alias of this function,
5631
which is a busy loop. Users can override this alias by defining the symbol themselves */
5732
EXTERN(ExceptionHandler);
5833

59-
/* It is possible to define a special handler for each exception type.
60-
By default, all exceptions are handled by ExceptionHandler. However, users can
61-
override these alias by defining the symbol themselves */
62-
PROVIDE(InstructionMisaligned = ExceptionHandler);
63-
PROVIDE(InstructionFault = ExceptionHandler);
64-
PROVIDE(IllegalInstruction = ExceptionHandler);
65-
PROVIDE(Breakpoint = ExceptionHandler);
66-
PROVIDE(LoadMisaligned = ExceptionHandler);
67-
PROVIDE(LoadFault = ExceptionHandler);
68-
PROVIDE(StoreMisaligned = ExceptionHandler);
69-
PROVIDE(StoreFault = ExceptionHandler);
70-
PROVIDE(UserEnvCall = ExceptionHandler);
71-
PROVIDE(SupervisorEnvCall = ExceptionHandler);
72-
PROVIDE(MachineEnvCall = ExceptionHandler);
73-
PROVIDE(InstructionPageFault = ExceptionHandler);
74-
PROVIDE(LoadPageFault = ExceptionHandler);
75-
PROVIDE(StorePageFault = ExceptionHandler);
76-
77-
/** INTERRUPT HANDLERS **/
78-
7934
/* Default interrupt handler. The riscv-rt crate provides a weak alias of this function,
8035
which is a busy loop. Users can override this alias by defining the symbol themselves */
8136
EXTERN(DefaultHandler);
8237

83-
/* It is possible to define a special handler for each interrupt type.
84-
By default, all interrupts are handled by DefaultHandler. However, users can
85-
override these alias by defining the symbol themselves */
86-
PROVIDE(SupervisorSoft = DefaultHandler);
87-
PROVIDE(MachineSoft = DefaultHandler);
88-
PROVIDE(SupervisorTimer = DefaultHandler);
89-
PROVIDE(MachineTimer = DefaultHandler);
90-
PROVIDE(SupervisorExternal = DefaultHandler);
91-
PROVIDE(MachineExternal = DefaultHandler);
38+
/* Default interrupt trap entry point. When vectored trap mode is enabled,
39+
the riscv-rt crate provides an implementation of this function, which saves caller saved
40+
registers, calls the the DefaultHandler ISR, restores caller saved registers and returns.
41+
Note, however, that this provided implementation cannot be overwritten. We use PROVIDE
42+
to avoid compilation errors in direct mode, not to allow users to overwrite the symbol. */
43+
PROVIDE(_start_DefaultHandler_trap = _start_trap);
44+
45+
${INCLUDE_LINKER_FILES}
46+
47+
PROVIDE(_stext = ORIGIN(REGION_TEXT));
48+
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
49+
PROVIDE(_max_hart_id = 0);
50+
PROVIDE(_hart_stack_size = 2K);
51+
PROVIDE(_heap_size = 0);
9252

9353
SECTIONS
9454
{

tests/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ edition = "2021"
77
riscv = { path = "../riscv", version = "0.13.0" }
88
riscv-rt = { path = "../riscv-rt", version = "0.14.0", features = ["no-exceptions", "no-interrupts"]}
99
trybuild = "1.0"
10+
11+
[features]
12+
v-trap = ["riscv-rt/v-trap"]

0 commit comments

Comments
 (0)