Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _ASM_X86_SWITCH_TO_H
0003 #define _ASM_X86_SWITCH_TO_H
0004 
0005 #include <linux/sched/task_stack.h>
0006 
0007 struct task_struct; /* one of the stranger aspects of C forward declarations */
0008 
0009 struct task_struct *__switch_to_asm(struct task_struct *prev,
0010                     struct task_struct *next);
0011 
0012 __visible struct task_struct *__switch_to(struct task_struct *prev,
0013                       struct task_struct *next);
0014 
0015 asmlinkage void ret_from_fork(void);
0016 
0017 /*
0018  * This is the structure pointed to by thread.sp for an inactive task.  The
0019  * order of the fields must match the code in __switch_to_asm().
0020  */
0021 struct inactive_task_frame {
0022 #ifdef CONFIG_X86_64
0023     unsigned long r15;
0024     unsigned long r14;
0025     unsigned long r13;
0026     unsigned long r12;
0027 #else
0028     unsigned long flags;
0029     unsigned long si;
0030     unsigned long di;
0031 #endif
0032     unsigned long bx;
0033 
0034     /*
0035      * These two fields must be together.  They form a stack frame header,
0036      * needed by get_frame_pointer().
0037      */
0038     unsigned long bp;
0039     unsigned long ret_addr;
0040 };
0041 
0042 struct fork_frame {
0043     struct inactive_task_frame frame;
0044     struct pt_regs regs;
0045 };
0046 
0047 #define switch_to(prev, next, last)                 \
0048 do {                                    \
0049     ((last) = __switch_to_asm((prev), (next)));         \
0050 } while (0)
0051 
0052 #ifdef CONFIG_X86_32
0053 static inline void refresh_sysenter_cs(struct thread_struct *thread)
0054 {
0055     /* Only happens when SEP is enabled, no need to test "SEP"arately: */
0056     if (unlikely(this_cpu_read(cpu_tss_rw.x86_tss.ss1) == thread->sysenter_cs))
0057         return;
0058 
0059     this_cpu_write(cpu_tss_rw.x86_tss.ss1, thread->sysenter_cs);
0060     wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
0061 }
0062 #endif
0063 
0064 /* This is used when switching tasks or entering/exiting vm86 mode. */
0065 static inline void update_task_stack(struct task_struct *task)
0066 {
0067     /* sp0 always points to the entry trampoline stack, which is constant: */
0068 #ifdef CONFIG_X86_32
0069     if (static_cpu_has(X86_FEATURE_XENPV))
0070         load_sp0(task->thread.sp0);
0071     else
0072         this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
0073 #else
0074     /* Xen PV enters the kernel on the thread stack. */
0075     if (static_cpu_has(X86_FEATURE_XENPV))
0076         load_sp0(task_top_of_stack(task));
0077 #endif
0078 }
0079 
0080 static inline void kthread_frame_init(struct inactive_task_frame *frame,
0081                       int (*fun)(void *), void *arg)
0082 {
0083     frame->bx = (unsigned long)fun;
0084 #ifdef CONFIG_X86_32
0085     frame->di = (unsigned long)arg;
0086 #else
0087     frame->r12 = (unsigned long)arg;
0088 #endif
0089 }
0090 
0091 #endif /* _ASM_X86_SWITCH_TO_H */