Skip to content

Commit ba514e3

Browse files
bors[bot]Norbert Fabritiusadamgreig
authored and
Santiago Cingolani
committed
455: Add zero-init-ram feature r=adamgreig a=inorick Add the 'zero-init-ram' feature that initializes the RAM with zeros during startup. This is normally not necessary but might be required on custom hardware. If this step is skipped on such hardware, reading from memory that was never written to will cause a hard-fault. Co-authored-by: Norbert Fabritius <[email protected]> Co-authored-by: Adam Greig <[email protected]>
1 parent 3253d23 commit ba514e3

File tree

2 files changed

+351
-0
lines changed

2 files changed

+351
-0
lines changed

cortex-m-rt/ci/script.sh

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/usr/bin/env bash
2+
3+
set -euxo pipefail
4+
5+
main() {
6+
cargo check --target "$TARGET"
7+
8+
cargo check --target "$TARGET" --features device
9+
10+
# A `critical_section` implementation is always needed.
11+
needed_features=cortex-m/critical-section-single-core
12+
13+
if [ "$TARGET" = x86_64-unknown-linux-gnu ] && [ "$TRAVIS_RUST_VERSION" = stable ]; then
14+
( cd macros && cargo check && cargo test )
15+
16+
cargo test --features "device,${needed_features}" --test compiletest
17+
fi
18+
19+
local examples=(
20+
alignment
21+
divergent-default-handler
22+
divergent-exception
23+
entry-static
24+
main
25+
minimal
26+
override-exception
27+
pre_init
28+
qemu
29+
state
30+
unsafe-default-handler
31+
unsafe-entry
32+
unsafe-exception
33+
unsafe-hard-fault
34+
)
35+
local fail_examples=(
36+
data_overflow
37+
)
38+
local linkers=(
39+
# Link with arm-none-eabi-ld
40+
"-C linker=arm-none-eabi-ld"
41+
# Link with arm-none-eabi-gcc, requires -nostartfiles
42+
"-C linker=arm-none-eabi-gcc -C link-arg=-nostartfiles"
43+
# Link with rust-lld (default)
44+
""
45+
)
46+
if [ "$TARGET" != x86_64-unknown-linux-gnu ]; then
47+
# Only test on stable and nightly, not MSRV.
48+
if [ "$TRAVIS_RUST_VERSION" = stable ] || [ "$TRAVIS_RUST_VERSION" = nightly ]; then
49+
RUSTDOCFLAGS="-Cpanic=abort" cargo test --features "${needed_features}" --doc
50+
fi
51+
52+
for linker in "${linkers[@]}"; do
53+
for ex in "${examples[@]}"; do
54+
cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" -- $linker
55+
cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" --release -- $linker
56+
done
57+
for ex in "${fail_examples[@]}"; do
58+
! cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" -- $linker
59+
! cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" --release -- $linker
60+
done
61+
cargo rustc --target "$TARGET" --example device --features "device,${needed_features}" -- $linker
62+
cargo rustc --target "$TARGET" --example device --features "device,${needed_features}" --release -- $linker
63+
64+
cargo rustc --target "$TARGET" --example minimal --features "set-sp,${needed_features}" -- $linker
65+
cargo rustc --target "$TARGET" --example minimal --features "set-sp,${needed_features}" --release -- $linker
66+
cargo rustc --target "$TARGET" --example minimal --features "zero-init-ram,${needed_features}" -- $linker
67+
cargo rustc --target "$TARGET" --example minimal --features "zero-init-ram,${needed_features}" --release -- $linker
68+
cargo rustc --target "$TARGET" --example minimal --features "set-vtor,${needed_features}" -- $linker
69+
cargo rustc --target "$TARGET" --example minimal --features "set-vtor,${needed_features}" --release -- $linker
70+
done
71+
fi
72+
73+
case $TARGET in
74+
thumbv6m-none-eabi|thumbv7m-none-eabi)
75+
for linker in "${linkers[@]}"; do
76+
env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \
77+
--target "$TARGET" --features "${needed_features}" --example qemu | grep "x = 42"
78+
env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \
79+
--target "$TARGET" --features "${needed_features}" --example qemu --release | grep "x = 42"
80+
done
81+
82+
;;
83+
esac
84+
}
85+
86+
main

