linux/arch/x86/include/asm/switch_to.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _ASM_X86_SWITCH_TO_H
   3#define _ASM_X86_SWITCH_TO_H
   4
   5#include <linux/sched/task_stack.h>
   6
   7struct task_struct; /* one of the stranger aspects of C forward declarations */
   8
   9struct task_struct *__switch_to_asm(struct task_struct *prev,
  10                                    struct task_struct *next);
  11
  12__visible struct task_struct *__switch_to(struct task_struct *prev,
  13                                          struct task_struct *next);
  14struct tss_struct;
  15void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
  16                      struct tss_struct *tss);
  17
  18/* This runs runs on the previous thread's stack. */
  19static inline void prepare_switch_to(struct task_struct *next)
  20{
  21#ifdef CONFIG_VMAP_STACK
  22        /*
  23         * If we switch to a stack that has a top-level paging entry
  24         * that is not present in the current mm, the resulting #PF will
  25         * will be promoted to a double-fault and we'll panic.  Probe
  26         * the new stack now so that vmalloc_fault can fix up the page
  27         * tables if needed.  This can only happen if we use a stack
  28         * in vmap space.
  29         *
  30         * We assume that the stack is aligned so that it never spans
  31         * more than one top-level paging entry.
  32         *
  33         * To minimize cache pollution, just follow the stack pointer.
  34         */
  35        READ_ONCE(*(unsigned char *)next->thread.sp);
  36#endif
  37}
  38
  39asmlinkage void ret_from_fork(void);
  40
  41/*
  42 * This is the structure pointed to by thread.sp for an inactive task.  The
  43 * order of the fields must match the code in __switch_to_asm().
  44 */
  45struct inactive_task_frame {
  46#ifdef CONFIG_X86_64
  47        unsigned long r15;
  48        unsigned long r14;
  49        unsigned long r13;
  50        unsigned long r12;
  51#else
  52        unsigned long si;
  53        unsigned long di;
  54#endif
  55        unsigned long bx;
  56
  57        /*
  58         * These two fields must be together.  They form a stack frame header,
  59         * needed by get_frame_pointer().
  60         */
  61        unsigned long bp;
  62        unsigned long ret_addr;
  63};
  64
  65struct fork_frame {
  66        struct inactive_task_frame frame;
  67        struct pt_regs regs;
  68};
  69
  70#define switch_to(prev, next, last)                                     \
  71do {                                                                    \
  72        prepare_switch_to(next);                                        \
  73                                                                        \
  74        ((last) = __switch_to_asm((prev), (next)));                     \
  75} while (0)
  76
  77#ifdef CONFIG_X86_32
  78static inline void refresh_sysenter_cs(struct thread_struct *thread)
  79{
  80        /* Only happens when SEP is enabled, no need to test "SEP"arately: */
  81        if (unlikely(this_cpu_read(cpu_tss_rw.x86_tss.ss1) == thread->sysenter_cs))
  82                return;
  83
  84        this_cpu_write(cpu_tss_rw.x86_tss.ss1, thread->sysenter_cs);
  85        wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
  86}
  87#endif
  88
  89/* This is used when switching tasks or entering/exiting vm86 mode. */
  90static inline void update_sp0(struct task_struct *task)
  91{
  92        /* On x86_64, sp0 always points to the entry trampoline stack, which is constant: */
  93#ifdef CONFIG_X86_32
  94        load_sp0(task->thread.sp0);
  95#else
  96        if (static_cpu_has(X86_FEATURE_XENPV))
  97                load_sp0(task_top_of_stack(task));
  98#endif
  99}
 100
 101#endif /* _ASM_X86_SWITCH_TO_H */
 102