尝试切换到较低的异常级别时,AArch64 执行在 ERET 后停止

问题描述

出于教育目的,我已经启动了 AArch64 的裸机应用程序。当我不将异常级别更改为较低级别时,它工作正常。但是当我想尝试将异常级别从 EL2 更改为 EL1 时,cpu 似乎在 ERET 指令之后挂起。

我当前的启动代码

#include <asm.h>

IMPORT_ASM(_cpu_el3_vec_tbl_set)
IMPORT_ASM(_cpu_el2_vec_tbl_set)
IMPORT_ASM(_cpu_el1_vec_tbl_set)

IMPORT_C(init)
IMPORT_C(main)

.text

ENTRY(_start)
    mrs x0,MPIDR_EL1
    and x0,x0,#0x3
    cmp x0,#0
    beq __elx

__wfe_cpu1_3:
    wfe
    b __wfe_cpu1_3
    
__elx:
__el3:
    mrs x0,CurrentEL
    and x0,#0xC
    asr x0,#2
    cmp x0,#3
    bne __el2
__el3_stack:
    ldr x0,=_stack_el3_e
    mov sp,x0
__el3_vector:
    bl _cpu_el3_vec_tbl_set
    msr SCTLR_EL2,xzr
    msr HCR_EL2,xzr
    mrs x0,SCR_EL3
    orr x0,#(1<<10)
    orr x0,#(1<<0)
    msr SCR_EL3,x0
    mov x0,#0b01001
    msr SPSR_EL3,x0
    adr x0,__el2
    msr ELR_EL3,x0
    eret
    
__el2:
    mrs x0,#2
    bne __el1
__el2_stack:
    ldr x0,=_stack_el2_e
    mov sp,x0
__el2_vector:
    bl _cpu_el2_vec_tbl_set
    msr SCTLR_EL1,xzr
    mov x0,xzr
    orr x0,#(1 << 31)
    msr HCR_EL2,x0
    /*orr x0,#(7 << 6) */
    adr x0,__el1
    mov x1,xzr
    orr x1,x1,#(1 << 2)
    orr x1,#(1 << 0)
    msr SPSR_EL2,x1
    msr ELR_EL2,x0
    eret
    
__el1:
__el1_stack:
    ldr x0,=_stack_el1_e
    mov sp,x0
__el1_vector:
    bl _cpu_el1_vec_tbl_set
    
    ldr x0,=_bss_s
    ldr x1,=_bss_e
    sub x1,x0
    mov x2,#0x0
    cbz x1,__init
__bss:
    strb w2,[x0],#1
    sub x1,#1
    cbnz x1,__bss
    
__init:
    bl init

__main:
    bl main
__main_wfe:
    wfe
    b __main_wfe

.end

当我注释掉标签 __elx__el1间的部分时,它会起作用(C 函数 initmain 将被执行)。我还尝试在 init 指令之前和之后放置 ERET (目前只包含一个函数,它通过 UART 打印出当前异常级别)。结果是,永远不会执行 init 之后的 ERET 调用

不知道这里出了什么问题。

编辑:
我还创建了一个带有 EL2EL1 处理程序的向量表。但不幸的是不会抛出异常。

更新:
好的,将输入 EL1。但是在 EL1 中运行时,我的 C 代码的某些部分有一些奇怪的问题:

首先:
EL1 中的 C 代码执行速度(主观上)比 EL2 中慢。

第二:
C 代码中的某些部分(我的 sprintf 实现)没有被调用。这里的奇怪之处在于 sprintf,它在 EL2 中没有问题。

HCR_EL2 和/或 SCTLR_EL1 的配置可能有误吗? 目前我用零初始化 HCR_EL2SCTLR_EL1,并在 RW 中设置 HCR_EL2 位(AArch64 状态)。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)