Skip to content

Commit 6db291d

Browse files
authored
Merge pull request #83 from rajivr/for-upstream2
Refactor `layout.ld` and `entry_point.rs`
2 parents 3765065 + 39167da commit 6db291d

File tree

4 files changed

+168
-54
lines changed

4 files changed

+168
-54
lines changed

hail_layout.ld

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ MEMORY {
66
SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 62K
77
}
88

9+
/*
10+
* Any change to STACK_SIZE should be accompanied by a corresponding change to
11+
* `elf2tab`'s `--stack` option
12+
*/
13+
STACK_SIZE = 2048;
14+
915
MPU_MIN_ALIGN = 8K;
1016

1117
INCLUDE layout.ld

layout.ld

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@
1414
* FLASH (rx) : ORIGIN = 0x10030, LENGTH = 0x0FFD0
1515
* SRAM (RWX) : ORIGIN = 0x20000, LENGTH = 0x10000
1616
* }
17+
* STACK_SIZE = 2048;
1718
* MPU_MIN_ALIGN = 8K;
1819
* INCLUDE ../libtock-rs/layout.ld
1920
*/
2021

21-
STACK_SIZE = 2048;
22-
2322
ENTRY(_start)
2423

2524
SECTIONS {
@@ -81,21 +80,28 @@ SECTIONS {
8180
*(.text*)
8281
*(.rodata*)
8382
KEEP (*(.syscalls))
84-
_etext = .;
8583
*(.ARM.extab*)
8684
. = ALIGN(4); /* Make sure we're word-aligned here */
85+
_etext = .;
8786
} > FLASH =0xFF
8887

88+
/* Application stack */
89+
.stack :
90+
{
91+
. = . + STACK_SIZE;
92+
93+
_stack_top_unaligned = .;
94+
. = ALIGN(8);
95+
_stack_top_aligned = .;
96+
} > SRAM
97+
8998
/* Data section, static initialized variables
9099
* Note: This is placed in Flash after the text section, but needs to be
91100
* moved to SRAM at runtime
92101
*/
93-
.data :
102+
.data : AT (_etext)
94103
{
95-
/* Account for MPU alignment and the stack */
96-
. = ALIGN(MPU_MIN_ALIGN);
97-
. = . + STACK_SIZE;
98-
. = ALIGN(8); /* The stack is aligned to a multiple of 8 bytes. */
104+
. = ALIGN(4); /* Make sure we're word-aligned here */
99105
_data = .;
100106
KEEP(*(.data*))
101107
. = ALIGN(4); /* Make sure we're word-aligned at the end of flash */
@@ -147,3 +153,6 @@ SECTIONS {
147153
} > FLASH
148154
PROVIDE_HIDDEN (__exidx_end = .);
149155
}
156+
157+
ASSERT((_stack_top_aligned - _stack_top_unaligned) == 0, "
158+
STACK_SIZE must be 8 byte multiple")

nrf52_layout.ld

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ MEMORY {
66
SRAM (rwx) : ORIGIN = 0x20002000, LENGTH = 62K
77
}
88

9+
/*
10+
* Any change to STACK_SIZE should be accompanied by a corresponding change to
11+
* `elf2tab`'s `--stack` option
12+
*/
13+
STACK_SIZE = 2048;
14+
915
MPU_MIN_ALIGN = 8K;
1016

1117
INCLUDE layout.ld

src/entry_point.rs

Lines changed: 139 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,54 @@ use core::ptr;
77
// application starts. _start is invoked directly by the Tock kernel; it
88
// performs stack setup then calls rust_start. rust_start performs data
99
// 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.
1211
//
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.
1513
//
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
2451
//
2552
// 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.
3158

3259
/// Tock programs' entry point. Called by the kernel at program start. Sets up
3360
/// the stack then calls rust_start() for the remainder of setup.
@@ -36,7 +63,7 @@ use core::ptr;
3663
#[naked]
3764
#[link_section = ".start"]
3865
pub unsafe extern "C" fn _start(
39-
text_start: usize,
66+
app_start: usize,
4067
mem_start: usize,
4168
_memory_len: usize,
4269
app_heap_break: usize,
@@ -61,29 +88,84 @@ pub unsafe extern "C" fn _start(
6188
b .Lyield_loop
6289
6390
.Lstack_init:
64-
// Initialize the stack pointer. The stack pointer is computed as
91+
// Compute the stacktop (stack_start). The stacktop is computed as
6592
// stack_size + mem_start plus padding to align the stack to a multiple
6693
// of 8 bytes. The 8 byte alignment is to follow ARM AAPCS:
6794
// 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
76157
bl rust_start"
77158
: // 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
81163
);
82164
intrinsics::unreachable();
83165
}
84166

85167
/// 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.
87169
#[repr(C)]
88170
struct LayoutHeader {
89171
got_sym_start: usize,
@@ -104,23 +186,22 @@ struct LayoutHeader {
104186
/// into the rustc-generated main(). This cannot use mutable global variables or
105187
/// global references to globals until it is done setting up the data segment.
106188
#[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) -> ! {
113190
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.
115193
fn main(argc: isize, argv: *const *const u8) -> isize;
116194
}
117195

118196
// Copy .data into its final location in RAM (determined by the linker
119197
// 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+
121202
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,
124205
layout_header.data_size,
125206
);
126207

@@ -136,11 +217,23 @@ pub unsafe extern "C" fn rust_start(
136217
// look like at the LLVM level. Once we know what the relocation strategy
137218
// looks like we can write the dynamic linker.
138219

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);
144237

145238
main(0, ptr::null());
146239

0 commit comments

Comments
 (0)