armv8 将异常级别从 el2 更改为 el1

armv8 changing exception level from el2 to el1

我正在尝试编写简单的 efi 应用程序,将异常级别从 el2 64 位更改为 el1 64 位,但没有成功。

void entry_el1(void){
    Print (L"running in el1.\n\r");
}

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{   


    __asm__ volatile (
    "mov x0, #(1 << 31)\n\t"
    "msr hcr_el2, x0\n\t"

    "mov x0, #0x0800\n\t"
    "movk x0, #0x30d0, lsl #16\n\t"
    "msr sctlr_el1, x0\n\t"

    "mov x0, #0x33ff\n\t"
    "msr cptr_el2, x0\n\t"

    "msr hstr_el2, xzr\n\t"

    "mov x0, #0x3c5\n\t" 
    "msr spsr_el2, x0\n\t"

    "mov x0, %0\n\t"  
    "msr elr_el2, x0\n\t"

    "eret" : : "r" (entry_el1) :
    );

    return EFI_SUCCESS;
}

在运行之后什么也没有发生!这是更改异常级别的正确程序吗?

假设不仅仅是内联 asm 上缺少破坏列表导致你的 ELR_EL2 地址被破坏(在这种情况下直接跳到下面的 "triggers an exception"),我认为你是降到 EL1 就好了;当您到达那里时,麻烦就开始了...

作为非叶 C 函数,entry_el1 要做的第一件事是将 return 地址压入堆栈(或者如果编译器足够聪明将其优化为没有堆栈框架的尾调用,那么 Print 的序言就是这样做的人,但同样的事情)。除了我们处于处理程序模式 (EL1h) 之外,这意味着除非有人在乱用 SPSel,否则我们的堆栈指针是 SP_EL1,此时它可能包含未初始化的废话。因此,堆栈访问几乎肯定会触发异常,但我们处于 EL1,因此异常被带到 VBAR_EL1 指向的向量,此时可能包含未初始化的废话。你好,递归异常导致锁死。

如果您正在与 Linux 入口代码进行比较,那么请务必注意,当(如果)从 EL2 下降时,它仍然会进入更多设置 EL1 的裸机汇编代码在接近 C 代码之前从头开始 - 实际上,设置堆栈指针是它所做的最后事情之一。