From: David Woodhouse Date: Fri, 2 Aug 2024 17:17:02 +0000 (+0100) Subject: WIP: Attempt to support interruptible exception handling on x86 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Fclocks;p=users%2Fdwmw2%2Flinux.git WIP: Attempt to support interruptible exception handling on x86 Signed-off-by: David Woodhouse --- diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 2bec0c89a95c2..854ccd5f23422 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -229,6 +229,9 @@ register unsigned long current_stack_pointer asm(_ASM_SP); #define _ASM_EXTABLE_UA(from, to) \ _ASM_EXTABLE_TYPE(from, to, EX_TYPE_UACCESS) +#define _ASM_EXTABLE_UA_INTR(from, to) \ + _ASM_EXTABLE_TYPE(from, to, EX_TYPE_UACCESS_INTERRUPTIBLE) + #define _ASM_EXTABLE_FAULT(from, to) \ _ASM_EXTABLE_TYPE(from, to, EX_TYPE_FAULT) diff --git a/arch/x86/include/asm/extable_fixup_types.h b/arch/x86/include/asm/extable_fixup_types.h index 906b0d5541e89..651d42f39e9ba 100644 --- a/arch/x86/include/asm/extable_fixup_types.h +++ b/arch/x86/include/asm/extable_fixup_types.h @@ -36,7 +36,7 @@ #define EX_TYPE_DEFAULT 1 #define EX_TYPE_FAULT 2 #define EX_TYPE_UACCESS 3 -/* unused, was: #define EX_TYPE_COPY 4 */ +#define EX_TYPE_UACCESS_INTERRUPTIBLE 4 #define EX_TYPE_CLEAR_FS 5 #define EX_TYPE_FPU_RESTORE 6 #define EX_TYPE_BPF 7 diff --git a/arch/x86/include/asm/trapnr.h b/arch/x86/include/asm/trapnr.h index 8d1154cdf7875..9f6397bad3988 100644 --- a/arch/x86/include/asm/trapnr.h +++ b/arch/x86/include/asm/trapnr.h @@ -41,4 +41,5 @@ #define X86_TRAP_VC 29 /* VMM Communication Exception */ #define X86_TRAP_IRET 32 /* IRET Exception */ +#define X86_TRAP_INTERRUPTIBLE 0x40000000 /* Internal, for interruptible exceptions */ #endif diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index cef729a256559..ab00150d360b5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3819,12 +3819,15 @@ static void record_steal_time(struct kvm_vcpu *vcpu) asm volatile("1: xchgb %0, %2\n" "xor %1, %1\n" "2:\n" - _ASM_EXTABLE_UA(1b, 2b) + _ASM_EXTABLE_UA_INTR(1b, 2b) : "+q" (st_preempted), "+&r" (err), "+m" (st->preempted)); - if (err) + if (err) { + if (signal_pending(current)) + err = -EINTR; goto out; + } user_access_end(); diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 51986e8a9d353..d2cef84042a5a 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -325,6 +325,12 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code, reg = FIELD_GET(EX_DATA_REG_MASK, e->data); imm = FIELD_GET(EX_DATA_IMM_MASK, e->data); + if (trapnr & X86_TRAP_INTERRUPTIBLE) { + trapnr &= ~X86_TRAP_INTERRUPTIBLE; + if (type != EX_TYPE_UACCESS_INTERRUPTIBLE) + return 0; + } + switch (type) { case EX_TYPE_DEFAULT: case EX_TYPE_DEFAULT_MCE_SAFE: @@ -333,6 +339,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code, case EX_TYPE_FAULT_MCE_SAFE: return ex_handler_fault(e, regs, trapnr); case EX_TYPE_UACCESS: + case EX_TYPE_UACCESS_INTERRUPTIBLE: return ex_handler_uaccess(e, regs, trapnr, fault_addr); case EX_TYPE_CLEAR_FS: return ex_handler_clear_fs(e, regs); diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index e6c469b323ccb..aa9dec82e612e 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1388,18 +1388,6 @@ retry: */ fault = handle_mm_fault(vma, address, flags, regs); - if (fault_signal_pending(fault, regs)) { - /* - * Quick path to respond to signals. The core mm code - * has unlocked the mm for us if we get here. - */ - if (!user_mode(regs)) - kernelmode_fixup_or_oops(regs, error_code, address, - SIGBUS, BUS_ADRERR, - ARCH_DEFAULT_PKEY); - return; - } - /* The fault is fully completed (including releasing mmap lock) */ if (fault & VM_FAULT_COMPLETED) return; @@ -1410,6 +1398,29 @@ retry: * that we made any progress. Handle this case first. */ if (unlikely(fault & VM_FAULT_RETRY)) { + if (signal_pending(current)) { + if (user_mode(regs)) + return; + + if (fatal_signal_pending(current)) { + kernelmode_fixup_or_oops(regs, error_code, address, + SIGBUS, BUS_ADRERR, + ARCH_DEFAULT_PKEY); + return; + } + + /* + * First time round, if woken by a signal, see if there + * is an interruptible exception handler. If so, do it. + * Else, switch off FAULT_FLAG_INTERRUPTIBLE. + */ + if (fixup_exception(regs, X86_TRAP_INTERRUPTIBLE | X86_TRAP_PF, + error_code, address)) + return; + + flags &= ~FAULT_FLAG_INTERRUPTIBLE; + } + flags |= FAULT_FLAG_TRIED; goto retry; }