Skip to content

cortex-m-rt: Allow custom memory region names #601

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cortex-m-rt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ cortex-m-rt-macros = { path = "macros", version = "=0.7.5" }
cortex-m = { version = "0.7.4", path = "../cortex-m" }
panic-halt = "0.2.0"
cortex-m-semihosting = { path = "../cortex-m-semihosting" }
far = "0.2.1"

[target.'cfg(not(target_os = "none"))'.dev-dependencies]
compiletest_rs = "0.11"
Expand All @@ -49,5 +50,8 @@ set-msplim = []
zero-init-ram = []
paint-stack = []

[build-dependencies]
far = "0.2.1"

[package.metadata.docs.rs]
features = ["device"]
34 changes: 31 additions & 3 deletions cortex-m-rt/build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
use far::{find, Render};
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::{env, ffi::OsStr};

const FLASH_REGION_ENV: &str = "CORTEX_M_RT_FLASH_REGION";
const RAM_REGION_ENV: &str = "CORTEX_M_RT_RAM_REGION";

#[derive(Render)]
struct LinkXReplacements {
flash_region: String,
ram_region: String,
}

fn main() {
let mut target = env::var("TARGET").unwrap();

Expand All @@ -18,11 +28,29 @@ fn main() {

// Put the linker script somewhere the linker can find it
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
let link_x = include_bytes!("link.x.in");
let link_x = include_str!("link.x.in");

// Replace regions in the linker script with the user's
// specified region names, or defaults if not specified
let tmpl = find::<_, LinkXReplacements>(link_x).unwrap();
let mut replacements = LinkXReplacements {
flash_region: "FLASH".to_owned(),
ram_region: "RAM".to_owned(),
};
if let Ok(region) = env::var(FLASH_REGION_ENV) {
println!("cargo:rerun-if-env-changed={}", FLASH_REGION_ENV);
replacements.flash_region = region;
};
if let Ok(region) = env::var(RAM_REGION_ENV) {
println!("cargo:rerun-if-env-changed={}", RAM_REGION_ENV);
replacements.ram_region = region;
};
let link_x = tmpl.replace(&replacements);

let mut f = if env::var_os("CARGO_FEATURE_DEVICE").is_some() {
let mut f = File::create(out.join("link.x")).unwrap();

f.write_all(link_x).unwrap();
f.write_all(link_x.as_bytes()).unwrap();

// *IMPORTANT*: The weak aliases (i.e. `PROVIDED`) must come *after* `EXTERN(__INTERRUPTS)`.
// Otherwise the linker will ignore user defined interrupts and always populate the table
Expand All @@ -38,7 +66,7 @@ INCLUDE device.x"#
f
} else {
let mut f = File::create(out.join("link.x")).unwrap();
f.write_all(link_x).unwrap();
f.write_all(link_x.as_bytes()).unwrap();
f
};

Expand Down
44 changes: 22 additions & 22 deletions cortex-m-rt/link.x.in
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ PROVIDE(__pre_init = DefaultPreInit);
/* # Sections */
SECTIONS
{
PROVIDE(_ram_start = ORIGIN(RAM));
PROVIDE(_ram_end = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(_ram_start = ORIGIN({{ram_region}}));
PROVIDE(_ram_end = ORIGIN({{ram_region}}) + LENGTH({{ram_region}}));
PROVIDE(_stack_start = _ram_end);

/* ## Sections in FLASH */
/* ## Sections in {{flash_region}} */
/* ### Vector table */
.vector_table ORIGIN(FLASH) :
.vector_table ORIGIN({{flash_region}}) :
{
__vector_table = .;

Expand All @@ -87,7 +87,7 @@ SECTIONS

/* Device specific interrupts */
KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */
} > FLASH
} > {{flash_region}}

PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table));

Expand All @@ -106,7 +106,7 @@ SECTIONS

. = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */
__etext = .;
} > FLASH
} > {{flash_region}}

/* ### .rodata */
.rodata : ALIGN(4)
Expand All @@ -120,17 +120,17 @@ SECTIONS
section will have the correct alignment. */
. = ALIGN(4);
__erodata = .;
} > FLASH
} > {{flash_region}}

