* [PATCH 2/8] x86: Naturally align the debug IST stack
2014-10-15 5:11 [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Andi Kleen
@ 2014-10-15 5:11 ` Andi Kleen
2014-10-15 5:11 ` [PATCH 3/8] x86: Add intrinsics/macros for new rd/wr fs/gs base instructions Andi Kleen
` (6 subsequent siblings)
7 siblings, 0 replies; 17+ messages in thread
From: Andi Kleen @ 2014-10-15 5:11 UTC (permalink / raw)
To: linux-kernel; +Cc: x86, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
The followon patch for RD*BASE requires the IST stacks to be naturally
aligned because it uses and to access the bottom of the stack.
This was true for everyone except for the debug ist stack.
Make the debug ist stack naturally aligned too.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/include/asm/page_64_types.h | 4 ++--
arch/x86/kernel/cpu/common.c | 8 +++++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 6782051..8b31477 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -17,8 +17,8 @@
#define STACKFAULT_STACK 1
#define DOUBLEFAULT_STACK 2
#define NMI_STACK 3
-#define DEBUG_STACK 4
-#define MCE_STACK 5
+#define MCE_STACK 4
+#define DEBUG_STACK 5 /* Must be always last */
#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index e4ab2b4..a9f1331 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1162,8 +1162,12 @@ static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = {
[DEBUG_STACK - 1] = DEBUG_STKSZ
};
+/* The IST stacks must be naturally aligned */
+
static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
- [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]);
+ [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ]);
+static DEFINE_PER_CPU_2PAGE_ALIGNED(char, debug_stack
+ [DEBUG_STKSZ]);
/* May not be marked __init: used by software suspend */
void syscall_init(void)
@@ -1336,6 +1340,8 @@ void cpu_init(void)
char *estacks = per_cpu(exception_stacks, cpu);
for (v = 0; v < N_EXCEPTION_STACKS; v++) {
+ if (v == DEBUG_STACK - 1)
+ estacks = per_cpu(debug_stack, cpu);
estacks += exception_stack_sizes[v];
oist->ist[v] = t->x86_tss.ist[v] =
(unsigned long)estacks;
--
1.9.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 3/8] x86: Add intrinsics/macros for new rd/wr fs/gs base instructions
2014-10-15 5:11 [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Andi Kleen
2014-10-15 5:11 ` [PATCH 2/8] x86: Naturally align the debug IST stack Andi Kleen
@ 2014-10-15 5:11 ` Andi Kleen
2014-10-15 5:11 ` [PATCH 4/8] x86: Add support for rd/wr fs/gs base Andi Kleen
` (5 subsequent siblings)
7 siblings, 0 replies; 17+ messages in thread
From: Andi Kleen @ 2014-10-15 5:11 UTC (permalink / raw)
To: linux-kernel; +Cc: x86, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Add C intrinsics and assembler macros for the new rd/wr fs/gs base
instructions and for swapgs.
Very straight forward. Used in followon patch.
For assembler only a few standard registers used by entry_64.S
are defined.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/include/asm/fsgs.h | 54 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 arch/x86/include/asm/fsgs.h
diff --git a/arch/x86/include/asm/fsgs.h b/arch/x86/include/asm/fsgs.h
new file mode 100644
index 0000000..1df5085
--- /dev/null
+++ b/arch/x86/include/asm/fsgs.h
@@ -0,0 +1,54 @@
+#ifndef _ASM_FSGS_H
+#define _ASM_FSGS_H 1
+
+#ifndef __ASSEMBLY__
+
+static inline void swapgs(void)
+{
+ asm volatile("swapgs" ::: "memory");
+}
+
+/* Must be protected by X86_FEATURE_FSGSBASE check. */
+
+static inline unsigned long rdgsbase(void)
+{
+ unsigned long gs;
+ asm volatile(".byte 0xf3,0x48,0x0f,0xae,0xc8 # rdgsbaseq %%rax"
+ : "=a" (gs)
+ :: "memory");
+ return gs;
+}
+
+static inline unsigned long rdfsbase(void)
+{
+ unsigned long fs;
+ asm volatile(".byte 0xf3,0x48,0x0f,0xae,0xc0 # rdfsbaseq %%rax"
+ : "=a" (fs)
+ :: "memory");
+ return fs;
+}
+
+static inline void wrgsbase(unsigned long gs)
+{
+ asm volatile(".byte 0xf3,0x48,0x0f,0xae,0xd8 # wrgsbaseq %%rax"
+ :: "a" (gs)
+ : "memory");
+}
+
+static inline void wrfsbase(unsigned long fs)
+{
+ asm volatile(".byte 0xf3,0x48,0x0f,0xae,0xd0 # wrfsbaseq %%rax"
+ :: "a" (fs)
+ : "memory");
+}
+
+#else
+
+/* Handle old assemblers. */
+#define RDGSBASE_R15 .byte 0xf3,0x49,0x0f,0xae,0xcf
+#define WRGSBASE_RDI .byte 0xf3,0x48,0x0f,0xae,0xdf
+#define WRGSBASE_R15 .byte 0xf3,0x49,0x0f,0xae,0xdf
+
+#endif /* __ASSEMBLY__ */
+
+#endif
--
1.9.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 4/8] x86: Add support for rd/wr fs/gs base
2014-10-15 5:11 [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Andi Kleen
2014-10-15 5:11 ` [PATCH 2/8] x86: Naturally align the debug IST stack Andi Kleen
2014-10-15 5:11 ` [PATCH 3/8] x86: Add intrinsics/macros for new rd/wr fs/gs base instructions Andi Kleen
@ 2014-10-15 5:11 ` Andi Kleen
2014-10-15 5:11 ` [PATCH 5/8] x86: Make old K8 swapgs workaround conditional Andi Kleen
` (4 subsequent siblings)
7 siblings, 0 replies; 17+ messages in thread
From: Andi Kleen @ 2014-10-15 5:11 UTC (permalink / raw)
To: linux-kernel; +Cc: x86, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Introduction:
IvyBridge added four new instructions to directly write the fs and gs
64bit base registers. Previously this had to be done with a system
call to write to MSRs. The main use case is fast user space threading
and switching the fs/gs registers quickly there. Another use
case is having (relatively) cheap access to a new address
register per thread.
The instructions are opt-in and have to be explicitely enabled
by the OS.
For more details on how to use the instructions see
Documentation/x86/fsgs.txt added in a followon patch.
Paranoid exception path changes:
===============================
The paranoid entry/exit code is used for any NMI like
exception.
Previously Linux couldn't support the new instructions
because the paranoid entry code relied on the gs base never being
negative outside the kernel to decide when to use swaps. It would
check the gs MSR value and assume it was already running in
kernel if negative.
To get rid of this assumption we have to revamp the paranoid exception
path to not rely on this. We can use the new instructions
to get (relatively) quick access to the GS value, and use
it directly.
This is also significantly faster than a MSR read, so will speed
NMIs (critical for profiling)
The kernel gs for the paranoid path is now stored at the
bottom of the IST stack (so that it can be derived from RSP).
For this we need to know the size of the IST stack
(4K or 8K), which is now passed in as a stack parameter
to save_paranoid.
The original patch compared the gs with the kernel gs and
assumed that if it was identical, swapgs was not needed
(and no user space processing was needed). This
was nice and simple and didn't need a lot of changes.
But this had the side effect that if a user process set its
GS to the same as the kernel it may lose rescheduling
checks (so a racing reschedule IPI would have been
only acted upon the next non paranoid interrupt)
This version now switches to full save/restore of the GS.
This requires quite some changes in the paranoid path.
Unfortunately I didn't come up with a simpler scheme.
Previously we had a flag in EBX that indicated whether
SWAPGS needs to be called later or not. In the new scheme
this turns into a tristate, with a new "restore from R15"
mode that is used when the FSGSBASE instructions are available.
In this case the GS base is saved and restored.
The exit paths are all adjusted to handle this correctly.
There is one complication: to allow debuggers (especially
from the int3 or debug vectors) access to the user GS
we need to save it in the task struct. Normally
the next context switch would overwrite it with the wrong
value from kernel_gs, so we set new flag also in task_struct
that prevents it. The flag is cleared on context switch.
[Even with the additional flag the new FS/GS context switch
is vastly faster than the old MSR based version for bases >4GB]
To prevent recursive interrupts clobbering this
state in the task_struct this is only done for interrupts
coming directly from ring 3.
After a reschedule comes back we check if the flag is still
set. If it wasn't set the GS is back in the (swapped) kernel
gs so we revert to the SWAPGS mode, instead of restoring GS.
So the three possible states for the paranoid exit path are:
- Do nothing (pre FSGSBASE), if we interrupted the kernel
as determined by the existing negative GS
- Do swapgs, if we interrupted user space with positive GS
(pre FSGSBASE), or we saved gs, but it was overwritten
later by a context switch (with FSGSBASE)
- Restore from R15 (with FSGSBASE), if the gs base was saved
in R15, and not overwritten by a context switch.
Context switch changes:
======================
Then after these changes we need to also use the new instructions
to save/restore fs and gs, so that the new values set by the
users won't disappear. This is also significantly
faster for the case when the 64bit base has to be switched
(that is when GS is larger than 4GB), as we can replace
the slow MSR write with a faster wr[fg]sbase execution.
The instructions do not context switch
the segment index, so the old invariant that fs or gs index
have to be 0 for a different 64bit value to stick is still
true. Previously it was enforced by arch_prctl, now the user
program has to make sure it keeps the segment indexes zero.
If it doesn't the changes may not stick.
[Yes, this implies that programs can find out when they
got context switched. However they could already do that
before by checking the timing.]
This is in term enables fast switching when there are
enough threads that their TLS segment does not fit below 4GB,
or alternatively programs that use fs as an additional base
register will not get a sigificant context switch penalty.
It is all done in a single patch because there was no
simple way to do it in pieces without having crash
holes inbetween.
v2: Change to save/restore GS instead of using swapgs
based on the value. Large scale changes.
v3: Fix wrong flag initialization in fallback path.
Thanks 0day!
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/include/asm/processor.h | 4 +
arch/x86/kernel/asm-offsets_64.c | 4 +
arch/x86/kernel/cpu/common.c | 6 ++
arch/x86/kernel/entry_64.S | 163 +++++++++++++++++++++++++++++++--------
arch/x86/kernel/process_64.c | 31 +++++++-
5 files changed, 170 insertions(+), 38 deletions(-)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index eb71ec7..987a631 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -522,6 +522,10 @@ struct thread_struct {
* a short time
*/
unsigned char fpu_counter;
+ /*
+ * Set to one when gs is already saved.
+ */
+ unsigned char gs_saved;
};
/*
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index e7c798b..32ab510 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -85,6 +85,10 @@ int main(void)
DEFINE(__NR_ia32_syscall_max, sizeof(syscalls_ia32) - 1);
DEFINE(IA32_NR_syscalls, sizeof(syscalls_ia32));
+ BLANK();
+
+ OFFSET(task_thread_gs, task_struct, thread.gs);
+ OFFSET(task_thread_gs_saved, task_struct, thread.gs_saved);
return 0;
}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a9f1331..4d5368f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -953,6 +953,9 @@ static void identify_cpu(struct cpuinfo_x86 *c)
#ifdef CONFIG_NUMA
numa_add_cpu(smp_processor_id());
#endif
+
+ if (cpu_has(c, X86_FEATURE_FSGSBASE))
+ set_in_cr4(X86_CR4_FSGSBASE);
}
#ifdef CONFIG_X86_64
@@ -1338,10 +1341,13 @@ void cpu_init(void)
*/
if (!oist->ist[0]) {
char *estacks = per_cpu(exception_stacks, cpu);
+ void *gs = per_cpu(irq_stack_union.gs_base, cpu);
for (v = 0; v < N_EXCEPTION_STACKS; v++) {
if (v == DEBUG_STACK - 1)
estacks = per_cpu(debug_stack, cpu);
+ /* Store GS at bottom of stack for bootstrap access */
+ *(void **)estacks = gs;
estacks += exception_stack_sizes[v];
oist->ist[v] = t->x86_tss.ist[v] =
(unsigned long)estacks;
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 2fac134..43b46a1 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -58,6 +58,8 @@
#include <asm/context_tracking.h>
#include <asm/smap.h>
#include <asm/pgtable_types.h>
+#include <asm/alternative-asm.h>
+#include <asm/fsgs.h>
#include <linux/err.h>
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
@@ -283,32 +285,86 @@ ENDPROC(native_usergs_sysret64)
TRACE_IRQS_OFF
.endm
+/* Values of the ebx flag: */
+#define DO_RESTORE_R15 2 /* Restore GS at end */
+#define DO_SWAPGS 1 /* Use SWAPGS at end */
+#define DO_NOTHING 0 /* Back to ring 0 with same gs */
+
+/*
+ * Stack layout:
+ * +16 pt_regs
+ * +8 stack mask for ist or 0
+ * +0 return address.
+ */
+#define OFF 16
+#define STKMSK 8
+
ENTRY(save_paranoid)
- XCPT_FRAME 1 RDI+8
+ XCPT_FRAME 1 RDI+OFF
cld
- movq %rdi, RDI+8(%rsp)
- movq %rsi, RSI+8(%rsp)
- movq_cfi rdx, RDX+8
- movq_cfi rcx, RCX+8
- movq_cfi rax, RAX+8
- movq %r8, R8+8(%rsp)
- movq %r9, R9+8(%rsp)
- movq %r10, R10+8(%rsp)
- movq %r11, R11+8(%rsp)
- movq_cfi rbx, RBX+8
- movq %rbp, RBP+8(%rsp)
- movq %r12, R12+8(%rsp)
- movq %r13, R13+8(%rsp)
- movq %r14, R14+8(%rsp)
- movq %r15, R15+8(%rsp)
- movl $1,%ebx
+ movq %rdi, RDI+OFF(%rsp)
+ movq %rsi, RSI+OFF(%rsp)
+ movq_cfi rdx, RDX+OFF
+ movq_cfi rcx, RCX+OFF
+ movq_cfi rax, RAX+OFF
+ movq %r8, R8+OFF(%rsp)
+ movq %r9, R9+OFF(%rsp)
+ movq %r10, R10+OFF(%rsp)
+ movq %r11, R11+OFF(%rsp)
+ movq_cfi rbx, RBX+OFF
+ movq %rbp, RBP+OFF(%rsp)
+ movq %r12, R12+OFF(%rsp)
+ movq %r13, R13+OFF(%rsp)
+ movq %r14, R14+OFF(%rsp)
+ movq %r15, R15+OFF(%rsp)
+ movq $-1,ORIG_RAX+OFF(%rsp) /* no syscall to restart */
+33:
+ ASM_NOP5 /* May be replaced with jump to paranoid_save_gs */
+34:
+ movl $DO_NOTHING,%ebx
movl $MSR_GS_BASE,%ecx
rdmsr
testl %edx,%edx
js 1f /* negative -> in kernel */
SWAPGS
- xorl %ebx,%ebx
+ movl $DO_SWAPGS,%ebx
1: ret
+
+ /* Patch in jump to paranoid_save_gs for X86_FEATURE_FSGSBASE */
+ .section .altinstr_replacement,"ax"
+35: .byte 0xe9 /* 32bit near jump */
+ .long paranoid_save_gs-34b
+ .previous
+ .section .altinstructions,"a"
+ altinstruction_entry 33b,35b,X86_FEATURE_FSGSBASE,5,5
+ .previous
+
+ /* Faster version not using RDMSR, and also not assuming
+ * anything about the previous GS value.
+ * This allows the user to arbitarily change GS using
+ * WRGSBASE.
+ */
+paranoid_save_gs:
+ RDGSBASE_R15 # read previous gs
+ movq STKMSK(%rsp),%rax # get ist stack mask
+ andq %rsp,%rax # get bottom of stack
+ movq (%rax),%rdi # get expected GS
+ WRGSBASE_RDI # set gs for kernel
+ mov $DO_RESTORE_R15,%ebx # flag for exit code
+ testl $3,CS+OFF(%rsp) # did we come from ring 0?
+ je paranoid_save_gs_kernel
+ /*
+ * Saving GS in the task struct allows a debugger to manipulate
+ * it. We only do this when coming from ring 3 to avoid recursion
+ * clobbering the state.
+ */
+ movq PER_CPU_VAR(current_task),%rcx # get current
+ movb $1,task_thread_gs_saved(%rcx) # tell context switch gs is
+ # is already saved
+ movq %r15,task_thread_gs(%rcx) # save gs in task struct
+paranoid_save_gs_kernel:
+ ret
+
CFI_ENDPROC
END(save_paranoid)
@@ -1053,7 +1109,8 @@ apicinterrupt IRQ_WORK_VECTOR \
*/
#define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
-.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1
+.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 \
+ stack_mask=-EXCEPTION_STKSZ
ENTRY(\sym)
/* Sanity check */
.if \shift_ist != -1 && \paranoid == 0
@@ -1077,7 +1134,10 @@ ENTRY(\sym)
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
.if \paranoid
+ pushq_cfi $\stack_mask /* ist stack size */
call save_paranoid
+ /* r15: previous gs */
+ popq_cfi %rax /* Drop ist stack size */
.else
call error_entry
.endif
@@ -1112,7 +1172,7 @@ ENTRY(\sym)
.endif
.if \paranoid
- jmp paranoid_exit /* %ebx: no swapgs flag */
+ jmp paranoid_exit /* %ebx: no swapgs flag, r15: old gs */
.else
jmp error_exit /* %ebx: no swapgs flag */
.endif
@@ -1300,8 +1360,10 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
hyperv_callback_vector hyperv_vector_handler
#endif /* CONFIG_HYPERV */
-idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
-idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
+idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK \
+ stack_mask=-DEBUG_STKSZ
+idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK \
+ stack_mask=-DEBUG_STKSZ
idtentry stack_segment do_stack_segment has_error_code=1 paranoid=1
#ifdef CONFIG_XEN
idtentry xen_debug do_debug has_error_code=0
@@ -1330,49 +1392,69 @@ idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vector(
* hard flags at once, atomically)
*/
- /* ebx: no swapgs flag */
+ /* ebx: no swapgs flag, r15: gs if ebx == DO_RESTORE_R15 */
ENTRY(paranoid_exit)
DEFAULT_FRAME
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF_DEBUG
- testl %ebx,%ebx /* swapgs needed? */
- jnz paranoid_restore
+ cmpl $DO_NOTHING,%ebx /* swapgs needed? */
+ je paranoid_restore
testl $3,CS(%rsp)
jnz paranoid_userspace
paranoid_swapgs:
TRACE_IRQS_IRETQ 0
+ cmpl $DO_RESTORE_R15,%ebx /* restore gs? */
+ je paranoid_restore_gs
SWAPGS_UNSAFE_STACK
RESTORE_ALL 8
jmp irq_return
+paranoid_restore_gs:
+ WRGSBASE_R15
+ RESTORE_ALL 8
+ jmp irq_return
paranoid_restore:
TRACE_IRQS_IRETQ_DEBUG 0
RESTORE_ALL 8
jmp irq_return
paranoid_userspace:
GET_THREAD_INFO(%rcx)
- movl TI_flags(%rcx),%ebx
- andl $_TIF_WORK_MASK,%ebx
- jz paranoid_swapgs
+ movl TI_flags(%rcx),%ebp
+ andl $_TIF_WORK_MASK,%ebp
+ jz paranoid_clear_gs_flag
movq %rsp,%rdi /* &pt_regs */
call sync_regs
movq %rax,%rsp /* switch stack for scheduling */
- testl $_TIF_NEED_RESCHED,%ebx
+ testl $_TIF_NEED_RESCHED,%ebp
jnz paranoid_schedule
- movl %ebx,%edx /* arg3: thread flags */
+ movl %ebp,%edx /* arg3: thread flags */
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_NONE)
xorl %esi,%esi /* arg2: oldset */
movq %rsp,%rdi /* arg1: &pt_regs */
call do_notify_resume
- DISABLE_INTERRUPTS(CLBR_NONE)
- TRACE_IRQS_OFF
- jmp paranoid_userspace
+ jmp paranoid_after_schedule
+paranoid_clear_gs_flag:
+ movq PER_CPU_VAR(current_task),%rcx
+ movb $0,task_thread_gs_saved(%rcx)
+ jmp paranoid_swapgs
paranoid_schedule:
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_ANY)
SCHEDULE_USER
+paranoid_after_schedule:
DISABLE_INTERRUPTS(CLBR_ANY)
TRACE_IRQS_OFF
+ cmpl $DO_RESTORE_R15,%ebx
+ jne paranoid_userspace
+ movq PER_CPU_VAR(current_task),%rcx
+ cmpb $0,task_thread_gs_saved(%rcx) /* did we schedule? */
+ jne paranoid_userspace /* did not schedule: keep our gs */
+ /*
+ * Otherwise the context switch has put the correct gs into
+ * kernel_gs, so we can just end with swapgs and it
+ * will DTRT.
+ */
+ mov $DO_SWAPGS,%ebx /* force swapgs after schedule */
jmp paranoid_userspace
CFI_ENDPROC
END(paranoid_exit)
@@ -1663,6 +1745,7 @@ end_repeat_nmi:
pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
+ pushq_cfi $-EXCEPTION_STKSZ /* ist stack size */
/*
* Use save_paranoid to handle SWAPGS, but no need to use paranoid_exit
* as we should not be calling schedule in NMI context.
@@ -1671,6 +1754,8 @@ end_repeat_nmi:
* exceptions might do.
*/
call save_paranoid
+ /* r15: previous gs */
+ popq_cfi %rax /* pop ist size */
DEFAULT_FRAME 0
/*
@@ -1695,11 +1780,21 @@ end_repeat_nmi:
je 1f
movq %r12, %cr2
1:
-
+ cmpl $DO_RESTORE_R15,%ebx
+ je nmi_gs_restore
testl %ebx,%ebx /* swapgs needed? */
jnz nmi_restore
nmi_swapgs:
SWAPGS_UNSAFE_STACK
+ jmp nmi_restore
+nmi_gs_restore:
+ /* If we came from ring 3 clear the saved gs flag. */
+ testl $3,CS(%rsp)
+ je nmi_wrgsbase
+ movq PER_CPU_VAR(current_task),%rcx
+ movb $0,task_thread_gs_saved(%rcx)
+nmi_wrgsbase:
+ WRGSBASE_R15 /* restore gs */
nmi_restore:
/* Pop the extra iret frame at once */
RESTORE_ALL 6*8
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index ca5b02d..9bad75a 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -49,6 +49,7 @@
#include <asm/syscalls.h>
#include <asm/debugreg.h>
#include <asm/switch_to.h>
+#include <asm/fsgs.h>
asmlinkage extern void ret_from_fork(void);
@@ -311,6 +312,16 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
*/
savesegment(fs, fsindex);
savesegment(gs, gsindex);
+ if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
+ prev->fs = rdfsbase();
+ /* Interrupts are disabled here. */
+ if (!prev->gs_saved) {
+ swapgs();
+ prev->gs = rdgsbase();
+ swapgs();
+ }
+ prev->gs_saved = 0;
+ }
load_TLS(next, cpu);
@@ -341,8 +352,12 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
prev->fs = 0;
}
/* when next process has a 64bit base use it */
- if (next->fs)
- wrmsrl(MSR_FS_BASE, next->fs);
+ if (next->fs) {
+ if (static_cpu_has(X86_FEATURE_FSGSBASE))
+ wrfsbase(next->fs);
+ else
+ wrmsrl(MSR_FS_BASE, next->fs);
+ }
prev->fsindex = fsindex;
if (unlikely(gsindex | next->gsindex | prev->gs)) {
@@ -350,8 +365,16 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
if (gsindex)
prev->gs = 0;
}
- if (next->gs)
- wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
+ if (next->gs) {
+ if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
+ /* Interrupts are disabled here. */
+ swapgs();
+ wrgsbase(next->gs);
+ swapgs();
+ } else {
+ wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
+ }
+ }
prev->gsindex = gsindex;
switch_fpu_finish(next_p, fpu);
--
1.9.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 5/8] x86: Make old K8 swapgs workaround conditional
2014-10-15 5:11 [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Andi Kleen
` (2 preceding siblings ...)
2014-10-15 5:11 ` [PATCH 4/8] x86: Add support for rd/wr fs/gs base Andi Kleen
@ 2014-10-15 5:11 ` Andi Kleen
2014-10-15 5:11 ` [PATCH 6/8] x86: Enumerate kernel FSGS capability in AT_HWCAP2 Andi Kleen
` (3 subsequent siblings)
7 siblings, 0 replies; 17+ messages in thread
From: Andi Kleen @ 2014-10-15 5:11 UTC (permalink / raw)
To: linux-kernel; +Cc: x86, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Every gs selector/index reload always paid an extra MFENCE
between the two SWAPGS. This was to work around an old
bug in early K8 steppings. All other CPUs don't need the extra
mfence. Patch the extra MFENCE only in for K8.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/include/asm/cpufeature.h | 1 +
arch/x86/kernel/cpu/amd.c | 3 +++
arch/x86/kernel/entry_64.S | 10 +++++++++-
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index bb9b258..5125c95 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -102,6 +102,7 @@
#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */
#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
+#define X86_FEATURE_SWAPGS_MFENCE (3*32+31) /* SWAPGS may need MFENCE */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 60e5497..85988e8 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -544,6 +544,9 @@ static void init_amd_k8(struct cpuinfo_x86 *c)
if ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)
set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+ /* Early steppings needed a mfence on swapgs. */
+ set_cpu_cap(c, X86_FEATURE_SWAPGS_MFENCE);
+
/*
* Some BIOSes incorrectly force this feature, but only K8 revision D
* (model = 0x14) and later actually support it.
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 43b46a1..5913360 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1216,13 +1216,21 @@ ENTRY(native_load_gs_index)
SWAPGS
gs_change:
movl %edi,%gs
-2: mfence /* workaround */
+2: ASM_NOP3 /* may be replaced with mfence */
SWAPGS
popfq_cfi
ret
CFI_ENDPROC
END(native_load_gs_index)
+ /* Early K8 systems needed an mfence after swapgs to workaround a bug */
+ .section .altinstr_replacement,"ax"
+3: mfence
+ .previous
+ .section .altinstructions,"a"
+ altinstruction_entry 2b,3b,X86_FEATURE_SWAPGS_MFENCE,3,3
+ .previous
+
_ASM_EXTABLE(gs_change,bad_gs)
.section .fixup,"ax"
/* running with kernelgs */
--
1.9.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 6/8] x86: Enumerate kernel FSGS capability in AT_HWCAP2
2014-10-15 5:11 [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Andi Kleen
` (3 preceding siblings ...)
2014-10-15 5:11 ` [PATCH 5/8] x86: Make old K8 swapgs workaround conditional Andi Kleen
@ 2014-10-15 5:11 ` Andi Kleen
2014-10-15 5:11 ` [PATCH 7/8] x86: Add documentation for rd/wr fs/gs base Andi Kleen
` (2 subsequent siblings)
7 siblings, 0 replies; 17+ messages in thread
From: Andi Kleen @ 2014-10-15 5:11 UTC (permalink / raw)
To: linux-kernel; +Cc: x86, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
The kernel needs to explicitely enable RD/WRFSBASE to handle context
switch correctly. So the application needs to know if it can safely use
these instruction. Just looking at the CPUID bit is not enough because it
may be running in a kernel that does not enable the instructions.
One way for the application would be to just try and catch the SIGILL.
But that is difficult to do in libraries which may not want
to overwrite the signal handlers of the main application.
So we need to provide a way for the application to discover the kernel
capability.
I used AT_HWCAP2 in the ELF aux vector which is already used by
PPC for similar things. We define a new Linux defined bitmap
returned in AT_HWCAP. Currently it has only one bit set,
for kernel is FSGSBASE capable.
The application can then access it manually or using
the getauxval() function in newer glibc.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/include/asm/elf.h | 7 +++++++
arch/x86/include/uapi/asm/hwcap.h | 7 +++++++
arch/x86/kernel/cpu/common.c | 7 ++++++-
3 files changed, 20 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/include/uapi/asm/hwcap.h
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 1a055c8..950d45d 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -256,6 +256,13 @@ extern int force_personality32;
#define ELF_HWCAP (boot_cpu_data.x86_capability[0])
+extern unsigned kernel_enabled_features;
+
+/* HWCAP2 supplies kernel enabled CPU feature, so that the application
+ can know that it can safely use them. The bits are defined in
+ uapi/asm/hwcap.h. */
+#define ELF_HWCAP2 kernel_enabled_features;
+
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
intent than poking at uname or /proc/cpuinfo.
diff --git a/arch/x86/include/uapi/asm/hwcap.h b/arch/x86/include/uapi/asm/hwcap.h
new file mode 100644
index 0000000..d9c54f8
--- /dev/null
+++ b/arch/x86/include/uapi/asm/hwcap.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_HWCAP_H
+#define _ASM_HWCAP_H 1
+
+#define HWCAP2_FSGSBASE (1 << 0) /* Kernel enabled RD/WR FS/GS BASE */
+/* upto bit 31 free */
+
+#endif
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 4d5368f..e099370 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -33,6 +33,7 @@
#include <asm/i387.h>
#include <asm/fpu-internal.h>
#include <asm/mtrr.h>
+#include <asm/hwcap.h>
#include <linux/numa.h>
#include <asm/asm.h>
#include <asm/cpu.h>
@@ -48,6 +49,8 @@
#include "cpu.h"
+unsigned kernel_enabled_features __read_mostly;
+
/* all of these masks are initialized in setup_cpu_local_masks() */
cpumask_var_t cpu_initialized_mask;
cpumask_var_t cpu_callout_mask;
@@ -954,8 +957,10 @@ static void identify_cpu(struct cpuinfo_x86 *c)
numa_add_cpu(smp_processor_id());
#endif
- if (cpu_has(c, X86_FEATURE_FSGSBASE))
+ if (cpu_has(c, X86_FEATURE_FSGSBASE)) {
+ kernel_enabled_features |= HWCAP2_FSGSBASE;
set_in_cr4(X86_CR4_FSGSBASE);
+ }
}
#ifdef CONFIG_X86_64
--
1.9.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 7/8] x86: Add documentation for rd/wr fs/gs base
2014-10-15 5:11 [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Andi Kleen
` (4 preceding siblings ...)
2014-10-15 5:11 ` [PATCH 6/8] x86: Enumerate kernel FSGS capability in AT_HWCAP2 Andi Kleen
@ 2014-10-15 5:11 ` Andi Kleen
2014-10-20 20:28 ` Konrad Rzeszutek Wilk
2014-10-15 5:11 ` [PATCH 8/8] x86: Use rd/wr fs/gs base in arch_prctl Andi Kleen
2014-10-27 15:00 ` [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Tejun Heo
7 siblings, 1 reply; 17+ messages in thread
From: Andi Kleen @ 2014-10-15 5:11 UTC (permalink / raw)
To: linux-kernel; +Cc: x86, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
Documentation/x86/fsgs.txt | 73 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
create mode 100644 Documentation/x86/fsgs.txt
diff --git a/Documentation/x86/fsgs.txt b/Documentation/x86/fsgs.txt
new file mode 100644
index 0000000..d895b25
--- /dev/null
+++ b/Documentation/x86/fsgs.txt
@@ -0,0 +1,73 @@
+
+Using FS and GS prefixes on x86_64-linux
+
+The x86 architecture supports segment prefixes per instruction to add an
+offset to an address. On 64bit x86, these are mostly nops, except for FS
+and GS.
+
+This offers an efficient way to reference a global pointer.
+
+The compiler has to generate special code to use these base registers,
+or they can be accessed with inline assembler.
+
+ mov %gs:offset,%reg
+ mov %fs:offset,%reg
+
+FS is used to address the thread local segment (TLS), declared using
+__thread. The compiler the automatically generates the correct prefixes and
+relocations to access these values.
+
+FS is normally managed by the runtime code or the threading library.
+
+GS is freely available, but may need special (compiler or inline assembler)
+code to use.
+
+Traditionally 64bit FS and GS could be set by the arch_prctl system call
+
+ arch_prctl(ARCH_SET_GS, value)
+ arch_prctl(ARCH_SET_FS, value)
+
+[There was also an older method using modify_ldt(), inherited from 32bit,
+but this is not discussed here.]
+
+However using a syscall is problematic for user space threading libraries
+that want to context switch in user space.
+
+Newer Intel CPUs (Ivy Bridge and later) added new instructions to directly
+access these registers quickly from user context
+
+ RDFSBASE %reg read the FS base (or _readfsbase_u64)
+ RDGSBASE %reg read the GS base (or _readgsbase_u64)
+
+ WRFSBASE %reg write the FS base (or _writefsbase_u64)
+ WRGSBASE %reg write the GS base (or _writegsbase_u64)
+
+The instructions are supported by the CPU when the "fsgsbase" string is shown in
+/proc/cpuinfo (or directly retrieved through the CPUID instruction).
+The instructions are only available to 64bit binaries.
+
+However the kernel needs to explicitly enable these instructions, as it
+may otherwise not correctly context switch the state. Newer Linux
+kernels enable this. When the kernel did not enable the instruction
+they will fault.
+
+An FSGSBASE enabled kernel can be detected by checking the AT_HWCAP2
+bitmask in the aux vector. When the HWCAP2_FSGSBASE bit is set the
+kernel supports RDFSGSBASE.
+
+ #include <sys/auxv.h>
+ #include <elf.h>
+
+ /* Will be eventually in asm/hwcap.h */
+ #define HWCAP2_FSGSBASE (1 << 0)
+
+ unsigned val = getauxval(AT_HWCAP2);
+ if (val & HWCAP2_FSGSBASE) {
+ asm("wrgsbase %0" :: "r" (ptr));
+ }
+
+Another requirement is that the FS or GS selector has to be zero
+(is normally true unless changed explicitly)
+
+
+Andi Kleen
--
1.9.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 7/8] x86: Add documentation for rd/wr fs/gs base
2014-10-15 5:11 ` [PATCH 7/8] x86: Add documentation for rd/wr fs/gs base Andi Kleen
@ 2014-10-20 20:28 ` Konrad Rzeszutek Wilk
0 siblings, 0 replies; 17+ messages in thread
From: Konrad Rzeszutek Wilk @ 2014-10-20 20:28 UTC (permalink / raw)
To: Andi Kleen; +Cc: linux-kernel, x86, Andi Kleen
On Tue, Oct 14, 2014 at 10:11:50PM -0700, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>
>
> Signed-off-by: Andi Kleen <ak@linux.intel.com>
> ---
> Documentation/x86/fsgs.txt | 73 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 73 insertions(+)
> create mode 100644 Documentation/x86/fsgs.txt
>
> diff --git a/Documentation/x86/fsgs.txt b/Documentation/x86/fsgs.txt
> new file mode 100644
> index 0000000..d895b25
> --- /dev/null
> +++ b/Documentation/x86/fsgs.txt
> @@ -0,0 +1,73 @@
> +
> +Using FS and GS prefixes on x86_64-linux
> +
> +The x86 architecture supports segment prefixes per instruction to add an
> +offset to an address. On 64bit x86, these are mostly nops, except for FS
> +and GS.
> +
> +This offers an efficient way to reference a global pointer.
> +
> +The compiler has to generate special code to use these base registers,
> +or they can be accessed with inline assembler.
> +
> + mov %gs:offset,%reg
> + mov %fs:offset,%reg
> +
> +FS is used to address the thread local segment (TLS), declared using
> +__thread. The compiler the automatically generates the correct prefixes and
s/the/then
> +relocations to access these values.
> +
> +FS is normally managed by the runtime code or the threading library.
> +
> +GS is freely available, but may need special (compiler or inline assembler)
> +code to use.
> +
> +Traditionally 64bit FS and GS could be set by the arch_prctl system call
> +
> + arch_prctl(ARCH_SET_GS, value)
> + arch_prctl(ARCH_SET_FS, value)
> +
> +[There was also an older method using modify_ldt(), inherited from 32bit,
> +but this is not discussed here.]
> +
> +However using a syscall is problematic for user space threading libraries
> +that want to context switch in user space.
Could you explain that a bit more?
> +
> +Newer Intel CPUs (Ivy Bridge and later) added new instructions to directly
> +access these registers quickly from user context
> +
> + RDFSBASE %reg read the FS base (or _readfsbase_u64)
> + RDGSBASE %reg read the GS base (or _readgsbase_u64)
> +
> + WRFSBASE %reg write the FS base (or _writefsbase_u64)
> + WRGSBASE %reg write the GS base (or _writegsbase_u64)
> +
> +The instructions are supported by the CPU when the "fsgsbase" string is shown in
> +/proc/cpuinfo (or directly retrieved through the CPUID instruction).
> +The instructions are only available to 64bit binaries.
> +
> +However the kernel needs to explicitly enable these instructions, as it
> +may otherwise not correctly context switch the state. Newer Linux
> +kernels enable this. When the kernel did not enable the instruction
> +they will fault.
#GP? or #UD?
> +
> +An FSGSBASE enabled kernel can be detected by checking the AT_HWCAP2
> +bitmask in the aux vector. When the HWCAP2_FSGSBASE bit is set the
> +kernel supports RDFSGSBASE.
> +
> + #include <sys/auxv.h>
> + #include <elf.h>
> +
> + /* Will be eventually in asm/hwcap.h */
> + #define HWCAP2_FSGSBASE (1 << 0)
> +
> + unsigned val = getauxval(AT_HWCAP2);
> + if (val & HWCAP2_FSGSBASE) {
> + asm("wrgsbase %0" :: "r" (ptr));
> + }
> +
> +Another requirement is that the FS or GS selector has to be zero
> +(is normally true unless changed explicitly)
> +
> +
> +Andi Kleen
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 8/8] x86: Use rd/wr fs/gs base in arch_prctl
2014-10-15 5:11 [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Andi Kleen
` (5 preceding siblings ...)
2014-10-15 5:11 ` [PATCH 7/8] x86: Add documentation for rd/wr fs/gs base Andi Kleen
@ 2014-10-15 5:11 ` Andi Kleen
2014-10-27 15:00 ` [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Tejun Heo
7 siblings, 0 replies; 17+ messages in thread
From: Andi Kleen @ 2014-10-15 5:11 UTC (permalink / raw)
To: linux-kernel; +Cc: x86, Andi Kleen
From: Andi Kleen <ak@linux.intel.com>
Convert arch_prctl to use the new instructions to
change fs/gs if available, instead of using MSRs.
This is merely a small performance optimization,
no new functionality.
With the new instructions the syscall is really obsolete,
as everything can be set directly in ring 3. But the syscall
is widely used by existing software, so we still support it.
The syscall still enforces that the addresses are not
in kernel space, even though that is not needed more.
This is mainly so that the programs written for new CPUs
do not suddenly fail on old CPUs.
With the new instructions available it prefers to use
them in the context switch, instead of using the old
"use GDT segment rewrite" trick.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/kernel/process_64.c | 45 ++++++++++++++++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 9bad75a..7669b3b 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -486,15 +486,23 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
int ret = 0;
int doit = task == current;
int cpu;
+ int fast_seg = boot_cpu_has(X86_FEATURE_FSGSBASE);
switch (code) {
case ARCH_SET_GS:
+ /*
+ * With fast_seg we don't need that check anymore,
+ * but keep it so that programs do not suddenly
+ * start failing when run on older CPUs.
+ * If you really want to set a address in kernel space
+ * use WRGSBASE directly.
+ */
if (addr >= TASK_SIZE_OF(task))
return -EPERM;
cpu = get_cpu();
/* handle small bases via the GDT because that's faster to
switch. */
- if (addr <= 0xffffffff) {
+ if (addr <= 0xffffffff && !fast_seg) {
set_32bit_tls(task, GS_TLS, addr);
if (doit) {
load_TLS(&task->thread, cpu);
@@ -506,8 +514,17 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
task->thread.gsindex = 0;
task->thread.gs = addr;
if (doit) {
- load_gs_index(0);
- ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, addr);
+ if (fast_seg) {
+ local_irq_disable();
+ swapgs();
+ loadsegment(gs, 0);
+ wrgsbase(addr);
+ swapgs();
+ local_irq_enable();
+ } else {
+ load_gs_index(0);
+ ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, addr);
+ }
}
}
put_cpu();
@@ -520,7 +537,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
cpu = get_cpu();
/* handle small bases via the GDT because that's faster to
switch. */
- if (addr <= 0xffffffff) {
+ if (addr <= 0xffffffff && !fast_seg) {
set_32bit_tls(task, FS_TLS, addr);
if (doit) {
load_TLS(&task->thread, cpu);
@@ -535,7 +552,10 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
/* set the selector to 0 to not confuse
__switch_to */
loadsegment(fs, 0);
- ret = wrmsrl_safe(MSR_FS_BASE, addr);
+ if (fast_seg)
+ wrfsbase(addr);
+ else
+ ret = wrmsrl_safe(MSR_FS_BASE, addr);
}
}
put_cpu();
@@ -544,6 +564,8 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
unsigned long base;
if (task->thread.fsindex == FS_TLS_SEL)
base = read_32bit_tls(task, FS_TLS);
+ else if (doit && fast_seg)
+ base = rdfsbase();
else if (doit)
rdmsrl(MSR_FS_BASE, base);
else
@@ -558,9 +580,16 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
base = read_32bit_tls(task, GS_TLS);
else if (doit) {
savesegment(gs, gsindex);
- if (gsindex)
- rdmsrl(MSR_KERNEL_GS_BASE, base);
- else
+ if (gsindex) {
+ if (fast_seg) {
+ local_irq_disable();
+ swapgs();
+ base = rdgsbase();
+ swapgs();
+ local_irq_enable();
+ } else
+ rdmsrl(MSR_KERNEL_GS_BASE, base);
+ } else
base = task->thread.gs;
} else
base = task->thread.gs;
--
1.9.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED
2014-10-15 5:11 [PATCH 1/8] percpu: Add a DEFINE_PER_CPU_2PAGE_ALIGNED Andi Kleen
` (6 preceding siblings ...)
2014-10-15 5:11 ` [PATCH 8/8] x86: Use rd/wr fs/gs base in arch_prctl Andi Kleen
@ 2014-10-27 15:00 ` Tejun Heo
7 siblings, 0 replies; 17+ messages in thread
From: Tejun Heo @ 2014-10-27 15:00 UTC (permalink / raw)
To: Andi Kleen; +Cc: linux-kernel, x86, Andi Kleen
On Tue, Oct 14, 2014 at 10:11:44PM -0700, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>
>
> Needed in a followon patch which needs to naturally align a 8K stack.
> I just put it into the page aligned section. This may cause an extra
> 4K hole if we're unlucky.
>
> Cc: tj@kernel.org
> Signed-off-by: Andi Kleen <ak@linux.intel.com>
Looks fine to me. Please feel free to add
Acked-by: Tejun Heo <tj@kernel.org>
and route any way you see fit.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 17+ messages in thread