x86/entry/64: Fix and clean up paranoid_exit
[platform/kernel/linux-rpi.git] / arch / x86 / entry / entry_64.S
index 20e45d9..670306f 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/export.h>
 #include <asm/frame.h>
 #include <asm/nospec-branch.h>
+#include <asm/fsgsbase.h>
 #include <linux/err.h>
 
 #include "calling.h"
@@ -878,7 +879,7 @@ apicinterrupt IRQ_WORK_VECTOR                       irq_work_interrupt              smp_irq_work_interrupt
  * @paranoid == 2 is special: the stub will never switch stacks.  This is for
  * #DF: if the thread stack is somehow unusable, we'll still get a useful OOPS.
  */
-.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ist_offset=0
+.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ist_offset=0 create_gap=0
 ENTRY(\sym)
        UNWIND_HINT_IRET_REGS offset=\has_error_code*8
 
@@ -898,6 +899,20 @@ ENTRY(\sym)
        jnz     .Lfrom_usermode_switch_stack_\@
        .endif
 
+       .if \create_gap == 1
+       /*
+        * If coming from kernel space, create a 6-word gap to allow the
+        * int3 handler to emulate a call instruction.
+        */
+       testb   $3, CS-ORIG_RAX(%rsp)
+       jnz     .Lfrom_usermode_no_gap_\@
+       .rept   6
+       pushq   5*8(%rsp)
+       .endr
+       UNWIND_HINT_IRET_REGS offset=8
+.Lfrom_usermode_no_gap_\@:
+       .endif
+
        .if \paranoid
        call    paranoid_entry
        .else
@@ -933,7 +948,6 @@ ENTRY(\sym)
        addq    $\ist_offset, CPU_TSS_IST(\shift_ist)
        .endif
 
-       /* these procedures expect "no swapgs" flag in ebx */
        .if \paranoid
        jmp     paranoid_exit
        .else
@@ -1129,7 +1143,7 @@ apicinterrupt3 HYPERV_STIMER0_VECTOR \
 #endif /* CONFIG_HYPERV */
 
 idtentry debug                 do_debug                has_error_code=0        paranoid=1 shift_ist=IST_INDEX_DB ist_offset=DB_STACK_OFFSET
-idtentry int3                  do_int3                 has_error_code=0
+idtentry int3                  do_int3                 has_error_code=0        create_gap=1
 idtentry stack_segment         do_stack_segment        has_error_code=1
 
 #ifdef CONFIG_XEN_PV
@@ -1150,24 +1164,21 @@ idtentry machine_check          do_mce                  has_error_code=0        paranoid=1
 #endif
 
 /*
- * Save all registers in pt_regs, and switch gs if needed.
- * Use slow, but surefire "are we in kernel?" check.
- * Return: ebx=0: need swapgs on exit, ebx=1: otherwise
+ * Save all registers in pt_regs. Return GSBASE related information
+ * in EBX depending on the availability of the FSGSBASE instructions:
+ *
+ * FSGSBASE    R/EBX
+ *     N        0 -> SWAPGS on exit
+ *              1 -> no SWAPGS on exit
+ *
+ *     Y        GSBASE value at entry, must be restored in paranoid_exit
  */
 ENTRY(paranoid_entry)
        UNWIND_HINT_FUNC
        cld
        PUSH_AND_CLEAR_REGS save_ret=1
        ENCODE_FRAME_POINTER 8
-       movl    $1, %ebx
-       movl    $MSR_GS_BASE, %ecx
-       rdmsr
-       testl   %edx, %edx
-       js      1f                              /* negative -> in kernel */
-       SWAPGS
-       xorl    %ebx, %ebx
 
-1:
        /*
         * Always stash CR3 in %r14.  This value will be restored,
         * verbatim, at exit.  Needed if paranoid_entry interrupted
@@ -1177,9 +1188,49 @@ ENTRY(paranoid_entry)
         * This is also why CS (stashed in the "iret frame" by the
         * hardware at entry) can not be used: this may be a return
         * to kernel code, but with a user CR3 value.
+        *
+        * Switching CR3 does not depend on kernel GSBASE so it can
+        * be done before switching to the kernel GSBASE. This is
+        * required for FSGSBASE because the kernel GSBASE has to
+        * be retrieved from a kernel internal table.
         */
        SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14
 
+        /*
+        * Handling GSBASE depends on the availability of FSGSBASE.
+        *
+        * Without FSGSBASE the kernel enforces that negative GSBASE
+        * values indicate kernel GSBASE. With FSGSBASE no assumptions
+        * can be made about the GSBASE value when entering from user
+        * space.
+       */
+       ALTERNATIVE "jmp .Lparanoid_entry_checkgs", "", X86_FEATURE_FSGSBASE
+
+       /*
+        * Read the current GSBASE and store it in in %rbx unconditionally,
+        * retrieve and set the current CPUs kernel GSBASE. The stored value
+        * has to be restored in paranoid_exit unconditionally.
+        */
+       SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
+       ret
+
+.Lparanoid_entry_checkgs:
+       /* EBX = 1 -> kernel GSBASE active, no restore required */
+       movl    $1, %ebx
+       /*
+        * The kernel-enforced convention is a negative GSBASE indicates
+        * a kernel value. No SWAPGS needed on entry and exit.
+        */
+       movl    $MSR_GS_BASE, %ecx
+       rdmsr
+       testl   %edx, %edx
+       jns     .Lparanoid_entry_swapgs
+       ret
+
+.Lparanoid_entry_swapgs:
+       SWAPGS
+       /* EBX = 0 -> SWAPGS required on exit */
+       xorl    %ebx, %ebx
        ret
 END(paranoid_entry)
 