cortex-m-rt/link.x.in

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
/* # Developer notes
2+
3+
- Symbols that start with a double underscore (__) are considered "private"
4+
5+
- Symbols that start with a single underscore (_) are considered "semi-public"; they can be
6+
overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" {
7+
static mut __sbss }`).
8+
9+
- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a
10+
symbol if not dropped if it appears in or near the front of the linker arguments and "it's not
11+
needed" by any of the preceding objects (linker arguments)
12+
13+
- `PROVIDE` is used to provide default values that can be overridden by a user linker script
14+
15+
- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and*
16+
the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization
17+
routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see
18+
"Address (..) is out of bounds" in the disassembly produced by `objdump`.
19+
*/
20+
21+
/* Provides information about the memory layout of the device */
22+
/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */
23+
INCLUDE memory.x
24+
25+
/* # Entry point = reset vector */
26+
EXTERN(__RESET_VECTOR);
27+
EXTERN(Reset);
28+
ENTRY(Reset);
29+
30+
/* # Exception vectors */
31+
/* This is effectively weak aliasing at the linker level */
32+
/* The user can override any of these aliases by defining the corresponding symbol themselves (cf.
33+
the `exception!` macro) */
34+
EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */
35+
36+
EXTERN(DefaultHandler);
37+
38+
PROVIDE(NonMaskableInt = DefaultHandler);
39+
EXTERN(HardFaultTrampoline);
40+
PROVIDE(MemoryManagement = DefaultHandler);
41+
PROVIDE(BusFault = DefaultHandler);
42+
PROVIDE(UsageFault = DefaultHandler);
43+
PROVIDE(SecureFault = DefaultHandler);
44+
PROVIDE(SVCall = DefaultHandler);
45+
PROVIDE(DebugMonitor = DefaultHandler);
46+
PROVIDE(PendSV = DefaultHandler);
47+
PROVIDE(SysTick = DefaultHandler);
48+
49+
PROVIDE(DefaultHandler = DefaultHandler_);
50+
PROVIDE(HardFault = HardFault_);
51+
52+
/* # Interrupt vectors */
53+
EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */
54+
55+
/* # Pre-initialization function */
56+
/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function,
57+
then the function this points to will be called before the RAM is initialized. */
58+
PROVIDE(__pre_init = DefaultPreInit);
59+
60+
/* # Sections */
61+
SECTIONS
62+
{
63+
PROVIDE(_ram_start = ORIGIN(RAM));
64+
PROVIDE(_ram_end = ORIGIN(RAM) + LENGTH(RAM));
65+
PROVIDE(_stack_start = _ram_end);
66+
67+
/* ## Sections in FLASH */
68+
/* ### Vector table */
69+
.vector_table ORIGIN(FLASH) :
70+
{
71+
__vector_table = .;
72+
73+
/* Initial Stack Pointer (SP) value.
74+
* We mask the bottom three bits to force 8-byte alignment.
75+
* Despite having an assert for this later, it's possible that a separate
76+
* linker script could override _stack_start after the assert is checked.
77+
*/
78+
LONG(_stack_start & 0xFFFFFFF8);
79+
80+
/* Reset vector */
81+
KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */
82+
__reset_vector = .;
83+
84+
/* Exceptions */
85+
KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */
86+
__eexceptions = .;
87+
88+
/* Device specific interrupts */
89+
KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */
90+
} > FLASH
91+
92+
PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table));
93+
94+
/* ### .text */
95+
.text _stext :
96+
{
97+
__stext = .;
98+
*(.Reset);
99+
100+
*(.text .text.*);
101+
102+
/* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`,
103+
so must be placed close to it. */
104+
*(.HardFaultTrampoline);
105+
*(.HardFault.*);
106+
107+
. = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */
108+
__etext = .;
109+
} > FLASH
110+
111+
/* ### .rodata */
112+
.rodata : ALIGN(4)
113+
{
114+
. = ALIGN(4);
115+
__srodata = .;
116+
*(.rodata .rodata.*);
117+
118+
/* 4-byte align the end (VMA) of this section.
119+
This is required by LLD to ensure the LMA of the following .data
120+
section will have the correct alignment. */
121+
. = ALIGN(4);
122+
__erodata = .;
123+
} > FLASH
124+
125+
/* ## Sections in RAM */
126+
/* ### .data */
127+
.data : ALIGN(4)
128+
{
129+
. = ALIGN(4);
130+
__sdata = .;
131+
*(.data .data.*);
132+
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
133+
} > RAM AT>FLASH
134+
/* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to
135+
* use the .data loading mechanism by pushing __edata. Note: do not change
136+
* output region or load region in those user sections! */
137+
. = ALIGN(4);
138+
__edata = .;
139+
140+
/* LMA of .data */
141+
__sidata = LOADADDR(.data);
142+
143+
/* ### .gnu.sgstubs
144+
This section contains the TrustZone-M veneers put there by the Arm GNU linker. */
145+
/* Security Attribution Unit blocks must be 32 bytes aligned. */
146+
/* Note that this pads the FLASH usage to 32 byte alignment. */
147+
.gnu.sgstubs : ALIGN(32)
148+
{
149+
. = ALIGN(32);
150+
__veneer_base = .;
151+
*(.gnu.sgstubs*)
152+
. = ALIGN(32);
153+
} > FLASH
154+
/* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are
155+
* always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol.
156+
*/
157+
. = ALIGN(32);
158+
__veneer_limit = .;
159+
160+
/* ### .bss */
161+
.bss (NOLOAD) : ALIGN(4)
162+
{
163+
. = ALIGN(4);
164+
__sbss = .;
165+
*(.bss .bss.*);
166+
*(COMMON); /* Uninitialized C statics */
167+
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
168+
} > RAM
169+
/* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to
170+
* use the .bss zeroing mechanism by pushing __ebss. Note: do not change
171+
* output region or load region in those user sections! */
172+
. = ALIGN(4);
173+
__ebss = .;
174+
175+
/* ### .uninit */
176+
.uninit (NOLOAD) : ALIGN(4)
177+
{
178+
. = ALIGN(4);
179+
__suninit = .;
180+
*(.uninit .uninit.*);
181+
. = ALIGN(4);
182+
__euninit = .;
183+
} > RAM
184+
185+
/* Place the heap right after `.uninit` in RAM */
186+
PROVIDE(__sheap = __euninit);
187+
188+
/* ## .got */
189+
/* Dynamic relocations are unsupported. This section is only used to detect relocatable code in
190+
the input files and raise an error if relocatable code is found */
191+
.got (NOLOAD) :
192+
{
193+
KEEP(*(.got .got.*));
194+
}
195+
196+
/* ## Discarded sections */
197+
/DISCARD/ :
198+
{
199+
/* Unused exception related info that only wastes space */
200+
*(.ARM.exidx);
201+
*(.ARM.exidx.*);
202+
*(.ARM.extab.*);
203+
}
204+
}
205+
206+
/* Do not exceed this mark in the error messages below | */
207+
/* # Alignment checks */
208+
ASSERT(ORIGIN(FLASH) % 4 == 0, "
209+
ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned");
210+
211+
ASSERT(ORIGIN(RAM) % 4 == 0, "
212+
ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned");
213+
214+
ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, "
215+
BUG(cortex-m-rt): .data is not 4-byte aligned");
216+
217+
ASSERT(__sidata % 4 == 0, "
218+
BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned");
219+
220+
ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, "
221+
BUG(cortex-m-rt): .bss is not 4-byte aligned");
222+
223+
ASSERT(__sheap % 4 == 0, "
224+
BUG(cortex-m-rt): start of .heap is not 4-byte aligned");
225+
226+
ASSERT(_stack_start % 8 == 0, "
227+
ERROR(cortex-m-rt): stack start address is not 8-byte aligned.
228+
If you have set _stack_start, check it's set to an address which is a multiple of 8 bytes.
229+
If you haven't, stack starts at the end of RAM by default. Check that both RAM
230+
origin and length are set to multiples of 8 in the `memory.x` file.");
231+
232+
/* # Position checks */
233+
234+
/* ## .vector_table */
235+
ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, "
236+
BUG(cortex-m-rt): the reset vector is missing");
237+
238+
ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, "
239+
BUG(cortex-m-rt): the exception vectors are missing");
240+
241+
ASSERT(SIZEOF(.vector_table) > 0x40, "
242+
ERROR(cortex-m-rt): The interrupt vectors are missing.
243+
Possible solutions, from most likely to less likely:
244+
- Link to a svd2rust generated device crate
245+
- Check that you actually use the device/hal/bsp crate in your code
246+
- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency
247+
may be enabling it)
248+
- Supply the interrupt handlers yourself. Check the documentation for details.");
249+
250+
/* ## .text */
251+
ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, "
252+
ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section
253+
Set _stext to an address greater than the end of .vector_table (See output of `nm`)");
254+
255+
ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), "
256+
ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory.
257+
Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'");
258+
259+
/* # Other checks */
260+
ASSERT(SIZEOF(.got) == 0, "
261+
ERROR(cortex-m-rt): .got section detected in the input object files
262+
Dynamic relocations are not supported. If you are linking to C code compiled using
263+
the 'cc' crate then modify your build script to compile the C code _without_
264+
the -fPIC flag. See the documentation of the `cc::Build.pic` method for details.");
265+
/* Do not exceed this mark in the error messages above | */

0 commit comments

Comments
 (0)