[PATCH 25/24] x86/traps: Rewrite native_load_gs_index in C code

From: Lai Jiangshan
Date: Thu Sep 02 2021 - 06:51:43 EST


From: Lai Jiangshan <laijs@xxxxxxxxxxxxxxxxx>

There is no constrain/limition to force native_load_gs_index() to be in
ASM code.

Signed-off-by: Lai Jiangshan <laijs@xxxxxxxxxxxxxxxxx>
---
arch/x86/entry/entry_64.S | 36 ----------------------------
arch/x86/entry/traps.c | 25 +++++++++++++++++++
arch/x86/include/asm/special_insns.h | 11 +--------
arch/x86/mm/extable.c | 15 ++++++++++++
4 files changed, 41 insertions(+), 46 deletions(-)

diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index 2d17fca1f503..16ee481e9b5f 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -659,42 +659,6 @@ native_irq_return_ldt:
SYM_CODE_END(common_interrupt_return)
_ASM_NOKPROBE(common_interrupt_return)

-/*
- * Reload gs selector with exception handling
- * edi: new selector
- *
- * Is in entry.text as it shouldn't be instrumented.
- */
-SYM_FUNC_START(asm_load_gs_index)
- FRAME_BEGIN
- swapgs
-SYM_INNER_LABEL(asm_load_gs_index_gs_change, SYM_L_GLOBAL)
-.Lgs_change:
- movl %edi, %gs
-2: ALTERNATIVE "", "mfence", X86_BUG_SWAPGS_FENCE
- swapgs
- FRAME_END
- ret
-SYM_FUNC_END(asm_load_gs_index)
-EXPORT_SYMBOL(asm_load_gs_index)
-
- _ASM_EXTABLE(.Lgs_change, .Lbad_gs)
- .section .fixup, "ax"
- /* running with kernelgs */
-SYM_CODE_START_LOCAL_NOALIGN(.Lbad_gs)
- swapgs /* switch back to user gs */
-.macro ZAP_GS
- /* This can't be a string because the preprocessor needs to see it. */
- movl $__USER_DS, %eax
- movl %eax, %gs
-.endm
- ALTERNATIVE "", "ZAP_GS", X86_BUG_NULL_SEG
- xorl %eax, %eax
- movl %eax, %gs
- jmp 2b
-SYM_CODE_END(.Lbad_gs)
- .previous
-
#ifdef CONFIG_XEN_PV
/*
* A note on the "critical region" in our callback handler.
diff --git a/arch/x86/entry/traps.c b/arch/x86/entry/traps.c
index 52511db6baa6..2a17d74569fd 100644
--- a/arch/x86/entry/traps.c
+++ b/arch/x86/entry/traps.c
@@ -679,6 +679,31 @@ DEFINE_IDTENTRY_RAW(exc_int3)
}

#ifdef CONFIG_X86_64
+
+/*
+ * Reload gs selector with exception handling
+ * selector: new selector
+ *
+ * Is noinstr as it shouldn't be instrumented.
+ */
+noinstr void native_load_gs_index(unsigned int selector)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ native_swapgs();
+ asm volatile(
+ ".global asm_load_gs_index_gs_change \n"
+ "asm_load_gs_index_gs_change: \n"
+ "1: movl %0, %%gs \n"
+ " swapgs \n"
+ "2: \n"
+ _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_clear_gs)
+ :: "r" (selector) : "memory");
+ alternative("", "mfence", X86_BUG_SWAPGS_FENCE);
+ local_irq_restore(flags);
+}
+
/*
* Help handler running on a per-cpu (IST or entry trampoline) stack
* to switch to the normal thread stack if the interrupted code was in
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index 058995bb153c..c5d74ebce527 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -120,16 +120,7 @@ static inline void native_wbinvd(void)
asm volatile("wbinvd": : :"memory");
}

-extern asmlinkage void asm_load_gs_index(unsigned int selector);
-
-static inline void native_load_gs_index(unsigned int selector)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- asm_load_gs_index(selector);
- local_irq_restore(flags);
-}
+extern asmlinkage void native_load_gs_index(unsigned int selector);

static inline unsigned long __read_cr4(void)
{
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index e1664e9f969c..695a580a652a 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -138,6 +138,21 @@ __visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
}
EXPORT_SYMBOL(ex_handler_clear_fs);

+__visible bool ex_handler_clear_gs(const struct exception_table_entry *fixup,
+ struct pt_regs *regs, int trapnr,
+ unsigned long error_code,
+ unsigned long fault_addr)
+{
+ /*
+ * The following native_load_gs_index() should not fault, otherwise
+ * it would be infinite recursion.
+ */
+ if (static_cpu_has(X86_BUG_NULL_SEG))
+ native_load_gs_index(__USER_DS);
+ native_load_gs_index(0);
+ return ex_handler_default(fixup, regs, trapnr, error_code, fault_addr);
+}
+
enum handler_type ex_get_fault_handler_type(unsigned long ip)
{
const struct exception_table_entry *e;
--
2.19.1.6.gb485710b