Skip to content

Commit a3c4619

Browse files
Merge pull request #93 from us-irs/mohr/stacks
Reworked stack allocation
2 parents 8427c25 + e3ad93f commit a3c4619

File tree

6 files changed

+198
-37
lines changed

6 files changed

+198
-37
lines changed

aarch32-rt/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Reworked stack allocation (PR #93)
13+
1014
## [aarch32-rt v0.1.0]
1115

1216
### Added

aarch32-rt/link.x

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
Basic AArch32 linker script.
33
44
You must supply a file called `memory.x` which defines the memory regions
5-
'VECTORS', 'CODE' and 'DATA'.
5+
'VECTORS', 'CODE', 'DATA', 'STACKS'.
66
7-
The stack pointer(s) will be (near) the top of the DATA region by default.
7+
The stacks will be at the top of the STACKS region by default, use `_pack_stacks`
8+
to overwrite default behaviour.
89
910
Based upon the linker script from https://github.com/rust-embedded/cortex-m
1011
*/
@@ -70,31 +71,66 @@ SECTIONS {
7071
__euninit = .;
7172
} > DATA
7273

74+
.filler (NOLOAD) : {
75+
/* Move the .stacks section to the end of the STACKS memory region */
76+
_next_region = ORIGIN(STACKS) + LENGTH(STACKS);
77+
_start_moved_stacks = _next_region - SIZEOF(.stacks);
78+
_start_stacks = _pack_stacks ? . : _start_moved_stacks;
79+
FILL(0x00)
80+
. = _start_stacks;
81+
} > STACKS
82+
83+
.stacks (NOLOAD) : ALIGN(8)
84+
{
85+
. = ALIGN(8);
86+
_stacks_low_end = .;
87+
_sys_stack_end = .;
88+
. += _sys_stack_size;
89+
. = ALIGN(8);
90+
_sys_stack = .;
91+
_fiq_stack_end = .;
92+
. += _fiq_stack_size;
93+
. = ALIGN(8);
94+
_fiq_stack = .;
95+
_irq_stack_end = .;
96+
. += _irq_stack_size;
97+
. = ALIGN(8);
98+
_irq_stack = .;
99+
_abt_stack_end = .;
100+
. += _abt_stack_size;
101+
. = ALIGN(8);
102+
_abt_stack = .;
103+
_svc_stack_end = .;
104+
. += _svc_stack_size;
105+
. = ALIGN(8);
106+
_svc_stack = .;
107+
_und_stack_end = .;
108+
. += _und_stack_size;
109+
. = ALIGN(8);
110+
_und_stack = .;
111+
_hyp_stack_end = .;
112+
. += _hyp_stack_size;
113+
. = ALIGN(8);
114+
_hyp_stack = .;
115+
_stacks_high_end = .;
116+
} > STACKS
117+
73118
/DISCARD/ : {
74119
*(.note .note*)
75120
}
76121
}
77122

78-
/*
79-
We reserve some space at the top of the RAM for our exception stacks. The
80-
remainder is our system mode stack.
81-
82-
You must keep _stack_top and the stack sizes aligned to eight byte boundaries.
83-
*/
84-
PROVIDE(_stack_top = ORIGIN(DATA) + LENGTH(DATA));
123+
/* We provide default sizes for the stacks to be overwritten in memory.x */
124+
PROVIDE(_stack_top = _stacks_high_end); /* deprecated, use _xxx_stack labels as defined in .stacks section */
85125
PROVIDE(_hyp_stack_size = 0x400);
86126
PROVIDE(_und_stack_size = 0x400);
87127
PROVIDE(_svc_stack_size = 0x400);
88128
PROVIDE(_abt_stack_size = 0x400);
89129
PROVIDE(_irq_stack_size = 0x400);
90130
PROVIDE(_fiq_stack_size = 0x400);
131+
PROVIDE(_sys_stack_size = 0x2000);
132+
PROVIDE(_pack_stacks = 0); /* set this to 1 to remove the filler section pushing the stacks to the end of STACKS. */
91133

92-
ASSERT(_stack_top % 8 == 0, "ERROR(aarch32-rt): top of stack is not 8-byte aligned");
93-
ASSERT(_und_stack_size % 8 == 0, "ERROR(aarch32-rt): size of UND stack is not 8-byte aligned");
94-
ASSERT(_svc_stack_size % 8 == 0, "ERROR(aarch32-rt): size of SVC stack is not 8-byte aligned");
95-
ASSERT(_abt_stack_size % 8 == 0, "ERROR(aarch32-rt): size of ABT stack is not 8-byte aligned");
96-
ASSERT(_irq_stack_size % 8 == 0, "ERROR(aarch32-rt): size of IRQ stack is not 8-byte aligned");
97-
ASSERT(_fiq_stack_size % 8 == 0, "ERROR(aarch32-rt): size of FIQ stack is not 8-byte aligned");
98134

