Skip to content

Commit 0ea032e

Browse files
committed
cortex-m-rt: Allow custom memory region names
Adds support for environment variables which allow the user to use their own memory region names in memory.x, instead of FLASH and/or RAM.
1 parent 6d566b2 commit 0ea032e

File tree

4 files changed

+73
-25
lines changed

4 files changed

+73
-25
lines changed

cortex-m-rt/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ cortex-m-rt-macros = { path = "macros", version = "=0.7.5" }
2525
cortex-m = { version = "0.7.4", path = "../cortex-m" }
2626
panic-halt = "0.2.0"
2727
cortex-m-semihosting = { path = "../cortex-m-semihosting" }
28+
far = "0.2.1"
2829

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

53+
[build-dependencies]
54+
far = "0.2.1"
55+
5256
[package.metadata.docs.rs]
5357
features = ["device"]

cortex-m-rt/build.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1+
use far::{find, Render};
12
use std::fs::File;
23
use std::io::Write;
34
use std::path::{Path, PathBuf};
45
use std::{env, ffi::OsStr};
56

7+
const FLASH_REGION_ENV: &str = "CORTEX_M_RT_FLASH_REGION";
8+
const RAM_REGION_ENV: &str = "CORTEX_M_RT_RAM_REGION";
9+
10+
#[derive(Render)]
11+
struct LinkXReplacements {
12+
flash_region: String,
13+
ram_region: String,
14+
}
15+
616
fn main() {
717
let mut target = env::var("TARGET").unwrap();
818

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

1929
// Put the linker script somewhere the linker can find it
2030
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
21-
let link_x = include_bytes!("link.x.in");
31+
let link_x = include_str!("link.x.in");
32+
33+
// Replace regions in the linker script with the user's
34+
// specified region names, or defaults if not specified
35+
let tmpl = find::<_, LinkXReplacements>(link_x).unwrap();
36+
let mut replacements = LinkXReplacements {
37+
flash_region: "FLASH".to_owned(),
38+
ram_region: "RAM".to_owned(),
39+
};
40+
if let Ok(region) = env::var(FLASH_REGION_ENV) {
41+
println!("cargo:rerun-if-env-changed={}", FLASH_REGION_ENV);
42+
replacements.flash_region = region;
43+
};
44+
if let Ok(region) = env::var(RAM_REGION_ENV) {
45+
println!("cargo:rerun-if-env-changed={}", RAM_REGION_ENV);
46+
replacements.ram_region = region;
47+
};
48+
let link_x = tmpl.replace(&replacements);
49+
2250
let mut f = if env::var_os("CARGO_FEATURE_DEVICE").is_some() {
2351
let mut f = File::create(out.join("link.x")).unwrap();
2452

25-
f.write_all(link_x).unwrap();
53+
f.write_all(link_x.as_bytes()).unwrap();
2654

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

cortex-m-rt/link.x.in

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ PROVIDE(__pre_init = DefaultPreInit);
6060
/* # Sections */
6161
SECTIONS
6262
{
63-
PROVIDE(_ram_start = ORIGIN(RAM));
64-
PROVIDE(_ram_end = ORIGIN(RAM) + LENGTH(RAM));
63+
PROVIDE(_ram_start = ORIGIN({{ram_region}}));
64+
PROVIDE(_ram_end = ORIGIN({{ram_region}}) + LENGTH({{ram_region}}));
6565
PROVIDE(_stack_start = _ram_end);
6666

67-
/* ## Sections in FLASH */
67+
/* ## Sections in {{flash_region}} */
6868
/* ### Vector table */
69-
.vector_table ORIGIN(FLASH) :
69+
.vector_table ORIGIN({{flash_region}}) :
7070
{
7171
__vector_table = .;
7272

@@ -87,7 +87,7 @@ SECTIONS
8787

8888
/* Device specific interrupts */
8989
KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */
90-
} > FLASH
90+
} > {{flash_region}}
9191

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

@@ -106,7 +106,7 @@ SECTIONS
106106

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

111111
/* ### .rodata */
112112
.rodata : ALIGN(4)
@@ -120,17 +120,17 @@ SECTIONS
120120
section will have the correct alignment. */
121121
. = ALIGN(4);
122122
__erodata = .;
123-
} > FLASH
123+
} > {{flash_region}}
124124

