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
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
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
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" ) ]
497525core:: 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" ) ]
731761core:: 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
0 commit comments