99135
/* Weak aliases for ASM default handlers */
100136
PROVIDE(_start = _default_start);

aarch32-rt/src/lib.rs

Lines changed: 138 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,24 @@
3939
//!
4040
//! ## Constants
4141
//!
42-
//! * `_stack_top` - the address of the top of some region of RAM that we can
43-
//! use as stack space, with eight-byte alignment. Our linker script PROVIDEs
44-
//! a default pointing at the top of RAM.
4542
//! * `__sbss` - the start of zero-initialised data in RAM. Must be 4-byte
4643
//! aligned.
4744
//! * `__ebss` - the end of zero-initialised data in RAM. Must be 4-byte
4845
//! aligned.
4946
//! * `_fiq_stack_size` - the number of bytes to be reserved for stack space
50-
//! when in FIQ mode; must be a multiple of 8.
47+
//! when in FIQ mode; will be padded to a multiple of 8.
5148
//! * `_irq_stack_size` - the number of bytes to be reserved for stack space
52-
//! when in FIQ mode; must be a multiple of 8.
49+
//! when in FIQ mode; will be padded to a multiple of 8.
5350
//! * `_svc_stack_size` - the number of bytes to be reserved for stack space
54-
//! when in SVC mode; must be a multiple of 8.
51+
//! when in SVC mode; will be padded to a multiple of 8.
52+
//! * `_und_stack_size` - the number of bytes to be reserved for stack space
53+
//! when in Undefined mode; will be padded to a multiple of 8.
54+
//! * `_abt_stack_size` - the number of bytes to be reserved for stack space
55+
//! when in Abort mode; will be padded to a multiple of 8.
56+
//! * `_hyp_stack_size` - the number of bytes to be reserved for stack space
57+
//! when in Hyp mode; will be padded to a multiple of 8.
58+
//! * `_sys_stack_size` - the number of bytes to be reserved for stack space
59+
//! when in System mode; will be padded to a multiple of 8.
5560
//! * `__sdata` - the start of initialised data in RAM. Must be 4-byte aligned.
5661
//! * `__edata` - the end of initialised data in RAM. Must be 4-byte aligned.
5762
//! * `__sidata` - the start of the initialisation values for data, in read-only
@@ -61,10 +66,16 @@
6166
//! `__sbss` and `__ebss` is zeroed, and the memory between `__sdata` and
6267
//! `__edata` is initialised with the data found at `__sidata`.
6368
//!
69+
//! ## Stacks
70+
//!
71+
//! Stacks are located in `.stacks` section which is mapped to the `STACKS`
72+
//! memory region. Per default, the stacks are pushed to the end of the `STACKS`
73+
//! by a filler section.
74+
//!
6475
//! The stacks look like:
6576
//!
6677
//! ```text
67-
//! +------------------+ <----_stack_top
78+
//! +------------------+ <----_stack_top equals ORIGIN(STACKS) + LENGTH(STACKS)
6879
//! | HYP Stack | } _hyp_stack_size bytes (Armv8-R only)
6980
//! +------------------+
7081
//! | UND Stack | } _und_stack_size bytes
@@ -77,10 +88,17 @@
7788
//! +------------------+
7889
//! | FIQ Stack | } _fiq_stack_size bytes
7990
//! +------------------+
80-
//! | SYS Stack | } No specific size
91+
//! | SYS Stack | } _sys_stack_size bytes
8192
//! +------------------+
93+
//! | filler section | } calculated so that _stack_top equals end of STACKS
94+
//! +------------------+ <----either ORIGIN(STACKS) or the end of previous
95+
//! section located in STACKS or its alias.
8296
//! ```
8397
//!
98+
//! Our linker script PROVIDEs a symbol `_pack_stacks`. By setting this symbol
99+
//! to 0 in memory.x, the stacks can be moved to the beginning of the `STACKS`
100+
//! region or the end of the previous section located in STACKS or its alias.
101+
//!
84102
//! ## C-Compatible Functions
85103
//!
86104
//! ### Main Function
@@ -434,7 +452,16 @@
434452
//! * `_default_handler` - a C compatible function that spins forever.
435453
//! * `_init_segments` - initialises `.bss` and `.data`
436454
//! * `_stack_setup` - initialises UND, SVC, ABT, IRQ, FIQ and SYS stacks from
437-
//! the address given in `r0`
455+
//! the address given in `r0`. Deprecated, use `_stack_setup_preallocated` instead
456+
//! * `_stack_setup_preallocated` - initialises UND, SVC, ABT, IRQ, FIQ and SYS
457+
//! stacks from the `.stacks` section defined in link.x, based on
458+
//! _xxx_stack_size values
459+
//! * `_xxx_stack` and `_xxx_stack_end` where the former is the top and the latter
460+
//! the bottom of the stack for each mode (`und`, `svc`, `abt`, `irq`, `fiq`, `sys`)
461+
//! * `_stack_top` - the address of the top of the STACKS region that contains
462+
//! the reseved stacks, with eight-byte alignment.
463+
//! Using this symbol is deprecated, stacks should be initialized by their
464+
//! individual _xxx_stack symbols
438465
//!
439466
//! The assembly language trampolines are required because AArch32
440467
//! processors do not save a great deal of state on entry to an exception
@@ -493,13 +520,15 @@ pub extern "C" fn _default_handler() {
493520
}
494521