@@ -1190,28 +1241,48 @@ END(paranoid_entry)
  *
  * We may be returning to very strange contexts (e.g. very early
  * in syscall entry), so checking for preemption here would
- * be complicated.  Fortunately, we there's no good reason
- * to try to handle preemption here.
+ * be complicated.  Fortunately, there's no good reason to try
+ * to handle preemption here.
+ *
+ * R/EBX contains the GSBASE related information depending on the
+ * availability of the FSGSBASE instructions:
  *
- * On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it)
+ * FSGSBASE    R/EBX
+ *     N        0 -> SWAPGS on exit
+ *              1 -> no SWAPGS on exit
+ *
+ *     Y        User space GSBASE, must be restored unconditionally
  */
 ENTRY(paranoid_exit)
        UNWIND_HINT_REGS
        DISABLE_INTERRUPTS(CLBR_ANY)
-       TRACE_IRQS_OFF_DEBUG
-       testl   %ebx, %ebx                      /* swapgs needed? */
-       jnz     .Lparanoid_exit_no_swapgs
-       TRACE_IRQS_IRETQ
-       /* Always restore stashed CR3 value (see paranoid_entry) */
-       RESTORE_CR3     scratch_reg=%rbx save_reg=%r14
-       SWAPGS_UNSAFE_STACK
-       jmp     .Lparanoid_exit_restore
-.Lparanoid_exit_no_swapgs:
+
+       /*
+        * The order of operations is important.  IRQ tracing requires
+        * kernel GSBASE and CR3.  RESTORE_CR3 requires kernel GS base.
+        *
+        * NB to anyone to tries to optimize this code: this code does
+        * not execute at all for exceptions coming from user mode.  Those
+        * exceptions go through error_exit instead.
+        */
        TRACE_IRQS_IRETQ_DEBUG
-       /* Always restore stashed CR3 value (see paranoid_entry) */
-       RESTORE_CR3     scratch_reg=%rbx save_reg=%r14
-.Lparanoid_exit_restore:
-       jmp restore_regs_and_return_to_kernel
+       RESTORE_CR3     scratch_reg=%rax save_reg=%r14
+
+       /* Handle the three GSBASE cases. */
+       ALTERNATIVE "jmp .Lparanoid_exit_checkgs", "", X86_FEATURE_FSGSBASE
+
+       /* With FSGSBASE enabled, unconditionally restore GSBASE */
+       wrgsbase        %rbx
+       jmp     restore_regs_and_return_to_kernel
+
+.Lparanoid_exit_checkgs:
+       /* On non-FSGSBASE systems, conditionally do SWAPGS */
+       testl   %ebx, %ebx
+       jnz     restore_regs_and_return_to_kernel
+
+       /* We are returning to a context with user GSBASE. */
+       SWAPGS_UNSAFE_STACK
+       jmp     restore_regs_and_return_to_kernel
 END(paranoid_exit)
 
 /*
@@ -1622,10 +1693,27 @@ end_repeat_nmi:
        /* Always restore stashed CR3 value (see paranoid_entry) */
        RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
 
-       testl   %ebx, %ebx                      /* swapgs needed? */
+       /*
+        * The above invocation of paranoid_entry stored the GSBASE
+        * related information in R/EBX depending on the availability
+        * of FSGSBASE.
+        *
+        * If FSGSBASE is enabled, restore the saved GSBASE value
+        * unconditionally, otherwise take the conditional SWAPGS path.
+        */
+       ALTERNATIVE "jmp nmi_no_fsgsbase", "", X86_FEATURE_FSGSBASE
+
+       wrgsbase        %rbx
+       jmp     nmi_restore
+
+nmi_no_fsgsbase:
+       /* EBX == 0 -> invoke SWAPGS */
+       testl   %ebx, %ebx
        jnz     nmi_restore
+
 nmi_swapgs:
        SWAPGS_UNSAFE_STACK
+
 nmi_restore:
        POP_REGS
 
@@ -1656,11 +1744,17 @@ nmi_restore:
        iretq
 END(nmi)
 
+#ifndef CONFIG_IA32_EMULATION
+/*
+ * This handles SYSCALL from 32-bit code.  There is no way to program
+ * MSRs to fully disable 32-bit SYSCALL.
+ */
 ENTRY(ignore_sysret)
        UNWIND_HINT_EMPTY
        mov     $-ENOSYS, %eax
        sysret
 END(ignore_sysret)
+#endif
 
 ENTRY(rewind_stack_do_exit)
        UNWIND_HINT_FUNC