xref: /OK3568_Linux_fs/kernel/arch/x86/include/asm/switch_to.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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