1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _LINUX_CONTEXT_TRACKING_H 3 #define _LINUX_CONTEXT_TRACKING_H 4 5 #include <linux/sched.h> 6 #include <linux/vtime.h> 7 #include <linux/context_tracking_state.h> 8 #include <linux/instrumentation.h> 9 10 #include <asm/ptrace.h> 11 12 13 #ifdef CONFIG_CONTEXT_TRACKING 14 extern void ct_cpu_track_user(int cpu); 15 16 /* Called with interrupts disabled. */ 17 extern void __ct_user_enter(enum ctx_state state); 18 extern void __ct_user_exit(enum ctx_state state); 19 20 extern void ct_user_enter(enum ctx_state state); 21 extern void ct_user_exit(enum ctx_state state); 22 23 extern void user_enter_callable(void); 24 extern void user_exit_callable(void); 25 26 static inline void user_enter(void) 27 { 28 if (context_tracking_enabled()) 29 ct_user_enter(CONTEXT_USER); 30 31 } 32 static inline void user_exit(void) 33 { 34 if (context_tracking_enabled()) 35 ct_user_exit(CONTEXT_USER); 36 } 37 38 /* Called with interrupts disabled. */ 39 static __always_inline void user_enter_irqoff(void) 40 { 41 if (context_tracking_enabled()) 42 __ct_user_enter(CONTEXT_USER); 43 44 } 45 static __always_inline void user_exit_irqoff(void) 46 { 47 if (context_tracking_enabled()) 48 __ct_user_exit(CONTEXT_USER); 49 } 50 51 static inline enum ctx_state exception_enter(void) 52 { 53 enum ctx_state prev_ctx; 54 55 if (IS_ENABLED(CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK) || 56 !context_tracking_enabled()) 57 return 0; 58 59 prev_ctx = this_cpu_read(context_tracking.state); 60 if (prev_ctx != CONTEXT_KERNEL) 61 ct_user_exit(prev_ctx); 62 63 return prev_ctx; 64 } 65 66 static inline void exception_exit(enum ctx_state prev_ctx) 67 { 68 if (!IS_ENABLED(CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK) && 69 context_tracking_enabled()) { 70 if (prev_ctx != CONTEXT_KERNEL) 71 ct_user_enter(prev_ctx); 72 } 73 } 74 75 static __always_inline bool context_tracking_guest_enter(void) 76 { 77 if (context_tracking_enabled()) 78 __ct_user_enter(CONTEXT_GUEST); 79 80 return context_tracking_enabled_this_cpu(); 81 } 82 83 static __always_inline void context_tracking_guest_exit(void) 84 { 85 if (context_tracking_enabled()) 86 __ct_user_exit(CONTEXT_GUEST); 87 } 88 89 /** 90 * ct_state() - return the current context tracking state if known 91 * 92 * Returns the current cpu's context tracking state if context tracking 93 * is enabled. If context tracking is disabled, returns 94 * CONTEXT_DISABLED. This should be used primarily for debugging. 95 */ 96 static __always_inline enum ctx_state ct_state(void) 97 { 98 return context_tracking_enabled() ? 99 this_cpu_read(context_tracking.state) : CONTEXT_DISABLED; 100 } 101 #else 102 static inline void user_enter(void) { } 103 static inline void user_exit(void) { } 104 static inline void user_enter_irqoff(void) { } 105 static inline void user_exit_irqoff(void) { } 106 static inline enum ctx_state exception_enter(void) { return 0; } 107 static inline void exception_exit(enum ctx_state prev_ctx) { } 108 static inline enum ctx_state ct_state(void) { return CONTEXT_DISABLED; } 109 static __always_inline bool context_tracking_guest_enter(void) { return false; } 110 static inline void context_tracking_guest_exit(void) { } 111 112 #endif /* !CONFIG_CONTEXT_TRACKING */ 113 114 #define CT_WARN_ON(cond) WARN_ON(context_tracking_enabled() && (cond)) 115 116 #ifdef CONFIG_CONTEXT_TRACKING_FORCE 117 extern void context_tracking_init(void); 118 #else 119 static inline void context_tracking_init(void) { } 120 #endif /* CONFIG_CONTEXT_TRACKING_FORCE */ 121 122 #endif 123