我正在一个没有原生环3支持的单内核上启用英特尔SGX。因此,为了调用用户模式SGX指令,我需要实现一个环形开关例程。我遵循了james的教程(10)。-用户模式(jamesmolloy.com .co.uk),这是一个32位的解决方案)起草一个长模式版本:
void switch_to_ring3()
{
asm volatile("
mov $0x23, %rax;
mov %rax, %ds;
mov %rax, %es;
mov %rsp, %rax;
push $0x23;
push %rax;
pushf;
push $0x1B;
push $1f;
iretq;
1:
");
return;
}
我确信我已经正确设置了GDT条目,0x23/0x1B正是用户模式代码/数据描述符的索引,其中代码描述符值为0xaffb000000ffff
,数据描述符值为0xaff3000000ffff
。
奇怪的是,iretq
可以成功执行,rip
寄存器可以转到iretq
的下一个指令,如果我禁用优化,这是nop
,如果我启用优化,这是ret
。然而,当执行下一条指令时,它将在没有任何输出的情况下死亡(我的unikernel有一个异常处理程序,即使对于未处理的异常,它也会输出一些东西)。我试着用GDB调试,GDB说程序收到SIGQUIT.
我检查了寄存器,但没有发现任何错误,cs是0x1b, ss, ds和es是0x23,rip
正确指向iretq
的下一条指令。
我真的很困惑为什么它接收SIGQUIT。如果发生了一些异常,它应该输出转储消息,或者至少qemu日志将跟踪一些'check_exception'消息,但日志是空的。一切似乎都很好,正确的段寄存器,正确的rsp/rbp/rip
,内核代码段是用户可以通过设置其描述符的一致位来访问的,并且所有描述符中的高/低基址都指向0x0。
被这个问题困了一整天却找不到解决办法。我希望这里有人能救我的命t
我最终通过为所有内核代码/数据页设置U/S位来修复它。谢谢你的评论@prl @PeterCordes !