linux/include/linux/context_tracking.h
<<
>>
Prefs
   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 <asm/ptrace.h>
   9
  10
  11#ifdef CONFIG_CONTEXT_TRACKING
  12extern void context_tracking_cpu_set(int cpu);
  13
  14/* Called with interrupts disabled.  */
  15extern void __context_tracking_enter(enum ctx_state state);
  16extern void __context_tracking_exit(enum ctx_state state);
  17
  18extern void context_tracking_enter(enum ctx_state state);
  19extern void context_tracking_exit(enum ctx_state state);
  20extern void context_tracking_user_enter(void);
  21extern void context_tracking_user_exit(void);
  22
  23static inline void user_enter(void)
  24{
  25        if (context_tracking_is_enabled())
  26                context_tracking_enter(CONTEXT_USER);
  27
  28}
  29static inline void user_exit(void)
  30{
  31        if (context_tracking_is_enabled())
  32                context_tracking_exit(CONTEXT_USER);
  33}
  34
  35/* Called with interrupts disabled.  */
  36static inline void user_enter_irqoff(void)
  37{
  38        if (context_tracking_is_enabled())
  39                __context_tracking_enter(CONTEXT_USER);
  40
  41}
  42static inline void user_exit_irqoff(void)
  43{
  44        if (context_tracking_is_enabled())
  45                __context_tracking_exit(CONTEXT_USER);
  46}
  47
  48static inline enum ctx_state exception_enter(void)
  49{
  50        enum ctx_state prev_ctx;
  51
  52        if (!context_tracking_is_enabled())
  53                return 0;
  54
  55        prev_ctx = this_cpu_read(context_tracking.state);
  56        if (prev_ctx != CONTEXT_KERNEL)
  57                context_tracking_exit(prev_ctx);
  58
  59        return prev_ctx;
  60}
  61
  62static inline void exception_exit(enum ctx_state prev_ctx)
  63{
  64        if (context_tracking_is_enabled()) {
  65                if (prev_ctx != CONTEXT_KERNEL)
  66                        context_tracking_enter(prev_ctx);
  67        }
  68}
  69
  70
  71/**
  72 * ct_state() - return the current context tracking state if known
  73 *
  74 * Returns the current cpu's context tracking state if context tracking
  75 * is enabled.  If context tracking is disabled, returns
  76 * CONTEXT_DISABLED.  This should be used primarily for debugging.
  77 */
  78static inline enum ctx_state ct_state(void)
  79{
  80        return context_tracking_is_enabled() ?
  81                this_cpu_read(context_tracking.state) : CONTEXT_DISABLED;
  82}
  83#else
  84static inline void user_enter(void) { }
  85static inline void user_exit(void) { }
  86static inline void user_enter_irqoff(void) { }
  87static inline void user_exit_irqoff(void) { }
  88static inline enum ctx_state exception_enter(void) { return 0; }
  89static inline void exception_exit(enum ctx_state prev_ctx) { }
  90static inline enum ctx_state ct_state(void) { return CONTEXT_DISABLED; }
  91#endif /* !CONFIG_CONTEXT_TRACKING */
  92
  93#define CT_WARN_ON(cond) WARN_ON(context_tracking_is_enabled() && (cond))
  94
  95#ifdef CONFIG_CONTEXT_TRACKING_FORCE
  96extern void context_tracking_init(void);
  97#else
  98static inline void context_tracking_init(void) { }
  99#endif /* CONFIG_CONTEXT_TRACKING_FORCE */
 100
 101
 102#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
 103/* must be called with irqs disabled */
 104static inline void guest_enter_irqoff(void)
 105{
 106        if (vtime_accounting_cpu_enabled())
 107                vtime_guest_enter(current);
 108        else
 109                current->flags |= PF_VCPU;
 110
 111        if (context_tracking_is_enabled())
 112                __context_tracking_enter(CONTEXT_GUEST);
 113
 114        /* KVM does not hold any references to rcu protected data when it
 115         * switches CPU into a guest mode. In fact switching to a guest mode
 116         * is very similar to exiting to userspace from rcu point of view. In
 117         * addition CPU may stay in a guest mode for quite a long time (up to
 118         * one time slice). Lets treat guest mode as quiescent state, just like
 119         * we do with user-mode execution.
 120         */
 121        if (!context_tracking_cpu_is_enabled())
 122                rcu_virt_note_context_switch(smp_processor_id());
 123}
 124
 125static inline void guest_exit_irqoff(void)
 126{
 127        if (context_tracking_is_enabled())
 128                __context_tracking_exit(CONTEXT_GUEST);
 129
 130        if (vtime_accounting_cpu_enabled())
 131                vtime_guest_exit(current);
 132        else
 133                current->flags &= ~PF_VCPU;
 134}
 135
 136#else
 137static inline void guest_enter_irqoff(void)
 138{
 139        /*
 140         * This is running in ioctl context so its safe
 141         * to assume that it's the stime pending cputime
 142         * to flush.
 143         */
 144        vtime_account_system(current);
 145        current->flags |= PF_VCPU;
 146        rcu_virt_note_context_switch(smp_processor_id());
 147}
 148
 149static inline void guest_exit_irqoff(void)
 150{
 151        /* Flush the guest cputime we spent on the guest */
 152        vtime_account_system(current);
 153        current->flags &= ~PF_VCPU;
 154}
 155#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
 156
 157static inline void guest_enter(void)
 158{
 159        unsigned long flags;
 160
 161        local_irq_save(flags);
 162        guest_enter_irqoff();
 163        local_irq_restore(flags);
 164}
 165
 166static inline void guest_exit(void)
 167{
 168        unsigned long flags;
 169
 170        local_irq_save(flags);
 171        guest_exit_irqoff();
 172        local_irq_restore(flags);
 173}
 174
 175#endif
 176