Skip to content

Commit be04550

Browse files
committed
c-m-rt: update docs to cover custom linker scripts and link sections
1 parent bc0aca8 commit be04550

File tree

2 files changed

+55
-40
lines changed

2 files changed

+55
-40
lines changed

cortex-m-rt/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1717
exception handler directly.
1818
- MSRV increased to 1.60.0 to align with `embedded-hal` version 1.
1919
- Improve linker error message when code does not fit into flash.
20+
- Update documentation on using custom linker scripts and linker sections
21+
and on the `pre_init` function.
2022

2123
## [v0.7.3]
2224

cortex-m-rt/src/lib.rs

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,23 @@
1212
//!
1313
//! - Initializing `static` variables before the program entry point.
1414
//!
15-
//! - Enabling the FPU before the program entry point if the target is `thumbv7em-none-eabihf`.
15+
//! - Enabling the FPU before the program entry point if the target is `-eabihf`.
1616
//!
1717
//! This crate also provides the following attributes:
1818
//!
1919
//! - [`#[entry]`][attr-entry] to declare the entry point of the program
2020
//! - [`#[exception]`][attr-exception] to override an exception handler. If not overridden all
2121
//! exception handlers default to an infinite loop.
22-
//! - [`#[pre_init]`][attr-pre_init] to run code *before* `static` variables are initialized
2322
//!
2423
//! This crate also implements a related attribute called `#[interrupt]`, which allows you
2524
//! to define interrupt handlers. However, since which interrupts are available depends on the
26-
//! microcontroller in use, this attribute should be re-exported and used from a device crate.
25+
//! microcontroller in use, this attribute should be re-exported and used from a peripheral
26+
//! access crate (PAC).
27+
//!
28+
//! A [`#[pre_init]`][attr-pre_init] macro is also provided to run a function before RAM
29+
//! initialisation, but its use is deprecated as it is not defined behaviour to execute Rust
30+
//! code before initialisation. It is still possible to create a custom `pre_init` function
31+
//! using assembly.
2732
//!
2833
//! The documentation for these attributes can be found in the [Attribute Macros](#attributes)
2934
//! section.
@@ -33,8 +38,9 @@
3338
//! ## `memory.x`
3439
//!
3540
//! This crate expects the user, or some other crate, to provide the memory layout of the target
36-
//! device via a linker script named `memory.x`. This section covers the contents of `memory.x`
37-
//! The `memory.x` file is used during linking by the `link.x` script provided by this crate.
41+
//! device via a linker script named `memory.x`, described in this section. The `memory.x` file is
42+
//! used during linking by the `link.x` script provided by this crate. If you are using a custom
43+
//! linker script, you do not need a `memory.x` file.
3844
//!
3945
//! ### `MEMORY`
4046
//!
@@ -48,15 +54,16 @@
4854
//! MEMORY
4955
//! {
5056
//! FLASH : ORIGIN = 0x08000000, LENGTH = 64K
51-
//! RAM : ORIGIN = 0x20000000, LENGTH = 20K
57+
//! RAM : ORIGIN = 0x20000000, LENGTH = 20K
5258
//! }
5359
//! ```
5460
//!
5561
//! ### `_stack_start`
5662
//!
5763
//! This optional symbol can be used to indicate where the call stack of the program should be
5864
//! placed. If this symbol is not used then the stack will be placed at the *end* of the `RAM`
59-
//! region -- the stack grows downwards towards smaller address.
65+
//! region -- the stack grows downwards towards smaller address. This is generally a sensible
66+
//! default and most applications will not need to specify `_stack_start`.
6067
//!
6168
//! For Cortex-M, the `_stack_start` must always be aligned to 8 bytes, which is enforced by
6269
//! the linker script. If you override it, ensure that whatever value you set is a multiple
@@ -65,13 +72,13 @@
6572
//! This symbol can be used to place the stack in a different memory region, for example:
6673
//!
6774
//! ```text
68-
//! /* Linker script for the STM32F303VCT6 */
75+
//! /* Linker script for the STM32F303VCT6 with stack in CCM */
6976
//! MEMORY
7077
//! {
7178
//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
7279
//!
7380
//! /* .bss, .data and the heap go in this region */
74-
//! RAM : ORIGIN = 0x20000000, LENGTH = 40K
81+
//! RAM : ORIGIN = 0x20000000, LENGTH = 40K
7582
//!
7683
//! /* Core coupled (faster) RAM dedicated to hold the stack */
7784
//! CCRAM : ORIGIN = 0x10000000, LENGTH = 8K
@@ -106,17 +113,15 @@
106113
//! graph (see [`#[exception]`]). In this example we define them in the binary crate:
107114
//!
108115
//! ```no_run
109-
//! // IMPORTANT the standard `main` interface is not used because it requires nightly
110116
//! #![no_main]
111117
//! #![no_std]
112118
//!
113119
//! // Some panic handler needs to be included. This one halts the processor on panic.
114-
//! extern crate panic_halt;
120+
//! use panic_halt as _;
115121
//!
116122
//! use cortex_m_rt::entry;
117123
//!
118-
//! // use `main` as the entry point of this application
119-
//! // `main` is not allowed to return
124+
//! // Use `main` as the entry point of this application, which may not return.
120125
//! #[entry]
121126
//! fn main() -> ! {
122127
//! // initialization
@@ -133,16 +138,14 @@
133138
//!
134139
//! ```text
135140
//! $ cat > memory.x <<EOF
136-
//! /* Linker script for the STM32F103C8T6 */
137141
//! MEMORY
138142
//! {
139143
//! FLASH : ORIGIN = 0x08000000, LENGTH = 64K
140144
//! RAM : ORIGIN = 0x20000000, LENGTH = 20K
141145
//! }
142146
//! EOF
143147
//!
144-
//! $ cargo rustc --target thumbv7m-none-eabi -- \
145-
//! -C link-arg=-nostartfiles -C link-arg=-Tlink.x
148+
//! $ cargo rustc --target thumbv7m-none-eabi -- -C link-arg=-nostartfiles -C link-arg=-Tlink.x
146149
//!
147150
//! $ file target/thumbv7m-none-eabi/debug/app
148151
//! app: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, (..)
@@ -160,29 +163,28 @@
160163
//!
161164
//! If this feature is enabled then the interrupts section of the vector table is left unpopulated
162165
//! and some other crate, or the user, will have to populate it. This mode is meant to be used in
163-
//! conjunction with crates generated using `svd2rust`. Those *device crates* will populate the
164-
//! missing part of the vector table when their `"rt"` feature is enabled.
166+
//! conjunction with crates generated using `svd2rust`. Those peripheral access crates, or PACs,
167+
//! will populate the missing part of the vector table when their `"rt"` feature is enabled.
165168
//!
166169
//! ## `set-sp`
167170
//!
168171
//! If this feature is enabled, the stack pointer (SP) is initialised in the reset handler to the
169172
//! `_stack_start` value from the linker script. This is not usually required, but some debuggers
170173
//! do not initialise SP when performing a soft reset, which can lead to stack corruption.
171174
//!
172-
//! ## `zero-init-ram`
173-
//!
174-
//! If this feature is enabled, RAM is initialized with zeros during startup from the `_ram_start`
175-
//! value to the `_ram_end` value from the linker script. This is not usually required, but might be
176-
//! necessary to properly initialize checksum-based memory integrity measures on safety-critical
177-
//! hardware.
178-
//!
179175
//! ## `set-vtor`
180176
//!
181177
//! If this feature is enabled, the vector table offset register (VTOR) is initialised in the reset
182178
//! handler to the start of the vector table defined in the linker script. This is not usually
183179
//! required, but some bootloaders do not set VTOR before jumping to application code, leading to
184180
//! your main function executing but interrupt handlers not being used.
185181
//!
182+
//! ## `zero-init-ram`
183+
//!
184+
//! If this feature is enabled, RAM is initialized with zeros during startup from the `_ram_start`
185+
//! value to the `_ram_end` value from the linker script. This is not usually required, but might be
186+
//! necessary to properly initialize memory integrity measures on some hardware.
187+
//!
186188
//! # Inspection
187189
//!
188190
//! This section covers how to inspect a binary that builds on top of `cortex-m-rt`.
@@ -252,14 +254,22 @@
252254
//! `__EXCEPTIONS` in the `.vector_table` section.
253255
//!
254256
//! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults to an empty
255-
//! function. The function called can be changed by applying the [`#[pre_init]`][attr-pre_init]
256-
//! attribute to a function.
257+
//! function. As this runs before RAM is initialised, it is not sound to use a Rust function for
258+
//! `pre_init`, and instead it should typically be written in assembly using `global_asm` or an
259+
//! external assembly file.
257260
//!
258261
//! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or
259262
//! `SVCall`, in the output of `objdump`,
260263
//!
261264
//! # Advanced usage
262265
//!
266+
//! ## Custom linker script
267+
//!
268+
//! To use your own linker script, ensure it is placed in the linker search path (for example in
269+
//! the crate root or in Cargo's `OUT_DIR`) and use it with `-C link-arg=-Tmy_script.ld` instead
270+
//! of the normal `-C link-arg=-Tlink.x`. The provided `link.x` may be used as a starting point
271+
//! for customisation.
272+
//!
263273
//! ## Setting the program entry point
264274
//!
265275
//! This section describes how [`#[entry]`][attr-entry] is implemented. This information is useful
@@ -278,7 +288,7 @@
278288
//!
279289
//! This section covers how an external crate can insert device specific interrupt handlers into the
280290
//! vector table. Most users don't need to concern themselves with these details, but if you are
281-
//! interested in how device crates generated using `svd2rust` integrate with `cortex-m-rt` read on.
291+
//! interested in how PACs generated using `svd2rust` integrate with `cortex-m-rt` read on.
282292
//!
283293
//! The information in this section applies when the `"device"` feature has been enabled.
284294
//!
@@ -381,8 +391,7 @@
381391
//! to be used as thread stacks) -- this can considerably reduce initialization time on devices that
382392
//! operate at low frequencies.
383393
//!
384-
//! The only correct way to use this section is by placing `static mut` variables with type
385-
//! [`MaybeUninit`] in it.
394+
//! The only correct way to use this section is with [`MaybeUninit`] types.
386395
//!
387396
//! [`MaybeUninit`]: https://doc.rust-lang.org/core/mem/union.MaybeUninit.html
388397
//!
@@ -398,16 +407,14 @@
398407
//! ```
399408
//!
400409
//! Be very careful with the `link_section` attribute because it's easy to misuse in ways that cause
401-
//! undefined behavior. At some point in the future we may add an attribute to safely place static
402-
//! variables in this section.
410+
//! undefined behavior.
403411
//!
404412
//! ## Extra Sections
405413
//!
406-
//! Some microcontrollers provide additional memory regions beyond RAM and FLASH.
407-
//! For example, some STM32 devices provide "CCM" or core-coupled RAM that is
408-
//! only accessible from the core. In order to access these using
409-
//! [`link_section`] attributes from your code, you need to modify `memory.x`
410-
//! to declare the additional sections:
414+
//! Some microcontrollers provide additional memory regions beyond RAM and FLASH. For example,
415+
//! some STM32 devices provide "CCM" or core-coupled RAM that is only accessible from the core. In
416+
//! order to place variables in these sections using [`link_section`] attributes from your code,
417+
//! you need to modify `memory.x` to declare the additional sections:
411418
//!
412419
//! [`link_section`]: https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute
413420
//!
@@ -432,10 +439,16 @@
432439
//! You can then use something like this to place a variable into this specific section of memory:
433440
//!
434441
//! ```no_run,edition2018
442+
//! # extern crate core;
443+
//! # use core::mem::MaybeUninit;
435444
//! #[link_section=".ccmram.BUFFERS"]
436-
//! static mut BUF: [u8; 1024] = [0u8; 1024];
445+
//! static mut BUF: MaybeUninit<[u8; 1024]> = MaybeUninit::uninit();
437446
//! ```
438447
//!
448+
//! However, note that these sections are not initialised by cortex-m-rt, and so must be used
449+
//! either with `MaybeUninit` types or you must otherwise arrange for them to be initialised
450+
//! yourself, such as in `pre_init`.
451+
//!
439452
//! [attr-entry]: attr.entry.html
440453
//! [attr-exception]: attr.exception.html
441454
//! [attr-pre_init]: attr.pre_init.html
@@ -577,7 +590,7 @@ cfg_global_asm! {
577590
///
578591
/// **NOTE**: This attribute is exposed by `cortex-m-rt` only when the `device` feature is enabled.
579592
/// However, that export is not meant to be used directly -- using it will result in a compilation
580-
/// error. You should instead use the device crate (usually generated using `svd2rust`) re-export of
593+
/// error. You should instead use the PAC (usually generated using `svd2rust`) re-export of
581594
/// that attribute. You need to use the re-export to have the compiler check that the interrupt
582595
/// exists on the target device.
583596
///
@@ -586,7 +599,7 @@ cfg_global_asm! {
586599
/// ``` ignore
587600
/// extern crate device;
588601
///
589-
/// // the attribute comes from the device crate not from cortex-m-rt
602+
/// // the attribute comes from the PAC not from cortex-m-rt
590603
/// use device::interrupt;
591604
///
592605
/// #[interrupt]

0 commit comments

Comments
 (0)