SP0和SPn在AArch64中分别代表什么?

huangapple go评论86阅读模式
英文:

What is SP0 and SPn in AArch64?

问题

如果异常发生在相同的异常级别,要使用的堆栈指针是(SP0还是SPn)。

在AArch64异常向量表的文档中,根据上述因素选择一个条目。我找不到关于SP0和SPn的有用信息,所以我想问一下为什么会有两个堆栈指针以及它们之间的区别是什么?如果有链接会更好!

英文:

> 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!

答案1

得分: 1

免责声明:我并不是 Armv8-a 架构的专家,只是写了一些裸机代码来处理 Cortex-A53 上的异常,目的是学习。

你指向的文档简要解释了以下几点:

  • 每个异常级别都有一个堆栈指针,即 EL0 的 SP_EL0,EL1 的 SP_EL1,EL2 的 SP_EL2 以及 EL3 的 SP_EL3。
  • 当在特定的异常级别执行代码时,用于存储异常上下文并由异常处理程序访问保存的上下文的堆栈指针将取决于 SPSel 系统寄存器在异常发生时的值。

来自 SPSel 系统寄存器的 Arm 文档:

位 [63:1] 保留,RES0。
SP,位 [0] 要使用的堆栈指针。此位的可能值为:

0b0 在所有异常级别上使用 SP_EL0。
0b1 在异常级别 ELx 上使用 SP_ELx。

此字段的复位行为是:在热重置时,此字段复位为 1。

使用专用于特定异常级别的堆栈指针有助于更好地隔离在 EL3 上执行的代码与在 EL2..EL0 上执行的权限较低的代码,因为可以为每个异常级别实现不同的内存区域用于堆栈。

如果你正在编写自己的裸机代码,设置 SPSel 中的值最终将取决于你的选择。例如,在 Allwinner H6 Cortex-A53 上使用标准的 Arm 受信任固件(在 EL3 上运行的代码)/u-boot(在 EL2 上运行的代码)包时:

SPSel.s:

.global _start
.align 3
.text
_start:
    mrs x0, SPSel
    ret

构建:

/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

执行:

=> 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
=>

x0 中返回的 SPSel 的值为 0,即 SP 位于 SPSel 中为 0,因此在所有的 EL3..EL0 异常级别上都将使用 SP_EL0 作为堆栈指针寄存器。

英文:

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:

  • There are one stack pointer per exception level, i.e. SP_EL0 for EL0, SP_EL1 for EL1, SP_EL2 for EL2 and SP_EL3 for EL3,
  • When you execute code at a given exception level, the stack pointer that will be used for storing the exception context and by the exception handler to access the saved context will depend on the value of the SPSel system register at the time the exception occurred.

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 SPSelis 0, and SP_EL0 is therefore the stack-pointer register that will be used at all EL3..EL0 exception levels.

huangapple
  • 本文由 发表于 2023年2月18日 09:23:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/75490597.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定