1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_X86_SWITCH_TO_H 3 #define _ASM_X86_SWITCH_TO_H 4 5 struct task_struct; /* one of the stranger aspects of C forward declarations */ 6 7 struct task_struct *__switch_to_asm(struct task_struct *prev, 8 struct task_struct *next); 9 10 __visible struct task_struct *__switch_to(struct task_struct *prev, 11 struct task_struct *next); 12 struct tss_struct; 13 void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, 14 struct tss_struct *tss); 15 16 /* This runs runs on the previous thread's stack. */ 17 static inline void prepare_switch_to(struct task_struct *prev, 18 struct task_struct *next) 19 { 20 #ifdef CONFIG_VMAP_STACK 21 /* 22 * If we switch to a stack that has a top-level paging entry 23 * that is not present in the current mm, the resulting #PF will 24 * will be promoted to a double-fault and we'll panic. Probe 25 * the new stack now so that vmalloc_fault can fix up the page 26 * tables if needed. This can only happen if we use a stack 27 * in vmap space. 28 * 29 * We assume that the stack is aligned so that it never spans 30 * more than one top-level paging entry. 31 * 32 * To minimize cache pollution, just follow the stack pointer. 33 */ 34 READ_ONCE(*(unsigned char *)next->thread.sp); 35 #endif 36 } 37 38 asmlinkage void ret_from_fork(void); 39 40 /* 41 * This is the structure pointed to by thread.sp for an inactive task. The 42 * order of the fields must match the code in __switch_to_asm(). 43 */ 44 struct inactive_task_frame { 45 #ifdef CONFIG_X86_64 46 unsigned long r15; 47 unsigned long r14; 48 unsigned long r13; 49 unsigned long r12; 50 #else 51 unsigned long si; 52 unsigned long di; 53 #endif 54 unsigned long bx; 55 56 /* 57 * These two fields must be together. They form a stack frame header, 58 * needed by get_frame_pointer(). 59 */ 60 unsigned long bp; 61 unsigned long ret_addr; 62 }; 63 64 struct fork_frame { 65 struct inactive_task_frame frame; 66 struct pt_regs regs; 67 }; 68 69 #define switch_to(prev, next, last) \ 70 do { \ 71 prepare_switch_to(prev, next); \ 72 \ 73 ((last) = __switch_to_asm((prev), (next))); \ 74 } while (0) 75 76 #endif /* _ASM_X86_SWITCH_TO_H */ 77