From: Lai Jiangshan <jiangshanlai@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: x86@kernel.org, Lai Jiangshan <laijs@linux.alibaba.com>,
Andy Lutomirski <luto@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
"H. Peter Anvin" <hpa@zytor.com>,
Peter Zijlstra <peterz@infradead.org>
Subject: [PATCH V4 24/50] x86/entry: Implement the whole error_entry() as C code
Date: Tue, 26 Oct 2021 22:32:33 +0800 [thread overview]
Message-ID: <20211026143301.18895-1-jiangshanlai@gmail.com> (raw)
In-Reply-To: <20211026141420.17138-1-jiangshanlai@gmail.com>
From: Lai Jiangshan <laijs@linux.alibaba.com>
All the needed facilities are set in entry64.c, the whole error_entry()
can be implemented in C in entry64.c. The C version generally has better
readability and easier to be updated/improved.
No function change intended.
Signed-off-by: Lai Jiangshan <laijs@linux.alibaba.com>
---
arch/x86/entry/entry64.c | 63 +++++++++++++++++++++++++++
arch/x86/entry/entry_64.S | 82 +-----------------------------------
arch/x86/include/asm/traps.h | 1 +
3 files changed, 65 insertions(+), 81 deletions(-)
diff --git a/arch/x86/entry/entry64.c b/arch/x86/entry/entry64.c
index 173cf621317c..a8e59ae41794 100644
--- a/arch/x86/entry/entry64.c
+++ b/arch/x86/entry/entry64.c
@@ -77,3 +77,66 @@ static __always_inline void kernel_entry_swapgs_and_fence(void)
native_swapgs();
fence_swapgs_kernel_entry();
}
+
+/*
+ * Put pt_regs onto the task stack and switch GS and CR3 if needed.
+ * The actual stack switch is done in entry_64.S.
+ *
+ * Be careful, it might be in the user CR3 and user GS base at the start
+ * of the function.
+ */
+asmlinkage __visible __entry_text
+struct pt_regs *error_entry(struct pt_regs *eregs)
+{
+ unsigned long iret_ip = (unsigned long)native_irq_return_iret;
+
+ if (user_mode(eregs)) {
+ /*
+ * We entered from user mode.
+ * Switch to kernel gsbase and CR3.
+ */
+ user_entry_swapgs_and_fence();
+ switch_to_kernel_cr3();
+
+ /* Put pt_regs onto the task stack. */
+ return sync_regs(eregs);
+ }
+
+ /*
+ * There are two places in the kernel that can potentially fault with
+ * usergs. Handle them here. B stepping K8s sometimes report a
+ * truncated RIP for IRET exceptions returning to compat mode. Check
+ * for these here too.
+ */
+ if ((eregs->ip == iret_ip) || (eregs->ip == (unsigned int)iret_ip)) {
+ eregs->ip = iret_ip; /* Fix truncated RIP */
+
+ /*
+ * We came from an IRET to user mode, so we have user
+ * gsbase and CR3. Switch to kernel gsbase and CR3:
+ */
+ user_entry_swapgs_and_fence();
+ switch_to_kernel_cr3();
+
+ /*
+ * Pretend that the exception came from user mode: set up
+ * pt_regs as if we faulted immediately after IRET and put
+ * pt_regs onto the real task stack.
+ */
+ return sync_regs(fixup_bad_iret(eregs));
+ }
+
+ /*
+ * Hack: asm_load_gs_index_gs_change can fail with user gsbase.
+ * If this happens, fix up gsbase and proceed. We'll fix up the
+ * exception and land in asm_load_gs_index_gs_change's error
+ * handler with kernel gsbase.
+ */
+ if (eregs->ip == (unsigned long)asm_load_gs_index_gs_change)
+ kernel_entry_swapgs_and_fence();
+ else
+ fence_swapgs_kernel_entry();
+
+ /* Enter from kernel, don't move pt_regs */
+ return eregs;
+}
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index b97ce4204f6d..23de2a789e3d 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -334,7 +334,7 @@ SYM_CODE_END(ret_from_fork)
* XENPV uses its own pvops for iret and load_gs_index(). And it
* doesn't need to switch CR3. So it can skip invoking error_entry().
*/
- ALTERNATIVE "call error_entry; movq %rax, %rsp", \
+ ALTERNATIVE "movq %rsp, %rdi; call error_entry; movq %rax, %rsp", \
"", X86_FEATURE_XENPV
ENCODE_FRAME_POINTER
@@ -984,86 +984,6 @@ SYM_CODE_START_LOCAL(paranoid_exit)
jmp restore_regs_and_return_to_kernel
SYM_CODE_END(paranoid_exit)
-/*
- * Save all registers in pt_regs, and switch GS if needed.
- */
-SYM_CODE_START_LOCAL(error_entry)
- UNWIND_HINT_FUNC
- testb $3, CS+8(%rsp)
- jz .Lerror_kernelspace
-
- /*
- * We entered from user mode or we're pretending to have entered
- * from user mode due to an IRET fault.
- */
- swapgs
- FENCE_SWAPGS_USER_ENTRY
- /* We have user CR3. Change to kernel CR3. */
- SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
-
- leaq 8(%rsp), %rdi /* arg0 = pt_regs pointer */
-.Lerror_entry_from_usermode_after_swapgs:
- /* Put us onto the real thread stack. */
- call sync_regs
- ret
-
- /*
- * There are two places in the kernel that can potentially fault with
- * usergs. Handle them here. B stepping K8s sometimes report a
- * truncated RIP for IRET exceptions returning to compat mode. Check
- * for these here too.
- */
-.Lerror_kernelspace:
- leaq native_irq_return_iret(%rip), %rcx
- cmpq %rcx, RIP+8(%rsp)
- je .Lerror_bad_iret
- movl %ecx, %eax /* zero extend */
- cmpq %rax, RIP+8(%rsp)
- je .Lbstep_iret
- cmpq $asm_load_gs_index_gs_change, RIP+8(%rsp)
- jne .Lerror_entry_done_lfence
-
- /*
- * hack: .Lgs_change can fail with user gsbase. If this happens, fix up
- * gsbase and proceed. We'll fix up the exception and land in
- * .Lgs_change's error handler with kernel gsbase.
- */
- swapgs
-
- /*
- * The above code has no serializing instruction. So do an lfence
- * to prevent GS speculation, regardless of whether it is kernel
- * gsbase or user gsbase.
- */
-.Lerror_entry_done_lfence:
- FENCE_SWAPGS_KERNEL_ENTRY
- leaq 8(%rsp), %rax /* return pt_regs pointer */
- ret
-
-.Lbstep_iret:
- /* Fix truncated RIP */
- movq %rcx, RIP+8(%rsp)
- /* fall through */
-
-.Lerror_bad_iret:
- /*
- * We came from an IRET to user mode, so we have user
- * gsbase and CR3. Switch to kernel gsbase and CR3:
- */
- swapgs
- FENCE_SWAPGS_USER_ENTRY
- SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
-
- /*
- * Pretend that the exception came from user mode: set up pt_regs
- * as if we faulted immediately after IRET.
- */
- leaq 8(%rsp), %rdi /* arg0 = pt_regs pointer */
- call fixup_bad_iret
- mov %rax, %rdi
- jmp .Lerror_entry_from_usermode_after_swapgs
-SYM_CODE_END(error_entry)
-
SYM_CODE_START_LOCAL(error_return)
UNWIND_HINT_REGS
DEBUG_ENTRY_ASSERT_IRQS_OFF
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 1cdd7e8bcba7..686461ac9803 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -14,6 +14,7 @@
asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs);
asmlinkage __visible notrace
struct pt_regs *fixup_bad_iret(struct pt_regs *bad_regs);
+asmlinkage __visible notrace struct pt_regs *error_entry(struct pt_regs *eregs);
void __init trap_init(void);
asmlinkage __visible noinstr struct pt_regs *vc_switch_off_ist(struct pt_regs *eregs);
#endif
--
2.19.1.6.gb485710b
next prev parent reply other threads:[~2021-10-26 14:33 UTC|newest]
Thread overview: 59+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-26 14:13 [PATCH V4 00/50] x86/entry/64: Convert a bunch of ASM entry code into C code Lai Jiangshan
2021-10-26 14:13 ` [PATCH V4 01/50] x86/entry: Add fence for kernel entry swapgs in paranoid_entry() Lai Jiangshan
2021-10-27 12:19 ` Borislav Petkov
2021-10-28 0:51 ` Lai Jiangshan
2021-10-26 14:13 ` [PATCH V4 02/50] x86/entry: Use the correct fence macro after swapgs in kernel CR3 Lai Jiangshan
2021-10-26 14:13 ` [PATCH V4 03/50] x86/traps: Remove stack-protector from traps.c Lai Jiangshan
2021-10-26 14:13 ` [PATCH V4 04/50] x86/xen: Add xenpv_restore_regs_and_return_to_usermode() Lai Jiangshan
2021-11-02 8:58 ` Borislav Petkov
2021-11-02 9:19 ` Lai Jiangshan
2021-11-02 9:49 ` Borislav Petkov
2021-11-02 11:22 ` H. Peter Anvin
2021-11-02 14:27 ` Borislav Petkov
2021-10-26 14:20 ` [PATCH V4 05/50] x86/entry: Use swapgs and native_iret directly in swapgs_restore_regs_and_return_to_usermode Lai Jiangshan
2021-10-26 14:20 ` [PATCH V4 06/50] compiler_types.h: Add __noinstr_section() for noinstr Lai Jiangshan
2021-10-26 14:24 ` Miguel Ojeda
2021-10-26 14:20 ` [PATCH V4 07/50] x86/entry: Introduce __entry_text for entry code written in C Lai Jiangshan
2021-10-26 14:20 ` [PATCH V4 08/50] x86/entry: Move PTI_USER_* to arch/x86/include/asm/processor-flags.h Lai Jiangshan
2021-10-26 14:20 ` [PATCH V4 09/50] x86: Remove unused kernel_to_user_p4dp() and user_to_kernel_p4dp() Lai Jiangshan
2021-10-26 14:20 ` [PATCH V4 10/50] x86: Replace PTI_PGTABLE_SWITCH_BIT with PTI_USER_PGTABLE_BIT Lai Jiangshan
2021-10-26 14:27 ` [PATCH V4 11/50] x86: Mark __native_read_cr3() & native_write_cr3() as __always_inline Lai Jiangshan
2021-10-26 14:27 ` [PATCH V4 12/50] x86/traps: Move the declaration of native_irq_return_iret into proto.h Lai Jiangshan
2021-10-26 14:27 ` [PATCH V4 13/50] x86/entry: Add arch/x86/entry/entry64.c for C entry code Lai Jiangshan
2021-10-26 14:27 ` [PATCH V4 14/50] x86/entry: Expose the address of .Lgs_change to entry64.c Lai Jiangshan
2021-10-26 14:27 ` [PATCH V4 15/50] x86/entry: Add C verion of SWITCH_TO_KERNEL_CR3 as switch_to_kernel_cr3() Lai Jiangshan
2021-10-26 14:27 ` [PATCH V4 16/50] x86/traps: Add fence_swapgs_{user,kernel}_entry() Lai Jiangshan
2021-10-26 14:27 ` [PATCH V4 17/50] x86/entry: Add C {user,kernel}_entry_swapgs_and_fence() Lai Jiangshan
2021-10-26 14:27 ` [PATCH V4 18/50] x86/traps: Move pt_regs only in fixup_bad_iret() Lai Jiangshan
2021-10-26 14:30 ` [PATCH V4 19/50] x86/entry: Switch the stack after error_entry() returns Lai Jiangshan
2021-10-26 14:30 ` [PATCH V4 20/50] x86/entry: move PUSH_AND_CLEAR_REGS out of error_entry Lai Jiangshan
2021-10-26 14:30 ` [PATCH V4 21/50] x86/entry: Move cld to the start of idtentry Lai Jiangshan
2021-10-26 14:30 ` [PATCH V4 22/50] x86/entry: Don't call error_entry for XENPV Lai Jiangshan
2021-10-26 14:30 ` [PATCH V4 23/50] x86/entry: Convert SWAPGS to swapgs in error_entry() Lai Jiangshan
2021-10-26 14:32 ` Lai Jiangshan [this message]
2021-10-26 14:32 ` [PATCH V4 25/50] x86/entry: Use idtentry macro for entry_INT80_compat Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 26/50] x86/entry: Convert SWAPGS to swapgs in entry_SYSENTER_compat() Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 27/50] x86: Remove the definition of SWAPGS Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 28/50] x86/entry: Make paranoid_exit() callable Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 29/50] x86/entry: Call paranoid_exit() in asm_exc_nmi() Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 30/50] x86/entry: move PUSH_AND_CLEAR_REGS out of paranoid_entry Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 31/50] x86/entry: Add the C version ist_switch_to_kernel_cr3() Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 32/50] x86/entry: Skip CR3 write when the saved CR3 is kernel CR3 in RESTORE_CR3 Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 33/50] x86/entry: Add the C version ist_restore_cr3() Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 34/50] x86/entry: Add the C version get_percpu_base() Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 35/50] x86/entry: Add the C version ist_switch_to_kernel_gsbase() Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 36/50] x86/entry: Implement the C version ist_paranoid_entry() Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 37/50] x86/entry: Implement the C version ist_paranoid_exit() Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 38/50] x86/entry: Add a C macro to define the function body for IST in .entry.text Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 39/50] x86/debug, mce: Use C entry code Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 40/50] x86/idtentry.h: Move the definitions *IDTENTRY_{MCE|DEBUG}* up Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 41/50] x86/nmi: Use DEFINE_IDTENTRY_NMI for nmi Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 42/50] x86/nmi: Use C entry code Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 43/50] x86/entry: Add a C macro to define the function body for IST in .entry.text with an error code Lai Jiangshan
2021-10-26 14:34 ` [PATCH V4 44/50] x86/doublefault: Use C entry code Lai Jiangshan
2021-10-26 14:38 ` [PATCH V4 45/50] x86/sev: Add and use ist_vc_switch_off_ist() Lai Jiangshan
2021-10-26 14:38 ` [PATCH V4 46/50] x86/sev: Use C entry code Lai Jiangshan
2021-10-26 14:38 ` [PATCH V4 47/50] x86/entry: Remove ASM function paranoid_entry() and paranoid_exit() Lai Jiangshan
2021-10-26 14:38 ` [PATCH V4 48/50] x86/entry: Remove the unused ASM macros Lai Jiangshan
2021-10-26 14:38 ` [PATCH V4 49/50] x86/entry: Remove save_ret from PUSH_AND_CLEAR_REGS Lai Jiangshan
2021-10-26 14:38 ` [PATCH V4 50/50] x86/syscall/64: Move the checking for sysret to C code Lai Jiangshan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211026143301.18895-1-jiangshanlai@gmail.com \
--to=jiangshanlai@gmail.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=laijs@linux.alibaba.com \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.