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

Exception armv8将异常级别从el2更改为el1,exception,arm,uefi,Exception,Arm,Uefi,我正在尝试编写简单的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 ( "m

我正在尝试编写简单的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;
}
void条目\u el1(void){
打印(L“在el1中运行。\n\r”);
}
EFI_状态
EFIAPI
尤菲曼(
在EFI_HANDLE ImageHandle中,
在EFI_系统_表*系统表中
)
{   
__反复无常(

“mov x0,#(1假设这不仅仅是内联asm上缺少一个clobber列表导致您的ELR_EL2地址被破坏(在这种情况下,直接跳到下面的“触发异常”),我认为您降到EL1很好;当您到达那里时,问题开始了

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


如果您要与Linux入口代码进行比较,那么需要注意的是从EL2开始,它仍然会进入更多的裸机汇编代码,在EL1接近C代码之前,从头开始设置EL1——事实上,设置堆栈指针是它最后要做的事情之一。

首先也是最明显的,检查你的反汇编;如何阻止编译器在
x0
中传递
%0
>?此外,我对EDK2知之甚少,对其他UEFI实现一无所知,因此这可能是假设,但EL2地址在EL1仍然有效吗(即,此时MMU的设置是什么)?相反,您是否确定它实际上没有工作,只是在尝试返回错误的EL时崩溃,而没有刷新输出缓冲区?据我所知,应用程序在EL2中启动,具有标识映射。在EL1中,MMU在两个阶段都处于关闭状态,因此返回地址应该是有效的。Lin中使用了几乎类似的代码“el2_设置”函数中的ux…感谢您的提醒!我非常关心内联程序集,完全忘记了C函数调用约定。我用裸机程序集替换了它,现在它可以工作了!