Right now we have two IRET instructions that can fault for guest reasons, and the pre exception table gives handle_exception as the fixup for both.
Instead, we can have compat_restore_all_guest() use restore_all_guest()'s IRET which gives us just a single position to handle specially. In exception_with_ints_disabled(), remove search_pre_exception_table() and use a simpler check. Explain how the recovery works, because this isn't the first time I've had to figure it out. The reference to iret_to_guest highlights that any checking here is specific to CONFIG_PV, so exclude it in !PV builds. Later in exception_with_ints_disabled(), it suffices to load %ecx rather than %rcx, and remove a stray semi-colon from the rep movsq. No functional change. Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com> --- CC: Jan Beulich <jbeul...@suse.com> CC: Roger Pau Monné <roger....@citrix.com> v2: * New --- xen/arch/x86/x86_64/compat/entry.S | 3 +-- xen/arch/x86/x86_64/entry.S | 31 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S index d7b381ea546d..39925d80a677 100644 --- a/xen/arch/x86/x86_64/compat/entry.S +++ b/xen/arch/x86/x86_64/compat/entry.S @@ -167,8 +167,7 @@ FUNC(compat_restore_all_guest) scf=STK_REL(CPUINFO_scf, CPUINFO_rip), \ sel=STK_REL(CPUINFO_verw_sel, CPUINFO_rip) -.Lft0: iretq - _ASM_PRE_EXTABLE(.Lft0, handle_exception) + jmp iret_to_guest END(compat_restore_all_guest) /* Callers can cope with both %rax and %rcx being clobbered. */ diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index c02245ac064c..01b431793b7b 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -241,8 +241,9 @@ iret_exit_to_guest: SPEC_CTRL_COND_VERW /* Req: %rsp=eframe Clob: efl */ addq $8,%rsp -.Lft0: iretq - _ASM_PRE_EXTABLE(.Lft0, handle_exception) + +LABEL(iret_to_guest, 0) + iretq END(restore_all_guest) /* @@ -920,10 +921,23 @@ handle_exception_saved: exception_with_ints_disabled: testb $3,UREGS_cs(%rsp) # interrupts disabled outside Xen? jnz FATAL_exception_with_ints_disabled - movq %rsp,%rdi - call search_pre_exception_table - testq %rax,%rax # no fixup code for faulting EIP? - jz .Ldispatch_exceptions + +#ifndef CONFIG_PV + /* No PV? No IRETs-to-guest to worry about. */ + jmp .Ldispatch_exceptions +#else + /* Check to see if the exception was on the IRET to guest context. */ + lea iret_to_guest(%rip), %rax + cmp %rax, UREGS_rip(%rsp) + jne .Ldispatch_exceptions + + /* + * Recovery is at handle_exception. It may be necessary to make space + * on the interrupted stack for ec/ev, after which the current ec/ev + * is copied to make it appear as if this exception occurred in guest + * context. + */ + lea handle_exception(%rip), %rax movq %rax,UREGS_rip(%rsp) # fixup regular stack #ifdef CONFIG_XEN_SHSTK @@ -940,13 +954,14 @@ exception_with_ints_disabled: movq %rsp,%rsi subq $8,%rsp movq %rsp,%rdi - movq $UREGS_kernel_sizeof/8,%rcx - rep; movsq # make room for ec/ev + mov $UREGS_kernel_sizeof/8, %ecx + rep movsq # make room for ec/ev 1: movq UREGS_error_code(%rsp),%rax # ec/ev movq %rax,UREGS_kernel_sizeof(%rsp) mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14) mov %r13b, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14) jmp restore_all_xen # return to fixup code +#endif /* !CONFIG_PV */ /* No special register assumptions. */ FATAL_exception_with_ints_disabled: -- 2.39.5