1
- //! Initialization code ("crt0") written in Rust
1
+ //! Initialization code ("crt0") written in Rust.
2
2
//!
3
3
//! This is for bare metal systems where there is no ELF loader or OS to take
4
4
//! care of initializing RAM for the program.
5
5
//!
6
6
//! # Initializing RAM
7
7
//!
8
8
//! On the linker script side, we must assign names (symbols) to the boundaries
9
- //! of the `.bss` and `.data` sections.
9
+ //! of the `.bss` and `.data` sections:
10
10
//!
11
11
//! ```text
12
12
//! .bss : ALIGN(4)
26
26
//! _sidata = LOADADDR(.data);
27
27
//! ```
28
28
//!
29
- //! On the Rust side, we must bind to those symbols using an `extern` block.
29
+ //! On the Rust side, we must bind to those symbols using an `extern` block:
30
30
//!
31
- //! ```rust,ignore
31
+ //! ```no_run
32
+ //! # use r0::{zero_bss, init_data};
32
33
//! unsafe fn before_main() {
33
34
//! // The type, `u32`, indicates that the memory is 4-byte aligned
34
35
//! extern "C" {
45
46
//! init_data(&mut _sdata, &mut _edata, &_sidata);
46
47
//! }
47
48
//! ```
48
- //!
49
- //! # `.init_array` & `.pre_init_array`
50
- //!
51
- //! This crate also provides an API to add "life before main" functionality to
52
- //! bare metal systems.
53
- //!
54
- //! On the linker script side, instruct the linker to keep the `.init_array`
55
- //! sections from input object files. Store the start and end address of the
56
- //! merged `.init_array` section.
57
- //!
58
- //! ```text
59
- //! .text :
60
- //! {
61
- //! /* .. */
62
- //! _init_array_start = ALIGN(4);
63
- //! KEEP(*(.init_array));
64
- //! _init_array_end = ALIGN(4);
65
- //! /* .. */
66
- //! }
67
- //! ```
68
- //!
69
- //! On the startup code, invoke the `run_init_array` function *before* you call
70
- //! the user `main`.
71
- //!
72
- //! ```rust,ignore
73
- //! unsafe fn start() {
74
- //! extern "C" {
75
- //! static _init_array_start: extern "C" fn();
76
- //! static _init_array_end: extern "C" fn();
77
- //! }
78
- //!
79
- //! ::r0::run_init_array(&_init_array_start, &_init_array_end);
80
- //!
81
- //! extern "C" {
82
- //! fn main(argc: isize, argv: *const *const u8) -> isize;
83
- //! }
84
- //!
85
- //! main();
86
- //! }
87
- //! ```
88
- //!
89
- //! Then the user application can use this crate `init_array!` macro to run code
90
- //! before `main`.
91
- //!
92
- //! ```rust,ignore
93
- //! init_array!(before_main, {
94
- //! println!("Hello");
95
- //! });
96
- //!
97
- //! fn main() {
98
- //! println!("World");
99
- //! }
100
- //! ```
101
49
102
50
#![ deny( warnings) ]
103
51
#![ no_std]
104
52
105
53
#[ cfg( test) ]
106
54
mod test;
107
55
108
- use core:: { mem, ptr, slice} ;
56
+ use core:: { mem, ptr} ;
57
+
58
+ mod sealed {
59
+ pub trait Sealed { }
60
+ }
61
+
62
+ /// Trait for machine word types.
63
+ ///
64
+ /// This trait is implemented by unsigned integers representing common machine
65
+ /// word sizes. It can not be implemented by the user.
66
+ ///
67
+ /// Types implementing this trait can be used by the [`init_data`] and
68
+ /// [`zero_bss`] functions. For that to be sound, all bit patterns need to be
69
+ /// valid for the type, the type must implement `Copy`, and the type must not
70
+ /// be zero-sized.
71
+ ///
72
+ /// [`init_data`]: fn.init_data.html
73
+ /// [`zero_bss`]: fn.zero_bss.html
74
+ pub unsafe trait Word : sealed:: Sealed + Copy { }
75
+
76
+ impl sealed:: Sealed for u8 { }
77
+ impl sealed:: Sealed for u16 { }
78
+ impl sealed:: Sealed for u32 { }
79
+ impl sealed:: Sealed for u64 { }
80
+ impl sealed:: Sealed for u128 { }
81
+
82
+ unsafe impl Word for u8 { }
83
+ unsafe impl Word for u16 { }
84
+ unsafe impl Word for u32 { }
85
+ unsafe impl Word for u64 { }
86
+ unsafe impl Word for u128 { }
109
87
110
- /// Initializes the `.data` section
88
+ /// Initializes the `.data` section.
111
89
///
112
90
/// # Arguments
113
91
///
@@ -119,18 +97,17 @@ use core::{mem, ptr, slice};
119
97
///
120
98
/// # Safety
121
99
///
122
- /// - Must be called exactly once
123
- /// - `mem::size_of::<T>()` must be non-zero
124
- /// - `edata >= sdata`
100
+ /// - Must be called exactly once, before the application has started.
101
+ /// - `edata >= sdata`.
125
102
/// - The `sdata -> edata` region must not overlap with the `sidata -> ...`
126
- /// region
103
+ /// region.
127
104
/// - `sdata`, `edata` and `sidata` must be `T` aligned.
128
105
pub unsafe fn init_data < T > (
129
106
mut sdata : * mut T ,
130
107
edata : * mut T ,
131
108
mut sidata : * const T ,
132
109
) where
133
- T : Copy ,
110
+ T : Word ,
134
111
{
135
112
while sdata < edata {
136
113
ptr:: write ( sdata, ptr:: read ( sidata) ) ;
@@ -139,20 +116,7 @@ pub unsafe fn init_data<T>(
139
116
}
140
117
}
141
118
142
- pub unsafe fn run_init_array (
143
- init_array_start : & extern "C" fn ( ) ,
144
- init_array_end : & extern "C" fn ( ) ,
145
- ) {
146
- let n = ( init_array_end as * const _ as usize -
147
- init_array_start as * const _ as usize ) /
148
- mem:: size_of :: < extern "C" fn ( ) > ( ) ;
149
-
150
- for f in slice:: from_raw_parts ( init_array_start, n) {
151
- f ( ) ;
152
- }
153
- }
154
-
155
- /// Zeroes the `.bss` section
119
+ /// Zeroes the `.bss` section.
156
120
///
157
121
/// # Arguments
158
122
///
@@ -163,55 +127,16 @@ pub unsafe fn run_init_array(
163
127
///
164
128
/// # Safety
165
129
///
166
- /// - Must be called exactly once
167
- /// - `mem::size_of::<T>()` must be non-zero
168
- /// - `ebss >= sbss`
130
+ /// - Must be called exactly once, before the application has started.
131
+ /// - `ebss >= sbss`.
169
132
/// - `sbss` and `ebss` must be `T` aligned.
170
133
pub unsafe fn zero_bss < T > ( mut sbss : * mut T , ebss : * mut T )
171
134
where
172
- T : Copy ,
135
+ T : Word ,
173
136
{
174
137
while sbss < ebss {
175
138
// NOTE(volatile) to prevent this from being transformed into `memclr`
176
139
ptr:: write_volatile ( sbss, mem:: zeroed ( ) ) ;
177
140
sbss = sbss. offset ( 1 ) ;
178
141
}
179
142
}
180
-
181
- #[ macro_export]
182
- macro_rules! pre_init_array {
183
- ( $name: ident, $body: expr) => {
184
- #[ allow( dead_code) ]
185
- unsafe extern "C" fn $name( ) {
186
- #[ link_section = ".pre_init_array" ]
187
- #[ used]
188
- static PRE_INIT_ARRAY_ELEMENT : unsafe extern "C" fn ( ) = $name;
189
-
190
- #[ inline( always) ]
191
- fn inner( ) {
192
- $body
193
- }
194
-
195
- inner( )
196
- }
197
- }
198
- }
199
-
200
- #[ macro_export]
201
- macro_rules! init_array {
202
- ( $name: ident, $body: expr) => {
203
- #[ allow( dead_code) ]
204
- unsafe extern "C" fn $name( ) {
205
- #[ link_section = ".init_array" ]
206
- #[ used]
207
- static INIT_ARRAY_ELEMENT : unsafe extern "C" fn ( ) = $name;
208
-
209
- #[ inline( always) ]
210
- fn inner( ) {
211
- $body
212
- }
213
-
214
- inner( )
215
- }
216
- }
217
- }
0 commit comments