1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright IBM Corp. 1999, 2009
4  *
5  * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
6  */
7 
8 #ifndef __ASM_SWITCH_TO_H
9 #define __ASM_SWITCH_TO_H
10 
11 #include <linux/thread_info.h>
12 #include <asm/fpu/api.h>
13 #include <asm/ptrace.h>
14 #include <asm/guarded_storage.h>
15 
16 extern struct task_struct *__switch_to(void *, void *);
17 extern void update_cr_regs(struct task_struct *task);
18 
save_access_regs(unsigned int * acrs)19 static inline void save_access_regs(unsigned int *acrs)
20 {
21 	typedef struct { int _[NUM_ACRS]; } acrstype;
22 
23 	asm volatile("stam 0,15,%0" : "=Q" (*(acrstype *)acrs));
24 }
25 
restore_access_regs(unsigned int * acrs)26 static inline void restore_access_regs(unsigned int *acrs)
27 {
28 	typedef struct { int _[NUM_ACRS]; } acrstype;
29 
30 	asm volatile("lam 0,15,%0" : : "Q" (*(acrstype *)acrs));
31 }
32 
33 #define switch_to(prev, next, last) do {				\
34 	/* save_fpu_regs() sets the CIF_FPU flag, which enforces	\
35 	 * a restore of the floating point / vector registers as	\
36 	 * soon as the next task returns to user space			\
37 	 */								\
38 	save_fpu_regs();						\
39 	save_access_regs(&prev->thread.acrs[0]);			\
40 	save_ri_cb(prev->thread.ri_cb);					\
41 	save_gs_cb(prev->thread.gs_cb);					\
42 	update_cr_regs(next);						\
43 	restore_access_regs(&next->thread.acrs[0]);			\
44 	restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);		\
45 	restore_gs_cb(next->thread.gs_cb);				\
46 	prev = __switch_to(prev, next);					\
47 } while (0)
48 
49 #endif /* __ASM_SWITCH_TO_H */
50