diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 2393f742..e5700fe4 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -55,6 +55,8 @@ jobs: run: RUSTFLAGS="-C link-arg=-Tmemory.x -C link-arg=-Tlink.x" cargo build --package tests-build --target ${{ matrix.target }} --example ${{ matrix.example }} --features device - name: Build (include memory.x) run: RUSTFLAGS="-C link-arg=-Tdevice.x -C link-arg=-Tlink.x" cargo build --package tests-build --target ${{ matrix.target }} --example ${{ matrix.example }} --features memory + - name: Build (include memory.x, use trap region) + run: RUSTFLAGS="-C link-arg=-Tdevice.x -C link-arg=-Tlink.x" cargo build --package tests-build --target ${{ matrix.target }} --example ${{ matrix.example }} --features memory,trap-region - name: Build (include device.x and memory.x) run: RUSTFLAGS="-C link-arg=-Tlink.x" cargo build --package tests-build --target ${{ matrix.target }} --example ${{ matrix.example }} --features device,memory diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index cda604d6..d8015d2a 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -18,6 +18,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - In multi-hart targets, the hart ID is now validated earlier in the boot process. - General purpose registers are no longer zeroed, as this is not strictly necessary. This aligns with the `cortex-m-rt` crate. +- Better organization of the `.trap` section: + 1. `_trap_vector` (if `v-trap` is enabled). + 2. `_start_trap` (defaults to `_default_start_trap`). + 3. `_start_INTERRUPT_trap` routines (if `v-trap` is enabled). + 4. `_start_DefaultHandler_trap` and `_continue_trap` (if `v-trap` is enabled). + 5. `_start_trap_rust`. + 6. Other code in `.trap` section (usually, none) ### Fixed diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index 761cd52b..a79d856e 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -22,6 +22,7 @@ targets = [ [build-dependencies] riscv-target-parser = { path = "../riscv-target-parser", version = "0.1.2" } +minilink = "0.2" [dependencies] riscv = { path = "../riscv", version = "0.14.0" } @@ -41,3 +42,4 @@ no-interrupts = [] no-exceptions = [] device = [] memory = [] +trap-region = [] diff --git a/riscv-rt/build.rs b/riscv-rt/build.rs index e1da2d15..0e8ceab4 100644 --- a/riscv-rt/build.rs +++ b/riscv-rt/build.rs @@ -1,49 +1,19 @@ // NOTE: Adapted from cortex-m/build.rs -use riscv_target_parser::RiscvTarget; -use std::{env, fs, io, path::PathBuf}; +use riscv_target_parser::{RiscvTarget, Width}; +use std::env; // List of all possible RISC-V configurations to check for in risv-rt const RISCV_CFG: [&str; 4] = ["riscvi", "riscvm", "riscvf", "riscvd"]; -fn add_linker_script(arch_width: u32) -> io::Result<()> { - // Read the file to a string and replace all occurrences of ${ARCH_WIDTH} with the arch width - let mut content = fs::read_to_string("link.x.in")?; - content = content.replace("${ARCH_WIDTH}", &arch_width.to_string()); - - // Get target-dependent linker configuration and replace ${INCLUDE_LINKER_FILES} with it - let mut include_content = String::new(); - - // If no-exceptions is disabled, include the exceptions.x files - if env::var_os("CARGO_FEATURE_NO_EXCEPTIONS").is_none() { - let exceptions_content = fs::read_to_string("exceptions.x")?; - include_content.push_str(&(exceptions_content + "\n")); - } - // If no-interrupts is disabled, include the interrupts.x files - if env::var_os("CARGO_FEATURE_NO_INTERRUPTS").is_none() { - let interrupts_content = fs::read_to_string("interrupts.x")?; - include_content.push_str(&(interrupts_content + "\n")); - } - // If device is enabled, include the device.x file (usually, provided by PACs) - if env::var_os("CARGO_FEATURE_DEVICE").is_some() { - include_content.push_str("/* Device-specific exception and interrupt handlers */\n"); - include_content.push_str("INCLUDE device.x\n"); +fn add_linker_script(arch_width: Width) { + // `CARGO_CFG_TARGET_POINTER_WIDTH` technically be used, but instruction + // alignment and pointer width aren't necessarily the same things. + unsafe { + std::env::set_var("CARGO_CFG_ARCH_WIDTH", arch_width.to_string()); } - // If memory is enabled, include the memory.x file (usually, provided by BSPs) - if env::var_os("CARGO_FEATURE_MEMORY").is_some() { - include_content.push_str("/* Device-specific memory layout */\n"); - include_content.push_str("INCLUDE memory.x\n"); - } - - content = content.replace("${INCLUDE_LINKER_FILES}", &include_content); - // Put the linker script somewhere the linker can find it - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - fs::write(out_dir.join("link.x"), content)?; - println!("cargo:rustc-link-search={}", out_dir.display()); - println!("cargo:rerun-if-changed=link.x"); - - Ok(()) + minilink::register_template("./link.x.in", "link.x"); } fn main() { @@ -86,6 +56,7 @@ fn main() { println!("cargo:rustc-cfg={flag}"); } } - add_linker_script(width.into()).unwrap(); + + add_linker_script(width); } } diff --git a/riscv-rt/exceptions.x b/riscv-rt/exceptions.x deleted file mode 100644 index e9d3f8fb..00000000 --- a/riscv-rt/exceptions.x +++ /dev/null @@ -1,23 +0,0 @@ -/* # EXCEPTION HANDLERS DESCRIBED IN THE STANDARD RISC-V ISA - - If the `no-exceptions` feature is DISABLED, this file will be included in link.x.in. - If the `no-exceptions` feature is ENABLED, this file will be ignored. -*/ - -/* It is possible to define a special handler for each exception type. - By default, all exceptions are handled by ExceptionHandler. However, - users can override these alias by defining the symbol themselves */ -PROVIDE(InstructionMisaligned = ExceptionHandler); -PROVIDE(InstructionFault = ExceptionHandler); -PROVIDE(IllegalInstruction = ExceptionHandler); -PROVIDE(Breakpoint = ExceptionHandler); -PROVIDE(LoadMisaligned = ExceptionHandler); -PROVIDE(LoadFault = ExceptionHandler); -PROVIDE(StoreMisaligned = ExceptionHandler); -PROVIDE(StoreFault = ExceptionHandler); -PROVIDE(UserEnvCall = ExceptionHandler); -PROVIDE(SupervisorEnvCall = ExceptionHandler); -PROVIDE(MachineEnvCall = ExceptionHandler); -PROVIDE(InstructionPageFault = ExceptionHandler); -PROVIDE(LoadPageFault = ExceptionHandler); -PROVIDE(StorePageFault = ExceptionHandler); diff --git a/riscv-rt/interrupts.x b/riscv-rt/interrupts.x deleted file mode 100644 index 2440be77..00000000 --- a/riscv-rt/interrupts.x +++ /dev/null @@ -1,25 +0,0 @@ -/* # CORE INTERRUPT HANDLERS DESCRIBED IN THE STANDARD RISC-V ISA - - If the `no-interrupts` feature is DISABLED, this file will be included in link.x.in. - If the `no-interrupts` feature is ENABLED, this file will be ignored. -*/ - -/* It is possible to define a special handler for each interrupt type. - By default, all interrupts are handled by DefaultHandler. However, users can - override these alias by defining the symbol themselves */ -PROVIDE(SupervisorSoft = DefaultHandler); -PROVIDE(MachineSoft = DefaultHandler); -PROVIDE(SupervisorTimer = DefaultHandler); -PROVIDE(MachineTimer = DefaultHandler); -PROVIDE(SupervisorExternal = DefaultHandler); -PROVIDE(MachineExternal = DefaultHandler); - -/* When vectored trap mode is enabled, each interrupt source must implement its own - trap entry point. By default, all interrupts start in _DefaultHandler_trap. - However, users can override these alias by defining the symbol themselves */ -PROVIDE(_start_SupervisorSoft_trap = _start_DefaultHandler_trap); -PROVIDE(_start_MachineSoft_trap = _start_DefaultHandler_trap); -PROVIDE(_start_SupervisorTimer_trap = _start_DefaultHandler_trap); -PROVIDE(_start_MachineTimer_trap = _start_DefaultHandler_trap); -PROVIDE(_start_SupervisorExternal_trap = _start_DefaultHandler_trap); -PROVIDE(_start_MachineExternal_trap = _start_DefaultHandler_trap); diff --git a/riscv-rt/link.x.in b/riscv-rt/link.x.in index 0ef9bb02..2baf6442 100644 --- a/riscv-rt/link.x.in +++ b/riscv-rt/link.x.in @@ -12,13 +12,9 @@ - `PROVIDE` is used to provide default values that can be overridden by a user linker script -- In this linker script, you may find symbols that look like `${...}` (e.g., `${ARCH_WIDTH}`). - These are wildcards used by the `build.rs` script to adapt to different target particularities. - Check `build.rs` for more details about these symbols. - - On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* - the LMA of .data are all `${ARCH_WIDTH}`-byte aligned. These alignments are assumed by the RAM - initialization routine. There's also a second benefit: `${ARCH_WIDTH}`-byte aligned boundaries + the LMA of .data are all `{{ cfg.arch_width }}`-byte aligned. These alignments are assumed by the RAM + initialization routine. There's also a second benefit: `{{ cfg.arch_width }}`-byte aligned boundaries means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`. */ @@ -67,7 +63,63 @@ PROVIDE(DefaultHandler = abort); to avoid compilation errors in direct mode, not to allow users to overwrite the symbol. */ PROVIDE(_start_DefaultHandler_trap = _start_trap); -${INCLUDE_LINKER_FILES} +{% if not contains(cfg.feature, "no-exceptions") %} +/* # EXCEPTION HANDLERS DESCRIBED IN THE STANDARD RISC-V ISA + + It is possible to define a special handler for each exception type. + By default, all exceptions are handled by ExceptionHandler. However, + users can override these alias by defining the symbol themselves +*/ +PROVIDE(InstructionMisaligned = ExceptionHandler); +PROVIDE(InstructionFault = ExceptionHandler); +PROVIDE(IllegalInstruction = ExceptionHandler); +PROVIDE(Breakpoint = ExceptionHandler); +PROVIDE(LoadMisaligned = ExceptionHandler); +PROVIDE(LoadFault = ExceptionHandler); +PROVIDE(StoreMisaligned = ExceptionHandler); +PROVIDE(StoreFault = ExceptionHandler); +PROVIDE(UserEnvCall = ExceptionHandler); +PROVIDE(SupervisorEnvCall = ExceptionHandler); +PROVIDE(MachineEnvCall = ExceptionHandler); +PROVIDE(InstructionPageFault = ExceptionHandler); +PROVIDE(LoadPageFault = ExceptionHandler); +PROVIDE(StorePageFault = ExceptionHandler); +{% endif %} + +{% if not contains(cfg.feature, "no-interrupts") %} +/* # CORE INTERRUPT HANDLERS DESCRIBED IN THE STANDARD RISC-V ISA + + It is possible to define a special handler for each interrupt type. + By default, all interrupts are handled by DefaultHandler. However, users can + override these alias by defining the symbol themselves +*/ +PROVIDE(SupervisorSoft = DefaultHandler); +PROVIDE(MachineSoft = DefaultHandler); +PROVIDE(SupervisorTimer = DefaultHandler); +PROVIDE(MachineTimer = DefaultHandler); +PROVIDE(SupervisorExternal = DefaultHandler); +PROVIDE(MachineExternal = DefaultHandler); + +/* When vectored trap mode is enabled, each interrupt source must implement its own + trap entry point. By default, all interrupts start in _DefaultHandler_trap. + However, users can override these alias by defining the symbol themselves */ +PROVIDE(_start_SupervisorSoft_trap = _start_DefaultHandler_trap); +PROVIDE(_start_MachineSoft_trap = _start_DefaultHandler_trap); +PROVIDE(_start_SupervisorTimer_trap = _start_DefaultHandler_trap); +PROVIDE(_start_MachineTimer_trap = _start_DefaultHandler_trap); +PROVIDE(_start_SupervisorExternal_trap = _start_DefaultHandler_trap); +PROVIDE(_start_MachineExternal_trap = _start_DefaultHandler_trap); +{% endif %} + +{% if contains(cfg.feature, "device")%} +/* Device-specific exception and interrupt handlers, usually provided by PACs */ +INCLUDE device.x +{% endif %} + +{% if contains(cfg.feature, "memory")%} +/* Device-specific memory layout, usually provided by BSPs */ +INCLUDE memory.x +{% endif %} PROVIDE(_stext = ORIGIN(REGION_TEXT)); PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK)); @@ -75,6 +127,16 @@ PROVIDE(_max_hart_id = 0); PROVIDE(_hart_stack_size = SIZEOF(.stack) / (_max_hart_id + 1)); PROVIDE(_heap_size = 0); +{% set trap_regions %} +. = ALIGN(4); +KEEP(*(.trap.vector)); /* for _trap_vector (vectored mode only) */ +KEEP(*(.trap.start)); /* for _start_trap routine */ +KEEP(*(.trap.start.*)); /* for _start_INTERRUPT_trap routines (vectored mode only) */ +KEEP(*(.trap.continue)); /* for _continue_trap routine (vectored mode only) */ +KEEP(*(.trap.rust)); /* for _start_trap_rust Rust function */ +KEEP(*(.trap .trap.*)); /* Other .trap symbols at the end */ +{% endset %} + SECTIONS { .text.dummy (NOLOAD) : @@ -90,9 +152,10 @@ SECTIONS /* Put reset handler first in .text section so it ends up as the entry */ /* point of the program. */ KEEP(*(.init)); - . = ALIGN(4); - *(.trap); - *(.trap.rust); + + {% if not contains(cfg.feature, "trap-region") %} + {{ trap_regions }} + {% endif %} *(.text.abort); *(.text .text.*); @@ -108,16 +171,23 @@ SECTIONS *(.srodata .srodata.*); *(.rodata .rodata.*); - /* ${ARCH_WIDTH}-byte align the end (VMA) of this section. + /* {{ cfg.arch_width }}-byte align the end (VMA) of this section. This is required by LLD to ensure the LMA of the following .data section will have the correct alignment. */ - . = ALIGN(${ARCH_WIDTH}); + . = ALIGN({{ cfg.arch_width }}); __erodata = .; } > REGION_RODATA - .data : ALIGN(${ARCH_WIDTH}) + {% if contains(cfg.feature, "trap-region") %} + .trap : ALIGN(4) + { + {{ trap_regions }} + } > REGION_TRAP + {% endif %} + + .data : ALIGN({{ cfg.arch_width }}) { - . = ALIGN(${ARCH_WIDTH}); + . = ALIGN({{ cfg.arch_width }}); __sdata = .; /* Must be called __global_pointer$ for linker relaxations to work. */ @@ -130,15 +200,15 @@ SECTIONS /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to * use the .data loading mechanism by pushing __edata. Note: do not change * output region or load region in those user sections! */ - . = ALIGN(${ARCH_WIDTH}); + . = ALIGN({{ cfg.arch_width }}); __edata = .; /* LMA of .data */ __sidata = LOADADDR(.data); - .bss (NOLOAD) : ALIGN(${ARCH_WIDTH}) + .bss (NOLOAD) : ALIGN({{ cfg.arch_width }}) { - . = ALIGN(${ARCH_WIDTH}); + . = ALIGN({{ cfg.arch_width }}); __sbss = .; *(.sbss .sbss.* .bss .bss.*); @@ -147,7 +217,7 @@ SECTIONS /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to * use the .bss zeroing mechanism by pushing __ebss. Note: do not change * output region or load region in those user sections! */ - . = ALIGN(${ARCH_WIDTH}); + . = ALIGN({{ cfg.arch_width }}); __ebss = .; /* fictitious region that represents the memory available for the heap */ @@ -184,8 +254,8 @@ ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, " ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned"); -ASSERT(ORIGIN(REGION_DATA) % ${ARCH_WIDTH} == 0, " -ERROR(riscv-rt): the start of the REGION_DATA must be ${ARCH_WIDTH}-byte aligned"); +ASSERT(ORIGIN(REGION_DATA) % {{ cfg.arch_width }} == 0, " +ERROR(riscv-rt): the start of the REGION_DATA must be {{ cfg.arch_width }}-byte aligned"); ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, " ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned"); @@ -196,14 +266,14 @@ ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned"); ASSERT(_stext % 4 == 0, " ERROR(riscv-rt): `_stext` must be 4-byte aligned"); -ASSERT(__sdata % ${ARCH_WIDTH} == 0 && __edata % ${ARCH_WIDTH} == 0, " -BUG(riscv-rt): .data is not ${ARCH_WIDTH}-byte aligned"); +ASSERT(__sdata % {{ cfg.arch_width }} == 0 && __edata % {{ cfg.arch_width }} == 0, " +BUG(riscv-rt): .data is not {{ cfg.arch_width }}-byte aligned"); -ASSERT(__sidata % ${ARCH_WIDTH} == 0, " -BUG(riscv-rt): the LMA of .data is not ${ARCH_WIDTH}-byte aligned"); +ASSERT(__sidata % {{ cfg.arch_width }} == 0, " +BUG(riscv-rt): the LMA of .data is not {{ cfg.arch_width }}-byte aligned"); -ASSERT(__sbss % ${ARCH_WIDTH} == 0 && __ebss % ${ARCH_WIDTH} == 0, " -BUG(riscv-rt): .bss is not ${ARCH_WIDTH}-byte aligned"); +ASSERT(__sbss % {{ cfg.arch_width }} == 0 && __ebss % {{ cfg.arch_width }} == 0, " +BUG(riscv-rt): .bss is not {{ cfg.arch_width }}-byte aligned"); ASSERT(__sheap % 4 == 0, " BUG(riscv-rt): start of .heap is not 4-byte aligned"); diff --git a/riscv-rt/macros/src/lib.rs b/riscv-rt/macros/src/lib.rs index dc38e997..97d443c1 100644 --- a/riscv-rt/macros/src/lib.rs +++ b/riscv-rt/macros/src/lib.rs @@ -518,8 +518,8 @@ pub fn default_start_trap(_input: TokenStream) -> TokenStream { format!( r#" core::arch::global_asm!( -".section .trap, \"ax\" -.align 4 /* Alignment required for xtvec */ +".section .trap.start, \"ax\" +.balign 4 /* Alignment required for xtvec */ .global _default_start_trap _default_start_trap: addi sp, sp, - {trap_size} * {width} @@ -557,16 +557,15 @@ pub fn vectored_interrupt_trap(_input: TokenStream) -> TokenStream { let instructions = format!( r#" core::arch::global_asm!( -".section .trap, \"ax\" +".section .trap.continue, \"ax\" -.align 4 +.balign 4 .global _start_DefaultHandler_trap _start_DefaultHandler_trap: addi sp, sp, -{trap_size} * {width} // allocate space for trap frame {store_start} // store trap partially (only register a0) la a0, DefaultHandler // load interrupt handler address into a0 -.align 4 .global _continue_interrupt_trap _continue_interrupt_trap: {store_continue} // store trap partially (all registers except a0) @@ -685,10 +684,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { /// } /// ``` pub fn core_interrupt(args: TokenStream, input: TokenStream) -> TokenStream { - let arch = if cfg!(feature = "v-trap") { - RiscvArch::try_from_env() - } else { - None + let arch = match () { + #[cfg(feature = "v-trap")] + () => RiscvArch::try_from_env(), + #[cfg(not(feature = "v-trap"))] + () => None, }; trap(args, input, RiscvPacItem::CoreInterrupt, arch) } @@ -746,13 +746,14 @@ fn trap( let export_name = format!("{int_ident:#}"); let start_trap = match arch { + #[cfg(feature = "v-trap")] Some(arch) => { let trap = start_interrupt_trap(int_ident, arch); quote! { #trap } } - None => proc_macro2::TokenStream::new(), + _ => proc_macro2::TokenStream::new(), }; let pac_trait = pac_item.impl_trait(); @@ -772,6 +773,7 @@ fn trap( .into() } +#[cfg(feature = "v-trap")] fn start_interrupt_trap(ident: &syn::Ident, arch: RiscvArch) -> proc_macro2::TokenStream { let interrupt = ident.to_string(); let width = arch.width(); @@ -780,9 +782,10 @@ fn start_interrupt_trap(ident: &syn::Ident, arch: RiscvArch) -> proc_macro2::Tok let instructions = format!( r#" +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] core::arch::global_asm!( - ".section .trap, \"ax\" - .align 2 + ".section .trap.start.{interrupt}, \"ax\" + .balign 4 .global _start_{interrupt}_trap _start_{interrupt}_trap: addi sp, sp, -{trap_size} * {width} // allocate space for trap frame diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index c7af5ed7..dd15774a 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -532,6 +532,17 @@ //! because when booting from elf, U-boot passes `argc` and `argv`. This feature also implies `single-hart`. //! The only way to get boot-hart is through fdt, so other harts initialization is up to you. //! +//! ## `trap-region` +//! +//! Adds a dedicated trap memory region, `REGION_TRAP`, for placing `.trap` sections into. Enabling +//! this feature and adding `REGION_ALIAS("REGION_TRAP", RAM);` to `memory.x` would for example place +//! it in `RAM`. +//! +//! `REGION_TEXT` is usually placed in flash memory with a cache in front. Having a separate trap +//! memory region makes it possible to always store interrupt and exceptions handlers in RAM, +//! effectively bypassing cache contention and variable trap latency at the cost of increased RAM +//! usage. +//! //! [attr-entry]: attr.entry.html //! [attr-exception]: attr.exception.html //! [attr-external-interrupt]: attr.external_interrupt.html diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 1bdbb9b5..97233feb 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Use `cfg(any(target_arch = "riscv32", target_arch = "riscv64"))` instead of `cfg(riscv)`. +- `riscv::pac_enum(unsafe CoreInterrupt)` now locates the vector table at the `.trap.vector` + section instead of `.trap`. ### Removed diff --git a/riscv/macros/src/lib.rs b/riscv/macros/src/lib.rs index c03f3c43..5f4bf8f3 100644 --- a/riscv/macros/src/lib.rs +++ b/riscv/macros/src/lib.rs @@ -282,7 +282,7 @@ impl PacEnumItem { r#" #[cfg(all(feature = "v-trap", any(target_arch = "riscv32", target_arch = "riscv64")))] core::arch::global_asm!(" - .section .trap, \"ax\" + .section .trap.vector, \"ax\" .global _vector_table .type _vector_table, @function diff --git a/tests-build/Cargo.toml b/tests-build/Cargo.toml index 4798fa37..ebaa5baa 100644 --- a/tests-build/Cargo.toml +++ b/tests-build/Cargo.toml @@ -8,6 +8,9 @@ panic-halt = "1.0" riscv = { path = "../riscv" } riscv-rt = { path = "../riscv-rt" } +[build-dependencies] +minilink = "0.2" + [features] pre-init = ["riscv-rt/pre-init"] single-hart = ["riscv-rt/single-hart"] @@ -16,3 +19,4 @@ device = ["riscv-rt/device"] memory = ["riscv-rt/memory"] no-exceptions = ["riscv-rt/no-exceptions"] no-interrupts = ["riscv-rt/no-interrupts"] +trap-region = ["riscv-rt/trap-region"] diff --git a/tests-build/build.rs b/tests-build/build.rs index 0a4ea37e..dea3e61e 100644 --- a/tests-build/build.rs +++ b/tests-build/build.rs @@ -1,22 +1,4 @@ -use std::{env, fs::File, io::Write, path::PathBuf}; - fn main() { - // Put device.x somewhere the linker can find it - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("device.x")) - .unwrap() - .write_all(include_bytes!("device.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); - println!("cargo:rerun-if-changed=device.x"); - - // Put memory.x somewhere the linker can find it - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); - println!("cargo:rerun-if-changed=memory.x"); - - println!("cargo:rerun-if-changed=build.rs"); + minilink::register_template("device.x", "device.x"); + minilink::register_template("memory.x", "memory.x"); } diff --git a/tests-build/memory.x b/tests-build/memory.x index 0abe00d5..9b799a47 100644 --- a/tests-build/memory.x +++ b/tests-build/memory.x @@ -10,3 +10,7 @@ REGION_ALIAS("REGION_DATA", RAM); REGION_ALIAS("REGION_BSS", RAM); REGION_ALIAS("REGION_HEAP", RAM); REGION_ALIAS("REGION_STACK", RAM); + +{% if contains(cfg.feature, "trap-region") %} +REGION_ALIAS("REGION_TRAP", RAM); +{% endif %}