1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef _ASM_X86_SWITCH_TO_H
3*4882a593Smuzhiyun #define _ASM_X86_SWITCH_TO_H
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include <linux/sched/task_stack.h>
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun struct task_struct; /* one of the stranger aspects of C forward declarations */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun struct task_struct *__switch_to_asm(struct task_struct *prev,
10*4882a593Smuzhiyun struct task_struct *next);
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun __visible struct task_struct *__switch_to(struct task_struct *prev,
13*4882a593Smuzhiyun struct task_struct *next);
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun asmlinkage void ret_from_fork(void);
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /*
18*4882a593Smuzhiyun * This is the structure pointed to by thread.sp for an inactive task. The
19*4882a593Smuzhiyun * order of the fields must match the code in __switch_to_asm().
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun struct inactive_task_frame {
22*4882a593Smuzhiyun #ifdef CONFIG_X86_64
23*4882a593Smuzhiyun unsigned long r15;
24*4882a593Smuzhiyun unsigned long r14;
25*4882a593Smuzhiyun unsigned long r13;
26*4882a593Smuzhiyun unsigned long r12;
27*4882a593Smuzhiyun #else
28*4882a593Smuzhiyun unsigned long flags;
29*4882a593Smuzhiyun unsigned long si;
30*4882a593Smuzhiyun unsigned long di;
31*4882a593Smuzhiyun #endif
32*4882a593Smuzhiyun unsigned long bx;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun * These two fields must be together. They form a stack frame header,
36*4882a593Smuzhiyun * needed by get_frame_pointer().
37*4882a593Smuzhiyun */
38*4882a593Smuzhiyun unsigned long bp;
39*4882a593Smuzhiyun unsigned long ret_addr;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun struct fork_frame {
43*4882a593Smuzhiyun struct inactive_task_frame frame;
44*4882a593Smuzhiyun struct pt_regs regs;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define switch_to(prev, next, last) \
48*4882a593Smuzhiyun do { \
49*4882a593Smuzhiyun ((last) = __switch_to_asm((prev), (next))); \
50*4882a593Smuzhiyun } while (0)
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #ifdef CONFIG_X86_32
refresh_sysenter_cs(struct thread_struct * thread)53*4882a593Smuzhiyun static inline void refresh_sysenter_cs(struct thread_struct *thread)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun /* Only happens when SEP is enabled, no need to test "SEP"arately: */
56*4882a593Smuzhiyun if (unlikely(this_cpu_read(cpu_tss_rw.x86_tss.ss1) == thread->sysenter_cs))
57*4882a593Smuzhiyun return;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun this_cpu_write(cpu_tss_rw.x86_tss.ss1, thread->sysenter_cs);
60*4882a593Smuzhiyun wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun #endif
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /* This is used when switching tasks or entering/exiting vm86 mode. */
update_task_stack(struct task_struct * task)65*4882a593Smuzhiyun static inline void update_task_stack(struct task_struct *task)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun /* sp0 always points to the entry trampoline stack, which is constant: */
68*4882a593Smuzhiyun #ifdef CONFIG_X86_32
69*4882a593Smuzhiyun if (static_cpu_has(X86_FEATURE_XENPV))
70*4882a593Smuzhiyun load_sp0(task->thread.sp0);
71*4882a593Smuzhiyun else
72*4882a593Smuzhiyun this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
73*4882a593Smuzhiyun #else
74*4882a593Smuzhiyun /*
75*4882a593Smuzhiyun * x86-64 updates x86_tss.sp1 via cpu_current_top_of_stack. That
76*4882a593Smuzhiyun * doesn't work on x86-32 because sp1 and
77*4882a593Smuzhiyun * cpu_current_top_of_stack have different values (because of
78*4882a593Smuzhiyun * the non-zero stack-padding on 32bit).
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun if (static_cpu_has(X86_FEATURE_XENPV))
81*4882a593Smuzhiyun load_sp0(task_top_of_stack(task));
82*4882a593Smuzhiyun #endif
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
kthread_frame_init(struct inactive_task_frame * frame,unsigned long fun,unsigned long arg)85*4882a593Smuzhiyun static inline void kthread_frame_init(struct inactive_task_frame *frame,
86*4882a593Smuzhiyun unsigned long fun, unsigned long arg)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun frame->bx = fun;
89*4882a593Smuzhiyun #ifdef CONFIG_X86_32
90*4882a593Smuzhiyun frame->di = arg;
91*4882a593Smuzhiyun #else
92*4882a593Smuzhiyun frame->r12 = arg;
93*4882a593Smuzhiyun #endif
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun #endif /* _ASM_X86_SWITCH_TO_H */
97