If the exception is being taken at the same Exception level, the stack pointer to be used (SP0 or SPn)
In a document of AArch64 exception vector table, an entry is selected based off the factor above. I couldn't find any useful information regarding SP0 and SPn, so I'd like to ask why there are two stack pointers and what's the difference between them? A link is also appreciated!
Disclaimer: I am not an expert on the Armv8-a architecture, I have just been writing some bare-metal code dealing with exceptions on a Cortex-A53 for the purpose of learning.
The document you are pointing to explains, although succinctly, that:
From the Arm documentation for the SPSel system register:
Bits [63:1] Reserved, RES0.
SP, bit [0] Stack pointer to use. Possible values of this bit are:
0b0 Use SP_EL0 at all Exception levels.
0b1 Use SP_ELx for Exception level ELx.
The reset behaviour of this field is: On a Warm reset, this field resets to 1.
Using the stack pointer dedicated to a given exception level helps isolating more the code executing at, say, EL3, from the less-privileged code executing at EL2..EL0, since different memory areas can be used for implementing the stack for each exception level.
If you are writing your own bare-metal code, the value to set in SPSel would ultimately be your choice: For example, when using a standard Arm-Trusted firmware (code running at EL3)/u-boot (code running at EL2) bundle on an Alwinner H6 Cortex-A53:
SPSel.s:
.global _start
.align 3
.text
_start:
mrs x0, SPSel
ret
Building:
/opt/arm/11/gcc-arm-11.2-2022.02-x86_64-aarch64-none-elf/bin/aarch64-none-elf-gcc -nostartfiles -nostdlib --freestanding -Wl,--section-start=.text=0x40080000 -o SPSel.elf SPSel.s
/opt/arm/11/gcc-arm-11.2-2022.02-x86_64-aarch64-none-elf/bin/aarch64-none-elf-objcopy -O srec SPSel.elf SPSel.srec
/opt/arm/11/gcc-arm-11.2-2022.02-x86_64-aarch64-none-elf/bin/aarch64-none-elf-objdump -D -j .text SPSel.elf > SPSel.lst
Executing:
=> loads
## Ready for S-Record download ...
## First Load Addr = 0x40080000
## Last Load Addr = 0x40080007
## Total Size = 0x00000008 = 8 Bytes
## Start Addr = 0x40080000
=> go 0x40080000
## Starting application at 0x40080000 ...
## Application terminated, rc = 0x0
=>
The value of SPSel
returned in x0
is 0, i.e. the SP
bit of SPSel
is 0, and SP_EL0
is therefore the stack-pointer register that will be used at all EL3..EL0 exception levels.