aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorKyle Huey <me@kylehuey.com>2017-03-20 04:16:26 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-03-20 11:10:34 -0400
commite9ea1e7f53b852147cbd568b0568c7ad97ec21a3 (patch)
treefd7046c239c106887b0928cdcf55913eff19c798 /arch
parent90218ac77d0582eaf2d0872d8d900cbd5bf1f205 (diff)
x86/arch_prctl: Add ARCH_[GET|SET]_CPUID
Intel supports faulting on the CPUID instruction beginning with Ivy Bridge. When enabled, the processor will fault on attempts to execute the CPUID instruction with CPL>0. Exposing this feature to userspace will allow a ptracer to trap and emulate the CPUID instruction. When supported, this feature is controlled by toggling bit 0 of MSR_MISC_FEATURES_ENABLES. It is documented in detail in Section 2.3.2 of https://bugzilla.kernel.org/attachment.cgi?id=243991 Implement a new pair of arch_prctls, available on both x86-32 and x86-64. ARCH_GET_CPUID: Returns the current CPUID state, either 0 if CPUID faulting is enabled (and thus the CPUID instruction is not available) or 1 if CPUID faulting is not enabled. ARCH_SET_CPUID: Set the CPUID state to the second argument. If cpuid_enabled is 0 CPUID faulting will be activated, otherwise it will be deactivated. Returns ENODEV if CPUID faulting is not supported on this system. The state of the CPUID faulting flag is propagated across forks, but reset upon exec. Signed-off-by: Kyle Huey <khuey@kylehuey.com> Cc: Grzegorz Andrejczuk <grzegorz.andrejczuk@intel.com> Cc: kvm@vger.kernel.org Cc: Radim Krčmář <rkrcmar@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: linux-kselftest@vger.kernel.org Cc: Nadav Amit <nadav.amit@gmail.com> Cc: Robert O'Callahan <robert@ocallahan.org> Cc: Richard Weinberger <richard@nod.at> Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> Cc: Borislav Petkov <bp@suse.de> Cc: Andy Lutomirski <luto@kernel.org> Cc: Len Brown <len.brown@intel.com> Cc: Shuah Khan <shuah@kernel.org> Cc: user-mode-linux-devel@lists.sourceforge.net Cc: Jeff Dike <jdike@addtoit.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: user-mode-linux-user@lists.sourceforge.net Cc: David Matlack <dmatlack@google.com> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Dmitry Safonov <dsafonov@virtuozzo.com> Cc: linux-fsdevel@vger.kernel.org Cc: Paolo Bonzini <pbonzini@redhat.com> Link: http://lkml.kernel.org/r/20170320081628.18952-9-khuey@kylehuey.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/msr-index.h2
-rw-r--r--arch/x86/include/asm/processor.h2
-rw-r--r--arch/x86/include/asm/thread_info.h6
-rw-r--r--arch/x86/include/uapi/asm/prctl.h11
-rw-r--r--arch/x86/kernel/cpu/intel.c18
-rw-r--r--arch/x86/kernel/process.c78
6 files changed, 104 insertions, 13 deletions
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index b1f75daca34b..673f9ac50f6d 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -558,6 +558,8 @@
558/* MISC_FEATURES_ENABLES non-architectural features */ 558/* MISC_FEATURES_ENABLES non-architectural features */
559#define MSR_MISC_FEATURES_ENABLES 0x00000140 559#define MSR_MISC_FEATURES_ENABLES 0x00000140
560 560
561#define MSR_MISC_FEATURES_ENABLES_CPUID_FAULT_BIT 0
562#define MSR_MISC_FEATURES_ENABLES_CPUID_FAULT BIT_ULL(MSR_MISC_FEATURES_ENABLES_CPUID_FAULT_BIT)
561#define MSR_MISC_FEATURES_ENABLES_RING3MWAIT_BIT 1 563#define MSR_MISC_FEATURES_ENABLES_RING3MWAIT_BIT 1
562 564
563#define MSR_IA32_TSC_DEADLINE 0x000006E0 565#define MSR_IA32_TSC_DEADLINE 0x000006E0
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index f385eca5407a..a80c1b3997ed 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -884,6 +884,8 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip,
884extern int get_tsc_mode(unsigned long adr); 884extern int get_tsc_mode(unsigned long adr);
885extern int set_tsc_mode(unsigned int val); 885extern int set_tsc_mode(unsigned int val);
886 886
887DECLARE_PER_CPU(u64, msr_misc_features_shadow);
888
887/* Register/unregister a process' MPX related resource */ 889/* Register/unregister a process' MPX related resource */
888#define MPX_ENABLE_MANAGEMENT() mpx_enable_management() 890#define MPX_ENABLE_MANAGEMENT() mpx_enable_management()
889#define MPX_DISABLE_MANAGEMENT() mpx_disable_management() 891#define MPX_DISABLE_MANAGEMENT() mpx_disable_management()
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index ad6f5eb07a95..9fc44b95f7cb 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -87,6 +87,7 @@ struct thread_info {
87#define TIF_SECCOMP 8 /* secure computing */ 87#define TIF_SECCOMP 8 /* secure computing */
88#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */ 88#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
89#define TIF_UPROBE 12 /* breakpointed or singlestepping */ 89#define TIF_UPROBE 12 /* breakpointed or singlestepping */
90#define TIF_NOCPUID 15 /* CPUID is not accessible in userland */
90#define TIF_NOTSC 16 /* TSC is not accessible in userland */ 91#define TIF_NOTSC 16 /* TSC is not accessible in userland */
91#define TIF_IA32 17 /* IA32 compatibility process */ 92#define TIF_IA32 17 /* IA32 compatibility process */
92#define TIF_NOHZ 19 /* in adaptive nohz mode */ 93#define TIF_NOHZ 19 /* in adaptive nohz mode */
@@ -110,6 +111,7 @@ struct thread_info {
110#define _TIF_SECCOMP (1 << TIF_SECCOMP) 111#define _TIF_SECCOMP (1 << TIF_SECCOMP)
111#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY) 112#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
112#define _TIF_UPROBE (1 << TIF_UPROBE) 113#define _TIF_UPROBE (1 << TIF_UPROBE)
114#define _TIF_NOCPUID (1 << TIF_NOCPUID)
113#define _TIF_NOTSC (1 << TIF_NOTSC) 115#define _TIF_NOTSC (1 << TIF_NOTSC)
114#define _TIF_IA32 (1 << TIF_IA32) 116#define _TIF_IA32 (1 << TIF_IA32)
115#define _TIF_NOHZ (1 << TIF_NOHZ) 117#define _TIF_NOHZ (1 << TIF_NOHZ)
@@ -138,7 +140,7 @@ struct thread_info {
138 140
139/* flags to check in __switch_to() */ 141/* flags to check in __switch_to() */
140#define _TIF_WORK_CTXSW \ 142#define _TIF_WORK_CTXSW \
141 (_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP) 143 (_TIF_IO_BITMAP|_TIF_NOCPUID|_TIF_NOTSC|_TIF_BLOCKSTEP)
142 144
143#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY) 145#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
144#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW) 146#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
@@ -239,6 +241,8 @@ static inline int arch_within_stack_frames(const void * const stack,
239extern void arch_task_cache_init(void); 241extern void arch_task_cache_init(void);
240extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); 242extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
241extern void arch_release_task_struct(struct task_struct *tsk); 243extern void arch_release_task_struct(struct task_struct *tsk);
244extern void arch_setup_new_exec(void);
245#define arch_setup_new_exec arch_setup_new_exec
242#endif /* !__ASSEMBLY__ */ 246#endif /* !__ASSEMBLY__ */
243 247
244#endif /* _ASM_X86_THREAD_INFO_H */ 248#endif /* _ASM_X86_THREAD_INFO_H */
diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h
index 835aa51c7f6e..c45765517092 100644
--- a/arch/x86/include/uapi/asm/prctl.h
+++ b/arch/x86/include/uapi/asm/prctl.h
@@ -1,10 +1,13 @@
1#ifndef _ASM_X86_PRCTL_H 1#ifndef _ASM_X86_PRCTL_H
2#define _ASM_X86_PRCTL_H 2#define _ASM_X86_PRCTL_H
3 3
4#define ARCH_SET_GS 0x1001 4#define ARCH_SET_GS 0x1001
5#define ARCH_SET_FS 0x1002 5#define ARCH_SET_FS 0x1002
6#define ARCH_GET_FS 0x1003 6#define ARCH_GET_FS 0x1003
7#define ARCH_GET_GS 0x1004 7#define ARCH_GET_GS 0x1004
8
9#define ARCH_GET_CPUID 0x1011
10#define ARCH_SET_CPUID 0x1012
8 11
9#define ARCH_MAP_VDSO_X32 0x2001 12#define ARCH_MAP_VDSO_X32 0x2001
10#define ARCH_MAP_VDSO_32 0x2002 13#define ARCH_MAP_VDSO_32 0x2002
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index a07f8295c9ed..dfa90a3a5145 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -90,16 +90,12 @@ static void probe_xeon_phi_r3mwait(struct cpuinfo_x86 *c)
90 return; 90 return;
91 } 91 }
92 92
93 if (ring3mwait_disabled) { 93 if (ring3mwait_disabled)
94 msr_clear_bit(MSR_MISC_FEATURES_ENABLES,
95 MSR_MISC_FEATURES_ENABLES_RING3MWAIT_BIT);
96 return; 94 return;
97 }
98
99 msr_set_bit(MSR_MISC_FEATURES_ENABLES,
100 MSR_MISC_FEATURES_ENABLES_RING3MWAIT_BIT);
101 95
102 set_cpu_cap(c, X86_FEATURE_RING3MWAIT); 96 set_cpu_cap(c, X86_FEATURE_RING3MWAIT);
97 this_cpu_or(msr_misc_features_shadow,
98 1UL << MSR_MISC_FEATURES_ENABLES_RING3MWAIT_BIT);
103 99
104 if (c == &boot_cpu_data) 100 if (c == &boot_cpu_data)
105 ELF_HWCAP2 |= HWCAP2_RING3MWAIT; 101 ELF_HWCAP2 |= HWCAP2_RING3MWAIT;
@@ -505,9 +501,15 @@ static void init_intel_misc_features(struct cpuinfo_x86 *c)
505 if (rdmsrl_safe(MSR_MISC_FEATURES_ENABLES, &msr)) 501 if (rdmsrl_safe(MSR_MISC_FEATURES_ENABLES, &msr))
506 return; 502 return;
507 503
508 /* Check features and update capabilities */ 504 /* Clear all MISC features */
505 this_cpu_write(msr_misc_features_shadow, 0);
506
507 /* Check features and update capabilities and shadow control bits */
509 init_cpuid_fault(c); 508 init_cpuid_fault(c);
510 probe_xeon_phi_r3mwait(c); 509 probe_xeon_phi_r3mwait(c);
510
511 msr = this_cpu_read(msr_misc_features_shadow);
512 wrmsrl(MSR_MISC_FEATURES_ENABLES, msr);
511} 513}
512 514
513static void init_intel(struct cpuinfo_x86 *c) 515static void init_intel(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index b12e95eceb83..0bb88428cbf2 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -37,6 +37,7 @@
37#include <asm/vm86.h> 37#include <asm/vm86.h>
38#include <asm/switch_to.h> 38#include <asm/switch_to.h>
39#include <asm/desc.h> 39#include <asm/desc.h>
40#include <asm/prctl.h>
40 41
41/* 42/*
42 * per-CPU TSS segments. Threads are completely 'soft' on Linux, 43 * per-CPU TSS segments. Threads are completely 'soft' on Linux,
@@ -172,6 +173,73 @@ int set_tsc_mode(unsigned int val)
172 return 0; 173 return 0;
173} 174}
174 175
176DEFINE_PER_CPU(u64, msr_misc_features_shadow);
177
178static void set_cpuid_faulting(bool on)
179{
180 u64 msrval;
181
182 msrval = this_cpu_read(msr_misc_features_shadow);
183 msrval &= ~MSR_MISC_FEATURES_ENABLES_CPUID_FAULT;
184 msrval |= (on << MSR_MISC_FEATURES_ENABLES_CPUID_FAULT_BIT);
185 this_cpu_write(msr_misc_features_shadow, msrval);
186 wrmsrl(MSR_MISC_FEATURES_ENABLES, msrval);
187}
188
189static void disable_cpuid(void)
190{
191 preempt_disable();
192 if (!test_and_set_thread_flag(TIF_NOCPUID)) {
193 /*
194 * Must flip the CPU state synchronously with
195 * TIF_NOCPUID in the current running context.
196 */
197 set_cpuid_faulting(true);
198 }
199 preempt_enable();
200}
201
202static void enable_cpuid(void)
203{
204 preempt_disable();
205 if (test_and_clear_thread_flag(TIF_NOCPUID)) {
206 /*
207 * Must flip the CPU state synchronously with
208 * TIF_NOCPUID in the current running context.
209 */
210 set_cpuid_faulting(false);
211 }
212 preempt_enable();
213}
214
215static int get_cpuid_mode(void)
216{
217 return !test_thread_flag(TIF_NOCPUID);
218}
219
220static int set_cpuid_mode(struct task_struct *task, unsigned long cpuid_enabled)
221{
222 if (!static_cpu_has(X86_FEATURE_CPUID_FAULT))
223 return -ENODEV;
224
225 if (cpuid_enabled)
226 enable_cpuid();
227 else
228 disable_cpuid();
229
230 return 0;
231}
232
233/*
234 * Called immediately after a successful exec.
235 */
236void arch_setup_new_exec(void)
237{
238 /* If cpuid was previously disabled for this task, re-enable it. */
239 if (test_thread_flag(TIF_NOCPUID))
240 enable_cpuid();
241}
242
175static inline void switch_to_bitmap(struct tss_struct *tss, 243static inline void switch_to_bitmap(struct tss_struct *tss,
176 struct thread_struct *prev, 244 struct thread_struct *prev,
177 struct thread_struct *next, 245 struct thread_struct *next,
@@ -225,6 +293,9 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
225 293
226 if ((tifp ^ tifn) & _TIF_NOTSC) 294 if ((tifp ^ tifn) & _TIF_NOTSC)
227 cr4_toggle_bits(X86_CR4_TSD); 295 cr4_toggle_bits(X86_CR4_TSD);
296
297 if ((tifp ^ tifn) & _TIF_NOCPUID)
298 set_cpuid_faulting(!!(tifn & _TIF_NOCPUID));
228} 299}
229 300
230/* 301/*
@@ -549,5 +620,12 @@ out:
549long do_arch_prctl_common(struct task_struct *task, int option, 620long do_arch_prctl_common(struct task_struct *task, int option,
550 unsigned long cpuid_enabled) 621 unsigned long cpuid_enabled)
551{ 622{
623 switch (option) {
624 case ARCH_GET_CPUID:
625 return get_cpuid_mode();
626 case ARCH_SET_CPUID:
627 return set_cpuid_mode(task, cpuid_enabled);
628 }
629
552 return -EINVAL; 630 return -EINVAL;
553} 631}