18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_SWITCH_TO_H
38c2ecf20Sopenharmony_ci#define _ASM_X86_SWITCH_TO_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_cistruct task_struct; /* one of the stranger aspects of C forward declarations */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_cistruct task_struct *__switch_to_asm(struct task_struct *prev,
108c2ecf20Sopenharmony_ci				    struct task_struct *next);
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci__visible struct task_struct *__switch_to(struct task_struct *prev,
138c2ecf20Sopenharmony_ci					  struct task_struct *next);
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciasmlinkage void ret_from_fork(void);
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * This is the structure pointed to by thread.sp for an inactive task.  The
198c2ecf20Sopenharmony_ci * order of the fields must match the code in __switch_to_asm().
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_cistruct inactive_task_frame {
228c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
238c2ecf20Sopenharmony_ci	unsigned long r15;
248c2ecf20Sopenharmony_ci	unsigned long r14;
258c2ecf20Sopenharmony_ci	unsigned long r13;
268c2ecf20Sopenharmony_ci	unsigned long r12;
278c2ecf20Sopenharmony_ci#else
288c2ecf20Sopenharmony_ci	unsigned long flags;
298c2ecf20Sopenharmony_ci	unsigned long si;
308c2ecf20Sopenharmony_ci	unsigned long di;
318c2ecf20Sopenharmony_ci#endif
328c2ecf20Sopenharmony_ci	unsigned long bx;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	/*
358c2ecf20Sopenharmony_ci	 * These two fields must be together.  They form a stack frame header,
368c2ecf20Sopenharmony_ci	 * needed by get_frame_pointer().
378c2ecf20Sopenharmony_ci	 */
388c2ecf20Sopenharmony_ci	unsigned long bp;
398c2ecf20Sopenharmony_ci	unsigned long ret_addr;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct fork_frame {
438c2ecf20Sopenharmony_ci	struct inactive_task_frame frame;
448c2ecf20Sopenharmony_ci	struct pt_regs regs;
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define switch_to(prev, next, last)					\
488c2ecf20Sopenharmony_cido {									\
498c2ecf20Sopenharmony_ci	((last) = __switch_to_asm((prev), (next)));			\
508c2ecf20Sopenharmony_ci} while (0)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
538c2ecf20Sopenharmony_cistatic inline void refresh_sysenter_cs(struct thread_struct *thread)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	/* Only happens when SEP is enabled, no need to test "SEP"arately: */
568c2ecf20Sopenharmony_ci	if (unlikely(this_cpu_read(cpu_tss_rw.x86_tss.ss1) == thread->sysenter_cs))
578c2ecf20Sopenharmony_ci		return;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	this_cpu_write(cpu_tss_rw.x86_tss.ss1, thread->sysenter_cs);
608c2ecf20Sopenharmony_ci	wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci#endif
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/* This is used when switching tasks or entering/exiting vm86 mode. */
658c2ecf20Sopenharmony_cistatic inline void update_task_stack(struct task_struct *task)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	/* sp0 always points to the entry trampoline stack, which is constant: */
688c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
698c2ecf20Sopenharmony_ci	if (static_cpu_has(X86_FEATURE_XENPV))
708c2ecf20Sopenharmony_ci		load_sp0(task->thread.sp0);
718c2ecf20Sopenharmony_ci	else
728c2ecf20Sopenharmony_ci		this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
738c2ecf20Sopenharmony_ci#else
748c2ecf20Sopenharmony_ci	/*
758c2ecf20Sopenharmony_ci	 * x86-64 updates x86_tss.sp1 via cpu_current_top_of_stack. That
768c2ecf20Sopenharmony_ci	 * doesn't work on x86-32 because sp1 and
778c2ecf20Sopenharmony_ci	 * cpu_current_top_of_stack have different values (because of
788c2ecf20Sopenharmony_ci	 * the non-zero stack-padding on 32bit).
798c2ecf20Sopenharmony_ci	 */
808c2ecf20Sopenharmony_ci	if (static_cpu_has(X86_FEATURE_XENPV))
818c2ecf20Sopenharmony_ci		load_sp0(task_top_of_stack(task));
828c2ecf20Sopenharmony_ci#endif
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic inline void kthread_frame_init(struct inactive_task_frame *frame,
868c2ecf20Sopenharmony_ci				      unsigned long fun, unsigned long arg)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	frame->bx = fun;
898c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
908c2ecf20Sopenharmony_ci	frame->di = arg;
918c2ecf20Sopenharmony_ci#else
928c2ecf20Sopenharmony_ci	frame->r12 = arg;
938c2ecf20Sopenharmony_ci#endif
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#endif /* _ASM_X86_SWITCH_TO_H */
97