/* ## Sections in RAM */
/* ## Sections in {{ram_region}} */
/* ### .data */
.data : ALIGN(4)
{
. = ALIGN(4);
__sdata = .;
*(.data .data.*);
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
} > RAM AT>FLASH
} > {{ram_region}} AT>{{flash_region}}
/* 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! */
Expand All @@ -143,14 +143,14 @@ SECTIONS
/* ### .gnu.sgstubs
This section contains the TrustZone-M veneers put there by the Arm GNU linker. */
/* Security Attribution Unit blocks must be 32 bytes aligned. */
/* Note that this pads the FLASH usage to 32 byte alignment. */
/* Note that this pads the {{flash_region}} usage to 32 byte alignment. */
.gnu.sgstubs : ALIGN(32)
{
. = ALIGN(32);
__veneer_base = .;
*(.gnu.sgstubs*)
. = ALIGN(32);
} > FLASH
} > {{flash_region}}
/* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are
* always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol.
*/
Expand All @@ -165,7 +165,7 @@ SECTIONS
*(.bss .bss.*);
*(COMMON); /* Uninitialized C statics */
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
} > RAM
} > {{ram_region}}
/* 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! */
Expand All @@ -180,12 +180,12 @@ SECTIONS
*(.uninit .uninit.*);
. = ALIGN(4);
__euninit = .;
} > RAM
} > {{ram_region}}

/* Align `__sheap` and `_stack_end` pointers to 4 bytes */
. = ALIGN(4);

/* Place the heap start and stack end at the end of allocated RAM */
/* Place the heap start and stack end at the end of allocated {{ram_region}} */
PROVIDE(__sheap = .);
PROVIDE(_stack_end = .);

Expand All @@ -209,11 +209,11 @@ SECTIONS

/* Do not exceed this mark in the error messages below | */
/* # Alignment checks */
ASSERT(ORIGIN(FLASH) % 4 == 0, "
ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned");
ASSERT(ORIGIN({{flash_region}}) % 4 == 0, "
ERROR(cortex-m-rt): the start of the {{flash_region}} region must be 4-byte aligned");

ASSERT(ORIGIN(RAM) % 4 == 0, "
ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned");
ASSERT(ORIGIN({{ram_region}}) % 4 == 0, "
ERROR(cortex-m-rt): the start of the {{ram_region}} region must be 4-byte aligned");

ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, "
BUG(cortex-m-rt): .data is not 4-byte aligned");
Expand All @@ -230,7 +230,7 @@ BUG(cortex-m-rt): start of .heap is not 4-byte aligned");
ASSERT(_stack_start % 8 == 0, "
ERROR(cortex-m-rt): stack start address is not 8-byte aligned.
If you have set _stack_start, check it's set to an address which is a multiple of 8 bytes.
If you haven't, stack starts at the end of RAM by default. Check that both RAM
If you haven't, stack starts at the end of {{ram_region}} by default. Check that both {{ram_region}}
origin and length are set to multiples of 8 in the `memory.x` file.");

ASSERT(_stack_end % 4 == 0, "
Expand Down Expand Up @@ -273,9 +273,9 @@ ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, "
ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section
Set _stext to an address greater than the end of .vector_table (See output of `nm`)");

ASSERT(_stext >= ORIGIN(FLASH) && _stext < ORIGIN(FLASH) + LENGTH(FLASH), "
ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory.
Set _stext to an address within the FLASH region.");
ASSERT(_stext >= ORIGIN({{flash_region}}) && _stext < ORIGIN({{flash_region}}) + LENGTH({{flash_region}}), "
ERROR(cortex-m-rt): The .text section must be placed inside the {{flash_region}} memory.
Set _stext to an address within the {{flash_region}} region.");

/* # Other checks */
ASSERT(SIZEOF(.got) == 0, "
Expand Down
16 changes: 16 additions & 0 deletions cortex-m-rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
//! program will be placed in the `FLASH` region, whereas the `.bss` and `.data` sections, as well
//! as the heap, will be placed in the `RAM` region.
//!
//! The region names `FLASH` and `RAM` are defaults, but different names can be used if
//! desired. See the [Advanced Usage](#custom-memory-region-names) section for
//! details. Throughout the rest of this documentation, `FLASH` and `RAM` will be used to
//! indicate the purpose of these memory regions, but their names may be different.
//!
//! ```text
//! /* Linker script for the STM32F103C8T6 */
//! MEMORY
Expand Down Expand Up @@ -308,6 +313,17 @@
//! The unmangled `main` symbol must have signature `extern "C" fn() -> !` or its invocation from
//! `Reset` will result in undefined behavior.
//!
//! ## Custom memory region names
//!
//! If an environment variable named `CORTEX_M_RT_FLASH_REGION` is defined, its value will be
//! used instead of `FLASH`. Similarly, if an environment variable named
//! `CORTEX_M_RT_RAM_REGION` is defined, its value will be used instead of `RAM`.
//!
//! This feature can be useful in projects where binary output from two crates (for example a
//! bootloader and an application) will both be loaded into Flash memory, but at different
//! addresses. Using these environment variables allows those crates to share a single
//! `memory.x` file but direct their output to their respective regions.
//!
//! ## Incorporating device specific interrupts
//!
//! This section covers how an external crate can insert device specific interrupt handlers into the
Expand Down
Loading