aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Bosman <ejbosman@cs.vu.nl>2008-04-13 18:24:18 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-19 13:19:55 -0400
commit529e25f646e08901a6dad5768f681efffd77225e (patch)
treea284d6511b6eef0ab83a3e9ada7a6ae300a33010
parent8fb402bccf203ecca8f9e0202b8fd3c937dece6f (diff)
x86: implement prctl PR_GET_TSC and PR_SET_TSC
This patch implements the PR_GET_TSC and PR_SET_TSC prctl() commands on the x86 platform (both 32 and 64 bit.) These commands control the ability to read the timestamp counter from userspace (the RDTSC instruction.) While the RDTSC instuction is a useful profiling tool, it is also the source of some non-determinism in ring-3. For deterministic replay applications it is useful to be able to trap and emulate (and record the outcome of) this instruction. This patch uses code earlier used to disable the timestamp counter for the SECCOMP framework. A side-effect of this patch is that the SECCOMP environment will now also disable the timestamp counter on x86_64 due to the addition of the TIF_NOTSC define on this platform. The code which enables/disables the RDTSC instruction during context switches is in the __switch_to_xtra function, which already handles other unusual conditions, so normal performance should not have to suffer from this change. Signed-off-by: Erik Bosman <ejbosman@cs.vu.nl> Acked-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/kernel/process_32.c43
-rw-r--r--arch/x86/kernel/process_64.c68
-rw-r--r--include/asm-x86/processor.h7
-rw-r--r--include/asm-x86/thread_info_64.h4
-rw-r--r--include/asm-x86/tsc.h1
5 files changed, 118 insertions, 5 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 91e147b486dd..a3790a3f8a83 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -36,6 +36,7 @@
36#include <linux/personality.h> 36#include <linux/personality.h>
37#include <linux/tick.h> 37#include <linux/tick.h>
38#include <linux/percpu.h> 38#include <linux/percpu.h>
39#include <linux/prctl.h>
39 40
40#include <asm/uaccess.h> 41#include <asm/uaccess.h>
41#include <asm/pgtable.h> 42#include <asm/pgtable.h>
@@ -523,11 +524,11 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
523} 524}
524EXPORT_SYMBOL_GPL(start_thread); 525EXPORT_SYMBOL_GPL(start_thread);
525 526
526#ifdef CONFIG_SECCOMP
527static void hard_disable_TSC(void) 527static void hard_disable_TSC(void)
528{ 528{
529 write_cr4(read_cr4() | X86_CR4_TSD); 529 write_cr4(read_cr4() | X86_CR4_TSD);
530} 530}
531
531void disable_TSC(void) 532void disable_TSC(void)
532{ 533{
533 preempt_disable(); 534 preempt_disable();
@@ -539,11 +540,47 @@ void disable_TSC(void)
539 hard_disable_TSC(); 540 hard_disable_TSC();
540 preempt_enable(); 541 preempt_enable();
541} 542}
543
542static void hard_enable_TSC(void) 544static void hard_enable_TSC(void)
543{ 545{
544 write_cr4(read_cr4() & ~X86_CR4_TSD); 546 write_cr4(read_cr4() & ~X86_CR4_TSD);
545} 547}
546#endif /* CONFIG_SECCOMP */ 548
549void enable_TSC(void)
550{
551 preempt_disable();
552 if (test_and_clear_thread_flag(TIF_NOTSC))
553 /*
554 * Must flip the CPU state synchronously with
555 * TIF_NOTSC in the current running context.
556 */
557 hard_enable_TSC();
558 preempt_enable();
559}
560
561int get_tsc_mode(unsigned long adr)
562{
563 unsigned int val;
564
565 if (test_thread_flag(TIF_NOTSC))
566 val = PR_TSC_SIGSEGV;
567 else
568 val = PR_TSC_ENABLE;
569
570 return put_user(val, (unsigned int __user *)adr);
571}
572
573int set_tsc_mode(unsigned int val)
574{
575 if (val == PR_TSC_SIGSEGV)
576 disable_TSC();
577 else if (val == PR_TSC_ENABLE)
578 enable_TSC();
579 else
580 return -EINVAL;
581
582 return 0;
583}
547 584
548static noinline void 585static noinline void
549__switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, 586__switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
@@ -577,7 +614,6 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
577 set_debugreg(next->debugreg7, 7); 614 set_debugreg(next->debugreg7, 7);
578 } 615 }
579 616
580#ifdef CONFIG_SECCOMP
581 if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ 617 if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^
582 test_tsk_thread_flag(next_p, TIF_NOTSC)) { 618 test_tsk_thread_flag(next_p, TIF_NOTSC)) {
583 /* prev and next are different */ 619 /* prev and next are different */
@@ -586,7 +622,6 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
586 else 622 else
587 hard_enable_TSC(); 623 hard_enable_TSC();
588 } 624 }
589#endif
590 625
591#ifdef X86_BTS 626#ifdef X86_BTS
592 if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS)) 627 if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index e75ccc8a2b87..4c13b1406c70 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -36,6 +36,7 @@
36#include <linux/kprobes.h> 36#include <linux/kprobes.h>
37#include <linux/kdebug.h> 37#include <linux/kdebug.h>
38#include <linux/tick.h> 38#include <linux/tick.h>
39#include <linux/prctl.h>
39 40
40#include <asm/uaccess.h> 41#include <asm/uaccess.h>
41#include <asm/pgtable.h> 42#include <asm/pgtable.h>
@@ -535,6 +536,64 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
535} 536}
536EXPORT_SYMBOL_GPL(start_thread); 537EXPORT_SYMBOL_GPL(start_thread);
537 538
539static void hard_disable_TSC(void)
540{
541 write_cr4(read_cr4() | X86_CR4_TSD);
542}
543
544void disable_TSC(void)
545{
546 preempt_disable();
547 if (!test_and_set_thread_flag(TIF_NOTSC))
548 /*
549 * Must flip the CPU state synchronously with
550 * TIF_NOTSC in the current running context.
551 */
552 hard_disable_TSC();
553 preempt_enable();
554}
555
556static void hard_enable_TSC(void)
557{
558 write_cr4(read_cr4() & ~X86_CR4_TSD);
559}
560
561void enable_TSC(void)
562{
563 preempt_disable();
564 if (test_and_clear_thread_flag(TIF_NOTSC))
565 /*
566 * Must flip the CPU state synchronously with
567 * TIF_NOTSC in the current running context.
568 */
569 hard_enable_TSC();
570 preempt_enable();
571}
572
573int get_tsc_mode(unsigned long adr)
574{
575 unsigned int val;
576
577 if (test_thread_flag(TIF_NOTSC))
578 val = PR_TSC_SIGSEGV;
579 else
580 val = PR_TSC_ENABLE;
581
582 return put_user(val, (unsigned int __user *)adr);
583}
584
585int set_tsc_mode(unsigned int val)
586{
587 if (val == PR_TSC_SIGSEGV)
588 disable_TSC();
589 else if (val == PR_TSC_ENABLE)
590 enable_TSC();
591 else
592 return -EINVAL;
593
594 return 0;
595}
596
538/* 597/*
539 * This special macro can be used to load a debugging register 598 * This special macro can be used to load a debugging register
540 */ 599 */
@@ -572,6 +631,15 @@ static inline void __switch_to_xtra(struct task_struct *prev_p,
572 loaddebug(next, 7); 631 loaddebug(next, 7);
573 } 632 }
574 633
634 if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^
635 test_tsk_thread_flag(next_p, TIF_NOTSC)) {
636 /* prev and next are different */
637 if (test_tsk_thread_flag(next_p, TIF_NOTSC))
638 hard_disable_TSC();
639 else
640 hard_enable_TSC();
641 }
642
575 if (test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { 643 if (test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
576 /* 644 /*
577 * Copy the relevant range of the IO bitmap. 645 * Copy the relevant range of the IO bitmap.
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index 6e26c7c717a2..eaf4548a23d2 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -918,4 +918,11 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip,
918 918
919#define KSTK_EIP(task) (task_pt_regs(task)->ip) 919#define KSTK_EIP(task) (task_pt_regs(task)->ip)
920 920
921/* Get/set a process' ability to use the timestamp counter instruction */
922#define GET_TSC_CTL(adr) get_tsc_mode((adr))
923#define SET_TSC_CTL(val) set_tsc_mode((val))
924
925extern int get_tsc_mode(unsigned long adr);
926extern int set_tsc_mode(unsigned int val);
927
921#endif 928#endif
diff --git a/include/asm-x86/thread_info_64.h b/include/asm-x86/thread_info_64.h
index 1e5c6f6152cd..b17f5f6c2c59 100644
--- a/include/asm-x86/thread_info_64.h
+++ b/include/asm-x86/thread_info_64.h
@@ -126,6 +126,7 @@ static inline struct thread_info *stack_thread_info(void)
126#define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ 126#define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */
127#define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ 127#define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */
128#define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */ 128#define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */
129#define TIF_NOTSC 28 /* TSC is not accessible in userland */
129 130
130#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) 131#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
131#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) 132#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
@@ -147,6 +148,7 @@ static inline struct thread_info *stack_thread_info(void)
147#define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) 148#define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR)
148#define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) 149#define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR)
149#define _TIF_BTS_TRACE_TS (1 << TIF_BTS_TRACE_TS) 150#define _TIF_BTS_TRACE_TS (1 << TIF_BTS_TRACE_TS)
151#define _TIF_NOTSC (1 << TIF_NOTSC)
150 152
151/* work to do on interrupt/exception return */ 153/* work to do on interrupt/exception return */
152#define _TIF_WORK_MASK \ 154#define _TIF_WORK_MASK \
@@ -160,7 +162,7 @@ static inline struct thread_info *stack_thread_info(void)
160 162
161/* flags to check in __switch_to() */ 163/* flags to check in __switch_to() */
162#define _TIF_WORK_CTXSW \ 164#define _TIF_WORK_CTXSW \
163 (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS) 165 (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS|_TIF_NOTSC)
164#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW 166#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW
165#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) 167#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
166 168
diff --git a/include/asm-x86/tsc.h b/include/asm-x86/tsc.h
index d2d8eb5b55f5..0434bd8349a7 100644
--- a/include/asm-x86/tsc.h
+++ b/include/asm-x86/tsc.h
@@ -18,6 +18,7 @@ extern unsigned int cpu_khz;
18extern unsigned int tsc_khz; 18extern unsigned int tsc_khz;
19 19
20extern void disable_TSC(void); 20extern void disable_TSC(void);
21extern void enable_TSC(void);
21 22
22static inline cycles_t get_cycles(void) 23static inline cycles_t get_cycles(void)
23{ 24{