495522
// The Interrupt Vector Table, and some default assembly-language handler.
523+
// Needs to be aligned to 5bits/2^5 to be stored correctly in VBAR
496524
#[cfg(target_arch = "arm")]
497525
core::arch::global_asm!(
498526
r#"
499527
.section .vector_table,"ax",%progbits
500528
.arm
501529
.global _vector_table
502530
.type _vector_table, %function
531+
.align 5
503532
_vector_table:
504533
ldr pc, =_start
505534
ldr pc, =_asm_undefined_handler
@@ -725,7 +754,8 @@ macro_rules! fpu_enable {
725754
}
726755

727756
// Start-up code for Armv7-R (and Armv8-R once we've left EL2)
728-
//
757+
// DEPRECATED: use _stack_setup_preallocated to use sections defined
758+
// in linker script
729759
// We set up our stacks and `kmain` in system mode.
730760
#[cfg(target_arch = "arm")]
731761
core::arch::global_asm!(
@@ -779,6 +809,100 @@ core::arch::global_asm!(
779809
// return to caller
780810
bx r2
781811
.size _stack_setup, . - _stack_setup
812+
"#,
813+
und_mode = const {
814+
Cpsr::new_with_raw_value(0)
815+
.with_mode(ProcessorMode::Und)
816+
.with_i(true)
817+
.with_f(true)
818+
.raw_value()
819+
},
820+
svc_mode = const {
821+
Cpsr::new_with_raw_value(0)
822+
.with_mode(ProcessorMode::Svc)
823+
.with_i(true)
824+
.with_f(true)
825+
.raw_value()
826+
},
827+
abt_mode = const {
828+
Cpsr::new_with_raw_value(0)
829+
.with_mode(ProcessorMode::Abt)
830+
.with_i(true)
831+
.with_f(true)
832+
.raw_value()
833+
},
834+
fiq_mode = const {
835+
Cpsr::new_with_raw_value(0)
836+
.with_mode(ProcessorMode::Fiq)
837+
.with_i(true)
838+
.with_f(true)
839+
.raw_value()
840+
},
841+
irq_mode = const {
842+
Cpsr::new_with_raw_value(0)
843+
.with_mode(ProcessorMode::Irq)
844+
.with_i(true)
845+
.with_f(true)
846+
.raw_value()
847+
},
848+
sys_mode = const {
849+
Cpsr::new_with_raw_value(0)
850+
.with_mode(ProcessorMode::Sys)
851+
.with_i(true)
852+
.with_f(true)
853+
.raw_value()
854+
},
855+
te_bit = const {
856+
aarch32_cpu::register::Sctlr::new_with_raw_value(0)
857+
.with_te(true)
858+
.raw_value()
859+
}
860+
);
861+
862+
// Start-up code for Armv7-R (and Armv8-R once we've left EL2)
863+
// Stack location and sizes are taken from sections defined in linker script
864+
// We set up our stacks and `kmain` in system mode.
865+
#[cfg(target_arch = "arm")]
866+
core::arch::global_asm!(
867+
r#"
868+
// Work around https://github.com/rust-lang/rust/issues/127269
869+
.fpu vfp2
870+
871+
// Configure a stack for every mode. Leaves you in sys mode.
872+
//
873+
.section .text._stack_setup_preallocated
874+
.global _stack_setup_preallocated
875+
.type _stack_setup_preallocated, %function
876+
_stack_setup_preallocated:
877+
// Save LR from whatever mode we're currently in
878+
mov r2, lr
879+
// (we might not be in the same mode when we return).
880+
// Set stack pointer and mask interrupts for UND mode (Mode 0x1B)
881+
msr cpsr_c, {und_mode}
882+
ldr r13, =_und_stack
883+
// Set stack pointer (right after) and mask interrupts for SVC mode (Mode 0x13)
884+
msr cpsr_c, {svc_mode}
885+
ldr r13, =_svc_stack
886+
// Set stack pointer (right after) and mask interrupts for ABT mode (Mode 0x17)
887+
msr cpsr_c, {abt_mode}
888+
ldr r13, =_abt_stack
889+
// Set stack pointer (right after) and mask interrupts for IRQ mode (Mode 0x12)
890+
msr cpsr_c, {irq_mode}
891+
ldr r13, =_irq_stack
892+
// Set stack pointer (right after) and mask interrupts for FIQ mode (Mode 0x11)
893+
msr cpsr_c, {fiq_mode}
894+
ldr r13, =_fiq_stack
895+
// Set stack pointer (right after) and mask interrupts for System mode (Mode 0x1F)
896+
msr cpsr_c, {sys_mode}
897+
ldr r13, =_sys_stack
898+
// Clear the Thumb Exception bit because all our targets are currently
899+
// for Arm (A32) mode
900+
mrc p15, 0, r1, c1, c0, 0
901+
bic r1, #{te_bit}
902+
mcr p15, 0, r1, c1, c0, 0
903+
// return to caller
904+
bx r2
905+
.size _stack_setup_preallocated, . - _stack_setup_preallocated
782906
783907
// Initialises stacks, .data and .bss
784908
.section .text._init_segments
@@ -875,8 +999,7 @@ core::arch::global_asm!(
875999
.type _default_start, %function
8761000
_default_start:
8771001
// Set up stacks.
878-
ldr r0, =_stack_top
879-
bl _stack_setup
1002+
bl _stack_setup_preallocated
8801003
// Init .data and .bss
8811004
bl _init_segments
8821005
"#,
@@ -927,10 +1050,7 @@ core::arch::global_asm!(
9271050
cmp r0, {cpsr_mode_hyp}
9281051
bne 1f
9291052
// Set stack pointer
930-
ldr r0, =_stack_top
931-
mov sp, r0
932-
ldr r1, =_hyp_stack_size
933-
sub r0, r0, r1
1053+
ldr sp, =_hyp_stack
9341054
// Set the HVBAR (for EL2) to _vector_table
9351055
ldr r1, =_vector_table
9361056
mcr p15, 4, r1, c12, c0, 0
@@ -948,8 +1068,8 @@ core::arch::global_asm!(
9481068
isb
9491069
eret
9501070
1:
951-
// Set up stacks. r0 points to the bottom of the hyp stack.
952-
bl _stack_setup
1071+
// Set up stacks.
1072+
bl _stack_setup_preallocated
9531073
// Set the VBAR (for EL1) to _vector_table. NB: This isn't required on
9541074
// Armv7-R because that only supports 'low' (default) or 'high'.
9551075
ldr r0, =_vector_table

examples/mps3-an536/memory.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ MEMORY {
1212
REGION_ALIAS("VECTORS", QSPI);
1313
REGION_ALIAS("CODE", QSPI);
1414
REGION_ALIAS("DATA", DDR);
15+
REGION_ALIAS("STACKS", DDR);
1516

1617
SECTIONS {
1718
/* ### Interrupt Handler Entries
@@ -39,3 +40,4 @@ PROVIDE(_svc_stack_size = 1M);
3940
PROVIDE(_abt_stack_size = 1M);
4041
PROVIDE(_irq_stack_size = 1M);
4142
PROVIDE(_fiq_stack_size = 1M);
43+
PROVIDE(_sys_stack_size = 1M);

examples/mps3-an536/src/bin/el2_hello.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,7 @@ core::arch::global_asm!(
4343
.type _start, %function
4444
_start:
4545
// Set stack pointer
46-
ldr r0, =_stack_top
47-
mov sp, r0
48-
ldr r1, =_hyp_stack_size
49-
sub r0, r0, r1
46+
ldr sp, =_hyp_stack
5047
// Set the HVBAR (for EL2) to _vector_table
5148
ldr r1, =_vector_table
5249
mcr p15, 4, r1, c12, c0, 0

examples/versatileab/memory.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ MEMORY {
1111
REGION_ALIAS("VECTORS", SDRAM);
1212
REGION_ALIAS("CODE", SDRAM);
1313
REGION_ALIAS("DATA", SDRAM);
14+
REGION_ALIAS("STACKS", SDRAM);
1415

1516
PROVIDE(_hyp_stack_size = 1M);
1617
PROVIDE(_und_stack_size = 1M);
1718
PROVIDE(_svc_stack_size = 1M);
1819
PROVIDE(_abt_stack_size = 1M);
1920
PROVIDE(_irq_stack_size = 1M);
2021
PROVIDE(_fiq_stack_size = 1M);
22+
PROVIDE(_sys_stack_size = 1M);

0 commit comments

Comments
 (0)