@@ -7,27 +7,54 @@ use core::ptr;
7
7
// application starts. _start is invoked directly by the Tock kernel; it
8
8
// performs stack setup then calls rust_start. rust_start performs data
9
9
// relocation and sets up the heap before calling the rustc-generated main.
10
- // rust_start and _start are tightly coupled: the order of rust_start's
11
- // parameters is designed to simplify _start's implementation.
10
+ // rust_start and _start are tightly coupled.
12
11
//
13
- // The memory layout is controlled by the linker script and these methods. These
14
- // are written for the following memory layout:
12
+ // The memory layout is controlled by the linker script.
15
13
//
16
- // +----------------+ <- app_heap_break
17
- // | Heap |
18
- // +----------------| <- heap_bottom
19
- // | .data and .bss |
20
- // +----------------+ <- stack_top
21
- // | Stack |
22
- // | (grows down) |
23
- // +----------------+ <- mem_start
14
+ // When the kernel gives control to us, we get r0-r3 values that is as follows.
15
+ //
16
+ // +--------------+ <- (r2) mem.len()
17
+ // | Grant |
18
+ // +--------------+
19
+ // | Unused |
20
+ // S +--------------+ <- (r3) app_heap_break
21
+ // R | Heap | (hardcoded to mem_start + 3072 in
22
+ // A +--------------| Processs::create which could be lesser than
23
+ // M | .bss | mem_start + stack + .data + .bss)
24
+ // +--------------|
25
+ // | .data |
26
+ // +--------------+
27
+ // | Stack |
28
+ // +--------------+ <- (r1) mem_start
29
+ //
30
+ // +--------------+
31
+ // | .text |
32
+ // F +--------------+
33
+ // L | .crt0_header |
34
+ // A +--------------+ <- (r0) app_start
35
+ // S | Protected |
36
+ // H | Region |
37
+ // +--------------+
38
+ //
39
+ // We want to organize the memory as follows.
40
+ //
41
+ // +--------------+ <- app_heap_break
42
+ // | Heap |
43
+ // +--------------| <- heap_start
44
+ // | .bss |
45
+ // +--------------|
46
+ // | .data |
47
+ // +--------------+ <- stack_start (stacktop)
48
+ // | Stack |
49
+ // | (grows down) |
50
+ // +--------------+ <- mem_start
24
51
//
25
52
// app_heap_break and mem_start are given to us by the kernel. The stack size is
26
- // determined using pointer text_start , and is used with mem_start to compute
27
- // stack_top . The placement of .data and .bss are given to us by the linker
28
- // script; the heap is located between the end of .bss and app_heap_break. This
29
- // requires that .bss is the last (highest-address) section placed by the linker
30
- // script.
53
+ // determined using pointer app_start , and is used with mem_start to compute
54
+ // stack_start (stacktop) . The placement of .data and .bss are given to us by
55
+ // the linker script; the heap is located between the end of .bss and
56
+ // app_heap_break. This requires that .bss is the last (highest-address) section
57
+ // placed by the linker script.
31
58
32
59
/// Tock programs' entry point. Called by the kernel at program start. Sets up
33
60
/// the stack then calls rust_start() for the remainder of setup.
@@ -36,7 +63,7 @@ use core::ptr;
36
63
#[ naked]
37
64
#[ link_section = ".start" ]
38
65
pub unsafe extern "C" fn _start (
39
- text_start : usize ,
66
+ app_start : usize ,
40
67
mem_start : usize ,
41
68
_memory_len : usize ,
42
69
app_heap_break : usize ,
@@ -61,29 +88,84 @@ pub unsafe extern "C" fn _start(
61
88
b .Lyield_loop
62
89
63
90
.Lstack_init:
64
- // Initialize the stack pointer . The stack pointer is computed as
91
+ // Compute the stacktop (stack_start) . The stacktop is computed as
65
92
// stack_size + mem_start plus padding to align the stack to a multiple
66
93
// of 8 bytes. The 8 byte alignment is to follow ARM AAPCS:
67
94
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html
68
- ldr ip, [r0, #36] // ip = text_start->stack_size
69
- add ip, ip, r1 // ip = text_start->stack_size + mem_start
70
- add ip, #7 // ip = text_start->stack_size + mem_start + 7
71
- bic r1, ip, #7 // r1 = (text_start->stack_size + mem_start + 7) & ~0x7
72
- mov sp, r1 // sp = r1
73
-
74
- // Call rust_start. text_start, stack_top, and app_heap_break are
75
- // already in the correct registers.
95
+ ldr r4, [r0, #36] // r4 = app_start->stack_size
96
+ add r4, r4, r1 // r4 = app_start->stack_size + mem_start
97
+ add r4, #7 // r4 = app_start->stack_size + mem_start + 7
98
+ bic r4, r4, #7 // r4 = (app_start->stack_size + mem_start + 7) & ~0x7
99
+ mov sp, r4 // sp = r4
100
+
101
+ // We need to pass app_start, stacktop and app_heap_break to rust_start.
102
+ // Temporarily store them in r6, r7 and r8
103
+ mov r6, r0
104
+ mov r7, sp
105
+
106
+ // Debug support, tell the kernel the stack location
107
+ //
108
+ // memop(10, stacktop)
109
+ // r7 contains stacktop
110
+ mov r0, #10
111
+ mov r1, r7
112
+ svc 4
113
+
114
+ // Debug support, tell the kernel the heap_start location
115
+ mov r0, r6
116
+ ldr r4, [r0, #24] // r4 = app_start->bss_start
117
+ ldr r5, [r0, #28] // r5 = app_start->bss_size
118
+ add r4, r4, r5 // r4 = bss_start + bss_size
119
+ //
120
+ // memop(11, r4)
121
+ mov r0, #11
122
+ mov r1, r4
123
+ svc 4
124
+
125
+ // Store heap_start (and soon to be app_heap_break) in r8
126
+ mov r8, r4
127
+
128
+ // There is a possibility that stack + .data + .bss is greater than
129
+ // 3072. Therefore setup the initial app_heap_break to heap_start (that
130
+ // is zero initial heap) and let rust_start determine where the actual
131
+ // app_heap_break should go.
132
+ //
133
+ // Also, because app_heap_break is where the unprivileged MPU region
134
+ // ends, in case mem_start + stack + .data + .bss is greater than
135
+ // initial app_heap_break (mem_start + 3072), we will get a memory fault
136
+ // in rust_start when initializing .data and .bss. Setting
137
+ // app_heap_break to heap_start avoids that.
138
+
139
+ // memop(0, r8)
140
+ mov r0, #0
141
+ mov r1, r8
142
+ svc 4
143
+
144
+ // NOTE: If there is a hard-fault before this point, then
145
+ // process_detail_fmt in kernel/src/process.rs panics which
146
+ // will result in us losing the PC of the instruction
147
+ // generating the hard-fault. Therefore any code before
148
+ // this point is critical code
149
+
150
+ // Setup parameters needed by rust_start
151
+ // r6 (app_start), r7 (stacktop), r8 (app_heap_break)
152
+ mov r0, r6
153
+ mov r1, r7
154
+ mov r2, r8
155
+
156
+ // Call rust_start
76
157
bl rust_start"
77
158
: // No output operands
78
- : "{r0}" ( text_start) "{r1}" ( mem_start) "{r3}" ( app_heap_break) // Input operands
79
- : "cc" "ip" "lr" "memory" "r0" "r1" "r2" "r3" // Clobbers
80
- : // Options
159
+ : "{r0}" ( app_start) , "{r1}" ( mem_start) , "{r3}" ( app_heap_break) // Input operands
160
+ : "r0" , "r1" , "r2" , "r3" , "r4" , "r5" , "r6" , "r7" , "r8" , "r12" ,
161
+ "cc" , "memory" // Clobbers
162
+ : "volatile" // Options
81
163
) ;
82
164
intrinsics:: unreachable ( ) ;
83
165
}
84
166
85
167
/// The header encoded at the beginning of .text by the linker script. It is
86
- /// accessed by rust_start() using its text_start parameter.
168
+ /// accessed by rust_start() using its app_start parameter.
87
169
#[ repr( C ) ]
88
170
struct LayoutHeader {
89
171
got_sym_start : usize ,
@@ -104,23 +186,22 @@ struct LayoutHeader {
104
186
/// into the rustc-generated main(). This cannot use mutable global variables or
105
187
/// global references to globals until it is done setting up the data segment.
106
188
#[ no_mangle]
107
- pub unsafe extern "C" fn rust_start (
108
- text_start : usize ,
109
- stack_top : usize ,
110
- _skipped : usize ,
111
- app_heap_break : usize ,
112
- ) -> ! {
189
+ pub unsafe extern "C" fn rust_start ( app_start : usize , stacktop : usize , app_heap_break : usize ) -> ! {
113
190
extern "C" {
114
- // This function is created internally by`rustc`. See `src/lang_items.rs` for more details.
191
+ // This function is created internally by `rustc`. See
192
+ // `src/lang_items.rs` for more details.
115
193
fn main ( argc : isize , argv : * const * const u8 ) -> isize ;
116
194
}
117
195
118
196
// Copy .data into its final location in RAM (determined by the linker
119
197
// script -- should be immediately above the stack).
120
- let layout_header: & LayoutHeader = core:: mem:: transmute ( text_start) ;
198
+ let layout_header: & LayoutHeader = core:: mem:: transmute ( app_start) ;
199
+
200
+ let data_flash_start_addr = app_start + layout_header. data_sym_start ;
201
+
121
202
intrinsics:: copy_nonoverlapping (
122
- ( text_start + layout_header . data_sym_start ) as * const u8 ,
123
- stack_top as * mut u8 ,
203
+ data_flash_start_addr as * const u8 ,
204
+ stacktop as * mut u8 ,
124
205
layout_header. data_size ,
125
206
) ;
126
207
@@ -136,11 +217,23 @@ pub unsafe extern "C" fn rust_start(
136
217
// look like at the LLVM level. Once we know what the relocation strategy
137
218
// looks like we can write the dynamic linker.
138
219
139
- // Initialize the heap and tell the kernel where everything is. The heap is
140
- // placed between .bss and the end of application memory.
141
- ALLOCATOR . lock ( ) . init ( bss_end, app_heap_break) ;
142
- syscalls:: memop ( 10 , stack_top) ;
143
- syscalls:: memop ( 11 , bss_end) ;
220
+ // Initialize the heap. Unlike libtock-c's newlib allocator, which can use
221
+ // `sbrk` system call to dynamically request heap memory from the kernel, we
222
+ // need to tell `linked_list_allocator` where the heap starts and ends.
223
+ //
224
+ // Heap size is set using `elf2tab` with `--heap-size` option, which is
225
+ // currently at 1024. If you change the `elf2tab` heap size, make sure to
226
+ // make the corresponding change here.
227
+ const HEAP_SIZE : usize = 1024 ;
228
+
229
+ // we could have also bss_end for app_heap_start
230
+ let app_heap_start = app_heap_break;
231
+ let app_heap_end = app_heap_break + HEAP_SIZE ;
232
+
233
+ // tell the kernel the new app heap break
234
+ syscalls:: memop ( 0 , app_heap_end) ;
235
+
236
+ ALLOCATOR . lock ( ) . init ( app_heap_start, HEAP_SIZE ) ;
144
237
145
238
main ( 0 , ptr:: null ( ) ) ;
146
239
0 commit comments