|
@@ -37,6 +37,7 @@
|
|
|
#include <asm/vm86.h>
|
|
|
#include <asm/switch_to.h>
|
|
|
#include <asm/desc.h>
|
|
|
+#include <asm/prctl.h>
|
|
|
|
|
|
/*
|
|
|
* per-CPU TSS segments. Threads are completely 'soft' on Linux,
|
|
@@ -172,6 +173,73 @@ int set_tsc_mode(unsigned int val)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+DEFINE_PER_CPU(u64, msr_misc_features_shadow);
|
|
|
+
|
|
|
+static void set_cpuid_faulting(bool on)
|
|
|
+{
|
|
|
+ u64 msrval;
|
|
|
+
|
|
|
+ msrval = this_cpu_read(msr_misc_features_shadow);
|
|
|
+ msrval &= ~MSR_MISC_FEATURES_ENABLES_CPUID_FAULT;
|
|
|
+ msrval |= (on << MSR_MISC_FEATURES_ENABLES_CPUID_FAULT_BIT);
|
|
|
+ this_cpu_write(msr_misc_features_shadow, msrval);
|
|
|
+ wrmsrl(MSR_MISC_FEATURES_ENABLES, msrval);
|
|
|
+}
|
|
|
+
|
|
|
+static void disable_cpuid(void)
|
|
|
+{
|
|
|
+ preempt_disable();
|
|
|
+ if (!test_and_set_thread_flag(TIF_NOCPUID)) {
|
|
|
+ /*
|
|
|
+ * Must flip the CPU state synchronously with
|
|
|
+ * TIF_NOCPUID in the current running context.
|
|
|
+ */
|
|
|
+ set_cpuid_faulting(true);
|
|
|
+ }
|
|
|
+ preempt_enable();
|
|
|
+}
|
|
|
+
|
|
|
+static void enable_cpuid(void)
|
|
|
+{
|
|
|
+ preempt_disable();
|
|
|
+ if (test_and_clear_thread_flag(TIF_NOCPUID)) {
|
|
|
+ /*
|
|
|
+ * Must flip the CPU state synchronously with
|
|
|
+ * TIF_NOCPUID in the current running context.
|
|
|
+ */
|
|
|
+ set_cpuid_faulting(false);
|
|
|
+ }
|
|
|
+ preempt_enable();
|
|
|
+}
|
|
|
+
|
|
|
+static int get_cpuid_mode(void)
|
|
|
+{
|
|
|
+ return !test_thread_flag(TIF_NOCPUID);
|
|
|
+}
|
|
|
+
|
|
|
+static int set_cpuid_mode(struct task_struct *task, unsigned long cpuid_enabled)
|
|
|
+{
|
|
|
+ if (!static_cpu_has(X86_FEATURE_CPUID_FAULT))
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ if (cpuid_enabled)
|
|
|
+ enable_cpuid();
|
|
|
+ else
|
|
|
+ disable_cpuid();
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Called immediately after a successful exec.
|
|
|
+ */
|
|
|
+void arch_setup_new_exec(void)
|
|
|
+{
|
|
|
+ /* If cpuid was previously disabled for this task, re-enable it. */
|
|
|
+ if (test_thread_flag(TIF_NOCPUID))
|
|
|
+ enable_cpuid();
|
|
|
+}
|
|
|
+
|
|
|
static inline void switch_to_bitmap(struct tss_struct *tss,
|
|
|
struct thread_struct *prev,
|
|
|
struct thread_struct *next,
|
|
@@ -225,6 +293,9 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
|
|
|
|
|
|
if ((tifp ^ tifn) & _TIF_NOTSC)
|
|
|
cr4_toggle_bits(X86_CR4_TSD);
|
|
|
+
|
|
|
+ if ((tifp ^ tifn) & _TIF_NOCPUID)
|
|
|
+ set_cpuid_faulting(!!(tifn & _TIF_NOCPUID));
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -549,5 +620,12 @@ out:
|
|
|
long do_arch_prctl_common(struct task_struct *task, int option,
|
|
|
unsigned long cpuid_enabled)
|
|
|
{
|
|
|
+ switch (option) {
|
|
|
+ case ARCH_GET_CPUID:
|
|
|
+ return get_cpuid_mode();
|
|
|
+ case ARCH_SET_CPUID:
|
|
|
+ return set_cpuid_mode(task, cpuid_enabled);
|
|
|
+ }
|
|
|
+
|
|
|
return -EINVAL;
|
|
|
}
|