From: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx> Exception table is used to fixup from a faulty instruction execution. In TDX scenario, some instructions trigger #VE and are simulated through tdvmcall. If the simulation fails, the instruction is treated as faulty and should be checked with the exception table to fixup. Move struct ex_record, exception_table_[start|end] to lib/x86/desc.h as it's a general declaration and will be used in TDX. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx> Reviewed-by: Yu Zhang <yu.c.zhang@xxxxxxxxx> Link: https://lore.kernel.org/r/20220303071907.650203-5-zhenzhong.duan@xxxxxxxxx Signed-off-by: Qian Wen <qian.wen@xxxxxxxxx> --- lib/x86/desc.c | 7 ------- lib/x86/desc.h | 6 ++++++ lib/x86/tdx.c | 23 ++++++++++++++++++++++- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/x86/desc.c b/lib/x86/desc.c index 5b41549e..14edac0c 100644 --- a/lib/x86/desc.c +++ b/lib/x86/desc.c @@ -100,13 +100,6 @@ void set_idt_sel(int vec, u16 sel) e->selector = sel; } -struct ex_record { - unsigned long rip; - unsigned long handler; -}; - -extern struct ex_record exception_table_start, exception_table_end; - const char* exception_mnemonic(int vector) { switch(vector) { diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 7778a0f8..54b3166f 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -237,6 +237,12 @@ extern tss64_t tss[]; #endif extern gdt_entry_t gdt[]; +struct ex_record { + unsigned long rip; + unsigned long handler; +}; +extern struct ex_record exception_table_start, exception_table_end; + unsigned exception_vector(void); unsigned exception_error_code(void); bool exception_rflags_rf(void); diff --git a/lib/x86/tdx.c b/lib/x86/tdx.c index d10e02b9..4f8bbad7 100644 --- a/lib/x86/tdx.c +++ b/lib/x86/tdx.c @@ -303,6 +303,22 @@ done: return !!tdx_guest; } +static bool tdx_check_exception_table(struct ex_regs *regs) +{ + struct ex_record *ex; + + for (ex = &exception_table_start; ex != &exception_table_end; ++ex) { + if (ex->rip == regs->rip) { + regs->rip = ex->handler; + return true; + } + } + unhandled_exception(regs, false); + + /* never reached */ + return false; +} + static bool tdx_get_ve_info(struct ve_info *ve) { struct tdx_module_args args = {}; @@ -334,8 +350,13 @@ static bool tdx_get_ve_info(struct ve_info *ve) static bool tdx_handle_virt_exception(struct ex_regs *regs, struct ve_info *ve) { + unsigned int ex_val; int insn_len = -EIO; + /* #VE exit_reason in bit16-32 */ + ex_val = regs->vector | (ve->exit_reason << 16); + asm("mov %0, %%gs:4" : : "r"(ex_val)); + switch (ve->exit_reason) { case EXIT_REASON_HLT: insn_len = handle_halt(regs, ve); @@ -357,7 +378,7 @@ static bool tdx_handle_virt_exception(struct ex_regs *regs, return false; } if (insn_len < 0) - return false; + return tdx_check_exception_table(regs); /* After successful #VE handling, move the IP */ regs->rip += insn_len; -- 2.25.1