blob: 8854eadb2142737a7cb332664bf26f0645a27a76 [file] [log] [blame]
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +01001#ifndef _LINUX_CONTEXT_TRACKING_H
2#define _LINUX_CONTEXT_TRACKING_H
3
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +01004#include <linux/sched.h>
Frederic Weisbecker95a79fd2013-01-07 18:12:14 +01005#include <linux/percpu.h>
Frederic Weisbecker521921b2013-05-16 01:21:38 +02006#include <linux/vtime.h>
Frederic Weisbecker65f382f2013-07-11 19:12:32 +02007#include <linux/static_key.h>
Frederic Weisbecker56dd9472013-02-24 00:23:25 +01008#include <asm/ptrace.h>
Frederic Weisbecker95a79fd2013-01-07 18:12:14 +01009
10struct context_tracking {
11 /*
12 * When active is false, probes are unset in order
13 * to minimize overhead: TIF flags are cleared
14 * and calls to user_enter/exit are ignored. This
15 * may be further optimized using static keys.
16 */
17 bool active;
Frederic Weisbecker6c1e0252013-02-24 01:19:14 +010018 enum ctx_state {
Frederic Weisbecker95a79fd2013-01-07 18:12:14 +010019 IN_KERNEL = 0,
20 IN_USER,
21 } state;
22};
23
Frederic Weisbecker521921b2013-05-16 01:21:38 +020024
Frederic Weisbecker6c1e0252013-02-24 01:19:14 +010025#ifdef CONFIG_CONTEXT_TRACKING
Frederic Weisbecker65f382f2013-07-11 19:12:32 +020026extern struct static_key context_tracking_enabled;
Frederic Weisbecker95a79fd2013-01-07 18:12:14 +010027DECLARE_PER_CPU(struct context_tracking, context_tracking);
28
29static inline bool context_tracking_in_user(void)
30{
31 return __this_cpu_read(context_tracking.state) == IN_USER;
32}
33
34static inline bool context_tracking_active(void)
35{
36 return __this_cpu_read(context_tracking.active);
37}
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +010038
Frederic Weisbecker2e709332013-07-10 00:55:25 +020039extern void context_tracking_cpu_set(int cpu);
40
Frederic Weisbeckerad657822013-07-10 02:44:35 +020041extern void context_tracking_user_enter(void);
42extern void context_tracking_user_exit(void);
43
44static inline void user_enter(void)
45{
46 if (static_key_false(&context_tracking_enabled))
47 context_tracking_user_enter();
48
49}
50static inline void user_exit(void)
51{
52 if (static_key_false(&context_tracking_enabled))
53 context_tracking_user_exit();
54}
Frederic Weisbecker56dd9472013-02-24 00:23:25 +010055
Frederic Weisbecker6c1e0252013-02-24 01:19:14 +010056static inline enum ctx_state exception_enter(void)
Frederic Weisbecker56dd9472013-02-24 00:23:25 +010057{
Frederic Weisbecker6c1e0252013-02-24 01:19:14 +010058 enum ctx_state prev_ctx;
59
Frederic Weisbeckerad657822013-07-10 02:44:35 +020060 if (!static_key_false(&context_tracking_enabled))
61 return 0;
62
Frederic Weisbecker6c1e0252013-02-24 01:19:14 +010063 prev_ctx = this_cpu_read(context_tracking.state);
Frederic Weisbeckerad657822013-07-10 02:44:35 +020064 context_tracking_user_exit();
Frederic Weisbecker6c1e0252013-02-24 01:19:14 +010065
66 return prev_ctx;
Frederic Weisbecker56dd9472013-02-24 00:23:25 +010067}
68
Frederic Weisbecker6c1e0252013-02-24 01:19:14 +010069static inline void exception_exit(enum ctx_state prev_ctx)
Frederic Weisbecker56dd9472013-02-24 00:23:25 +010070{
Frederic Weisbeckerad657822013-07-10 02:44:35 +020071 if (static_key_false(&context_tracking_enabled)) {
72 if (prev_ctx == IN_USER)
73 context_tracking_user_enter();
74 }
Frederic Weisbecker56dd9472013-02-24 00:23:25 +010075}
76
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +010077extern void context_tracking_task_switch(struct task_struct *prev,
78 struct task_struct *next);
79#else
Frederic Weisbecker95a79fd2013-01-07 18:12:14 +010080static inline bool context_tracking_in_user(void) { return false; }
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +010081static inline void user_enter(void) { }
82static inline void user_exit(void) { }
Frederic Weisbecker6c1e0252013-02-24 01:19:14 +010083static inline enum ctx_state exception_enter(void) { return 0; }
84static inline void exception_exit(enum ctx_state prev_ctx) { }
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +010085static inline void context_tracking_task_switch(struct task_struct *prev,
86 struct task_struct *next) { }
87#endif /* !CONFIG_CONTEXT_TRACKING */
88
Frederic Weisbecker65f382f2013-07-11 19:12:32 +020089
90#ifdef CONFIG_CONTEXT_TRACKING_FORCE
91extern void context_tracking_init(void);
92#else
93static inline void context_tracking_init(void) { }
94#endif /* CONFIG_CONTEXT_TRACKING_FORCE */
95
96
Frederic Weisbecker2d854e52013-07-12 19:02:30 +020097#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
Frederic Weisbecker48d6a812013-07-10 02:44:35 +020098static inline void guest_enter(void)
99{
100 if (static_key_false(&context_tracking_enabled) &&
101 vtime_accounting_enabled())
102 vtime_guest_enter(current);
103 else
104 current->flags |= PF_VCPU;
105}
106
107static inline void guest_exit(void)
108{
109 if (static_key_false(&context_tracking_enabled) &&
110 vtime_accounting_enabled())
111 vtime_guest_exit(current);
112 else
113 current->flags &= ~PF_VCPU;
114}
Frederic Weisbecker2d854e52013-07-12 19:02:30 +0200115#else
116static inline void guest_enter(void)
117{
118 /*
Frederic Weisbecker5b206d42013-07-12 19:05:14 +0200119 * This is running in ioctl context so its safe
120 * to assume that it's the stime pending cputime
121 * to flush.
Frederic Weisbecker2d854e52013-07-12 19:02:30 +0200122 */
123 vtime_account_system(current);
124 current->flags |= PF_VCPU;
125}
126
127static inline void guest_exit(void)
128{
Frederic Weisbecker5b206d42013-07-12 19:05:14 +0200129 /* Flush the guest cputime we spent on the guest */
Frederic Weisbecker2d854e52013-07-12 19:02:30 +0200130 vtime_account_system(current);
131 current->flags &= ~PF_VCPU;
132}
133#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
134
Frederic Weisbecker91d1aa432012-11-27 19:33:25 +0100135#endif