linker_sections/lib.rs
1//! Couple of macros for linker section memory initialization. This crate is
2//! designed for use on platforms with 32-bit aligned memory and 32-bit memory
3//! access, but was tested with cortex-m cores only.
4//!
5//! This crate provides section memory initialization macro in a couple of
6//! following variants.
7//! - [`init_sections`]
8//!
9//! Use this macro if your section is defined using symbols
10//! - `__s<section>` for section VMA start,
11//! - `__e<section>` for section VMA end,
12//! - `__si<section>` for section LMA start.
13//!
14//! ```
15//! init_sections!(buffers, sram2, sram3);
16//! ```
17//!
18//! - [`init_sections_with_prefixes`]
19//!
20//! Use if you want to specify your section boundary symbols manually.
21//!
22//! ```
23//! init_sections_with_prefixes!(
24//! buffers(__s, __e, __si),
25//! sram2(__s, __e, __si),
26//! sram3(__s, __e, __si)
27//! );
28//! ```
29//!
30//! # Example
31//!
32//! Simple example defines a section `.custom_data` with start at 4-byte aligned `__scustom_data`
33//! and 4-byte aligned end at `__ecustom_data`. The initialization data goes at `__sicustom_data`.
34//!
35//! ```text
36//! MEMORY
37//! {
38//! FLASH : ORIGIN = 0x08000000, LENGTH = 32K
39//! RAM : ORIGIN = 0x20000000, LENGTH = 16K
40//! DATA : ORIGIN = 0x20004000, LENGTH = 16K
41//! }
42//!
43//! SECTIONS
44//! {
45//! .custom_data : ALIGN(4)
46//! {
47//! . = ALIGN(4);
48//! __scustom_data = .;
49//! *(.custom_data .custom_data.*);
50//!
51//! . = ALIGN(4);
52//! __ecustom_data = .;
53//! } > DATA AT>FLASH
54//!
55//! __sicustom_data = LOADADDR(.custom_data);
56//! } INSERT BEFORE .uninit;
57//! ```
58//!
59//! In rust code it is needed to call macro [`init_sections`] with proper argument. the
60//! [`init_sections`] macro shall be usually called before or at the beginning of `main` function.
61//!
62//! ```
63//! #![no_std]
64//! #![no_main]
65//!
66//! use linker_sections::init_sections;
67//! use {defmt_rtt as _, panic_probe as _};
68//!
69//! const INITIAL_VALUE: u32 = 0xDEAD_BEEF;
70//!
71//! #[unsafe(link_section = ".custom_data")]
72//! static mut STATIC_VARIABLE: u32 = INITIAL_VALUE;
73//! #[cortex_m_rt::pre_init]
74//! unsafe fn pre_init() {
75//! init_sections!(custom_data);
76//! }
77//!
78//! #[cortex_m_rt::entry]
79//! fn main() -> ! {
80//! // print initialized variable value
81//! unsafe {
82//! defmt::info!("STATIC_VARIABLE = 0x{:08X}", STATIC_VARIABLE);
83//! }
84//!
85//! loop {}
86//! }
87//! ```
88//!
89//! # Safety
90//!
91//! - The symbols must be 4-byte aligned.
92//! - The symbols must point to memory with required access (read, write).
93//! - The symbols must represent continuos memory.
94//!
95//! # Limitations
96//!
97//! - Each section's name shall be a valid rust function name, but it does not have to be snake_case.
98//! - Only one macro can be called and it can be called at most once.
99
100#![no_std]
101
102#[doc(hidden)]
103pub extern crate with_builtin_macros;
104#[doc(hidden)]
105pub use with_builtin_macros::{with_builtin, with_eager_expansions};
106
107#[macro_export]
108/// Defines pre-init function initializing linker section memory.
109///
110/// This macro accepts linker section names as arguments and assumes the linker symbols are named
111/// after given section names prefixed with
112/// - `__s` for section VMA's start (usually points to RAM)
113/// - `__e` for section VMA's end (usually points to RAM)
114/// - `__si` for section LMA's start (usually points to FLASH)
115///
116/// If the symbols in the linker script are named `__scustom_data`, `__ecustom_data` and `__sicustom_data`,
117/// as depicted in an example below, the macro call should be
118///
119/// ```
120/// init_sections!(custom_data)
121/// ```
122///
123/// ```text
124/// MEMORY
125/// {
126/// FLASH : ORIGIN = 0x08000000, LENGTH = 32K
127/// RAM : ORIGIN = 0x20000000, LENGTH = 16K
128/// DATA : ORIGIN = 0x20004000, LENGTH = 16K
129/// }
130///
131/// SECTIONS
132/// {
133/// .custom_data : ALIGN(4)
134/// {
135/// . = ALIGN(4);
136/// __scustom_data = .;
137/// *(.custom_data .custom_data.*);
138///
139/// . = ALIGN(4);
140/// __ecustom_data = .;
141/// } > DATA AT>FLASH
142///
143/// __sicustom_data = LOADADDR(.custom_data);
144/// } INSERT BEFORE .uninit;
145/// ```
146///
147/// Multiple section names could be passed as
148///
149/// ```
150/// init_sections!(section_a, section_b, section_c);
151/// ```
152/// ```
153/// init_sections!(section_a, section_b, section_c,);
154/// ```
155/// ```
156/// init_sections!(section_a section_b section_c);
157/// ```
158macro_rules! init_sections {
159 ($($section_name:ident$(,)?)+) => {
160 $crate::init_sections_with_prefixes!($($section_name(__s, __e, __si),)*);
161 };
162}
163
164#[macro_export]
165/// Defines pre-init function initializing linker section memory.
166///
167/// This macro accepts linker section names and symbol prefixes as arguments. If your section
168/// symbols are prefixed with `__s`, `__e` and `__si`, look at [`init_sections`].
169///
170/// If the symbols in the linker script are named `__scustom_data`, `__ecustom_data` and `__sicustom_data`,
171/// as depicted in an example below, the macro call should be
172///
173/// ```
174/// init_sections_with_prefixes!(custom_data(__s, __e, __si))
175/// ```
176///
177/// ```text
178/// MEMORY
179/// {
180/// FLASH : ORIGIN = 0x08000000, LENGTH = 32K
181/// RAM : ORIGIN = 0x20000000, LENGTH = 16K
182/// DATA : ORIGIN = 0x20004000, LENGTH = 16K
183/// }
184///
185/// SECTIONS
186/// {
187/// .custom_data : ALIGN(4)
188/// {
189/// . = ALIGN(4);
190/// __scustom_data = .;
191/// *(.custom_data .custom_data.*);
192///
193/// . = ALIGN(4);
194/// __ecustom_data = .;
195/// } > DATA AT>FLASH
196///
197/// __sicustom_data = LOADADDR(.custom_data);
198/// } INSERT BEFORE .uninit;
199/// ```
200///
201/// Multiple section names could be passed as
202///
203/// ```
204/// init_sections_with_prefixes!(section_a(__s, __e __si), section_b(__s, __e, __si));
205/// ```
206/// ```
207/// init_sections_with_prefixes!(section_a(__s,__e,__si),);
208/// ```
209/// ```
210/// init_sections_with_prefixes!(
211/// section_a(__s, __e, __si)
212/// section_b(__s, __e, __si,)
213/// section_c(__s __e __si)
214/// );
215/// ```
216macro_rules! init_sections_with_prefixes {
217 ($($section_name:ident($beg:ident,$end:ident,$src:ident)$(,)?)+) => {
218 fn __init_sections() {$(
219 $crate::section_init_with_prefixes!($section_name($beg, $end, $src));
220 $section_name();
221 )*}
222
223 __init_sections();
224 };
225}
226
227#[macro_export]
228#[doc(hidden)]
229macro_rules! section_init_with_prefixes {
230 ($section_name:ident($beg:ident, $end:ident, $src:ident)) => {
231 #[allow(non_snake_case)]
232 fn $section_name() {
233 $crate::with_eager_expansions! { $crate::pointer_mut!( #{ concat_idents!($beg, $section_name) } ) };
234 $crate::with_eager_expansions! { $crate::pointer!( #{ concat_idents!($end, $section_name) } ) };
235 $crate::with_eager_expansions! { $crate::pointer!( #{ concat_idents!($src, $section_name) } ) };
236
237 let src: *const u32 = core::ptr::addr_of!(
238 $crate::with_builtin! { let $name = concat_idents!($src, $section_name) in { $name } }
239 );
240 let dst: *mut u32 = core::ptr::addr_of_mut!(
241 $crate::with_builtin! { let $name = concat_idents!($beg, $section_name) in { $name } }
242 );
243 let end: *const u32 = core::ptr::addr_of!(
244 $crate::with_builtin! { let $name = concat_idents!($end, $section_name) in { $name } }
245 );
246
247 unsafe { $crate::section_init(dst, end, src); }
248 }
249 };
250}
251
252#[macro_export]
253#[doc(hidden)]
254macro_rules! pointer {
255 ($name:ident) => {
256 unsafe extern "C" {
257 static $name: u32;
258 }
259 };
260}
261
262#[macro_export]
263#[doc(hidden)]
264macro_rules! pointer_mut {
265 ($name:ident) => {
266 unsafe extern "C" {
267 static mut $name: u32;
268 }
269 };
270}
271
272#[doc(hidden)]
273pub unsafe fn section_init(dst: *mut u32, end: *const u32, src: *const u32) {
274 // not using defmt::asserts since defmt is not initialized at the moment this function being executed
275
276 #[cfg(feature = "asserts")]
277 {
278 // section start shall be less or equal to section end
279 assert!(dst as *const u32 <= end);
280
281 // src and dst must be 4-byte aligned because of 4-byte oriented memcopy
282 assert!(src as usize % 4 == 0);
283 assert!(dst as usize % 4 == 0);
284
285 // to calculate section length, section end must be 4-byte aligned
286 assert!(end as usize % 4 == 0);
287 }
288
289 let len = unsafe { end.offset_from(dst) } as usize;
290
291 #[cfg(feature = "asserts")]
292 {
293 let src = src as usize;
294 let dst = dst as usize;
295
296 // check for memory region overlap
297 assert!(src > dst + len || src + len < dst);
298 }
299
300 unsafe { core::ptr::copy_nonoverlapping(src, dst, len) };
301}