125-
/* ## Sections in RAM */
125+
/* ## Sections in {{ram_region}} */
126126
/* ### .data */
127127
.data : ALIGN(4)
128128
{
129129
. = ALIGN(4);
130130
__sdata = .;
131131
*(.data .data.*);
132132
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
133-
} > RAM AT>FLASH
133+
} > {{ram_region}} AT>{{flash_region}}
134134
/* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to
135135
* use the .data loading mechanism by pushing __edata. Note: do not change
136136
* output region or load region in those user sections! */
@@ -143,14 +143,14 @@ SECTIONS
143143
/* ### .gnu.sgstubs
144144
This section contains the TrustZone-M veneers put there by the Arm GNU linker. */
145145
/* Security Attribution Unit blocks must be 32 bytes aligned. */
146-
/* Note that this pads the FLASH usage to 32 byte alignment. */
146+
/* Note that this pads the {{flash_region}} usage to 32 byte alignment. */
147147
.gnu.sgstubs : ALIGN(32)
148148
{
149149
. = ALIGN(32);
150150
__veneer_base = .;
151151
*(.gnu.sgstubs*)
152152
. = ALIGN(32);
153-
} > FLASH
153+
} > {{flash_region}}
154154
/* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are
155155
* always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol.
156156
*/
@@ -165,7 +165,7 @@ SECTIONS
165165
*(.bss .bss.*);
166166
*(COMMON); /* Uninitialized C statics */
167167
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
168-
} > RAM
168+
} > {{ram_region}}
169169
/* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to
170170
* use the .bss zeroing mechanism by pushing __ebss. Note: do not change
171171
* output region or load region in those user sections! */
@@ -180,12 +180,12 @@ SECTIONS
180180
*(.uninit .uninit.*);
181181
. = ALIGN(4);
182182
__euninit = .;
183-
} > RAM
183+
} > {{ram_region}}
184184

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

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

@@ -209,11 +209,11 @@ SECTIONS
209209

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

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

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

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

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

280280
/* # Other checks */
281281
ASSERT(SIZEOF(.got) == 0, "

cortex-m-rt/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@
4949
//! program will be placed in the `FLASH` region, whereas the `.bss` and `.data` sections, as well
5050
//! as the heap, will be placed in the `RAM` region.
5151
//!
52+
//! The region names `FLASH` and `RAM` are defaults, but different names can be used if
53+
//! desired. See the [Advanced Usage](#custom-memory-region-names) section for
54+
//! details. Throughout the rest of this documentation, `FLASH` and `RAM` will be used to
55+
//! indicate the purpose of these memory regions, but their names may be different.
56+
//!
5257
//! ```text
5358
//! /* Linker script for the STM32F103C8T6 */
5459
//! MEMORY
@@ -308,6 +313,17 @@
308313
//! The unmangled `main` symbol must have signature `extern "C" fn() -> !` or its invocation from
309314
//! `Reset` will result in undefined behavior.
310315
//!
316+
//! ## Custom memory region names
317+
//!
318+
//! If an environment variable named `CORTEX_M_RT_FLASH_REGION` is defined, its value will be
319+
//! used instead of `FLASH`. Similarly, if an environment variable named
320+
//! `CORTEX_M_RT_RAM_REGION` is defined, its value will be used instead of `RAM`.
321+
//!
322+
//! This feature can be useful in projects where binary output from two crates (for example a
323+
//! bootloader and an application) will both be loaded into Flash memory, but at different
324+
//! addresses. Using these environment variables allows those crates to share a single
325+
//! `memory.x` file but direct their output to their respective regions.
326+
//!
311327
//! ## Incorporating device specific interrupts
312328
//!
313329
//! This section covers how an external crate can insert device specific interrupt handlers into the

0 commit comments

Comments
 (0)