1/**
2 * @file IA64minstate.h
3 *
4 * @remark Copy of source code from linux kernel
5 * @remark linux/arch/ia64/kernel/minstate.h
6 *
7 */
8
9#include <linux/config.h>
10
11#include "IA64entry.h"
12
13/*
14 * A couple of convenience macros that make writing and reading
15 * SAVE_MIN and SAVE_REST easier.
16 */
17#define rARPR		r31
18#define rCRIFS		r30
19#define rCRIPSR		r29
20#define rCRIIP		r28
21#define rARRSC		r27
22#define rARPFS		r26
23#define rARUNAT		r25
24#define rARRNAT		r24
25#define rARBSPSTORE	r23
26#define rKRBS		r22
27#define rB6		r21
28#define rR1		r20
29
30/*
31 * Here start the source dependent macros.
32 */
33
34/*
35 * For ivt.s we want to access the stack virtually so we dont have
36 * to disable translation on interrupts.
37 */
38#define MINSTATE_START_SAVE_MIN_VIRT					\
39	/* r1 = current (virtual) */					\
40	dep r1=-1, r1, 61, 3;						\
41	/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	\
42(pUser)	mov ar.rsc=0;							\
43	;;								\
44	/* compute base of RBS */					\
45(pUser)	addl rKRBS=IA64_RBS_OFFSET, r1;					\
46(pUser)	mov rARRNAT=ar.rnat;						\
47	/* get sp  */							\
48(pKern) mov r1=sp;							\
49	;;								\
50	/* compute base of memory stack */				\
51(pUser)	addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE, r1;			\
52	/* save ar.bspstore */						\
53(pUser)	mov rARBSPSTORE=ar.bspstore;					\
54	;;								\
55	/* if in kernel mode, use sp (r12) */				\
56(pKern) addl r1=-IA64_PT_REGS_SIZE, r1;					\
57	/* switch to kernel RBS */					\
58(pUser)	mov ar.bspstore=rKRBS;						\
59	;;								\
60(pUser)	mov r18=ar.bsp;							\
61	/* set eager mode, pl 0, little-endian, loadrs=0 */		\
62(pUser)	mov ar.rsc=0x3;
63
64#define MINSTATE_END_SAVE_MIN_VIRT					\
65	/* make `current' a kernel virtual address */			\
66	or r13=r13, r14;						\
67	/* switch back to bank 1 (must be last in insn group) */	\
68	bsw.1;								\
69	;;
70
71/*
72 * For mca_asm.S we want to access the stack physically since the state
73 * is saved before we go virtual and dont want to destroy the iip or ipsr.
74 */
75#define MINSTATE_START_SAVE_MIN_PHYS					\
76(pKern) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE;	\
77	/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */	\
78(pUser)	mov ar.rsc=0;							\
79	/* compute base of register backing store */			\
80(pUser)	addl rKRBS=IA64_RBS_OFFSET, r1;					\
81	;;								\
82(pUser)	mov rARRNAT=ar.rnat;						\
83	/* compute physical addr of sp	*/				\
84(pKern) dep r1=0, sp, 61, 3;						\
85	/* compute base of memory stack */				\
86(pUser)	addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE, r1;			\
87	/* save ar.bspstore */						\
88(pUser)	mov rARBSPSTORE=ar.bspstore;					\
89	/* compute kernel virtual addr of RBS */			\
90(pUser)	dep rKRBS=-1, rKRBS, 61, 3;					\
91	;;								\
92	/* if in kernel mode, use sp (r12) */				\
93(pKern) addl r1=-IA64_PT_REGS_SIZE, r1;					\
94	/* switch to kernel RBS */					\
95(pUser)	mov ar.bspstore=rKRBS;						\
96	;;								\
97(pUser)	mov r18=ar.bsp;							\
98	/* set eager mode, pl 0, little-endian, loadrs=0 */		\
99(pUser)	mov ar.rsc=0x3;
100
101#define MINSTATE_END_SAVE_MIN_PHYS					\
102	/* make sp a kernel virtual address */				\
103	or r12=r12, r14;						\
104	/* make `current' a kernel virtual address */			\
105	or r13=r13, r14;						\
106	;;
107
108#ifdef MINSTATE_VIRT
109# define MINSTATE_START_SAVE_MIN	MINSTATE_START_SAVE_MIN_VIRT
110# define MINSTATE_END_SAVE_MIN		MINSTATE_END_SAVE_MIN_VIRT
111#endif
112
113#ifdef MINSTATE_PHYS
114# define MINSTATE_START_SAVE_MIN	MINSTATE_START_SAVE_MIN_PHYS
115# define MINSTATE_END_SAVE_MIN		MINSTATE_END_SAVE_MIN_PHYS
116#endif
117
118/*
119 * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
120 * the minimum state necessary that allows us to turn psr.ic back
121 * on.
122 *
123 * Assumed state upon entry:
124 *	psr.ic: off
125 *	psr.dt: off
126 *	r31:	contains saved predicates (pr)
127 *
128 * Upon exit, the state is as follows:
129 *	psr.ic: off
130 *	r2 = points to &pt_regs.r16
131 *	r12 = kernel sp (kernel virtual address)
132 *	r13 = points to current task_struct (kernel virtual address)
133 *	p15 = TRUE if psr.i is set in cr.ipsr
134 *	predicate registers (other than p2, p3, and p15), b6, r3, r8, r9,
135 *		r10, r11, r14, r15: preserved
136 *
137 * Note that psr.ic is NOT turned on by this macro.  This is so that
138 * we can pass interruption state as arguments to a handler.
139 */
140#define DO_SAVE_MIN(COVER, SAVE_IFS, EXTRA)				\
141	mov rARRSC=ar.rsc;						\
142	mov rARPFS=ar.pfs;						\
143	mov rR1=r1;							\
144	mov rARUNAT=ar.unat;						\
145	mov rCRIPSR=cr.ipsr;						\
146	/* rB6 = branch reg 6 */			  		\
147	mov rB6=b6;							\
148	mov rCRIIP=cr.iip;						\
149	/* r1 = current (physical) */			  		\
150	mov r1=IA64_KR(CURRENT);					\
151	COVER;								\
152	;;								\
153	invala;								\
154	/* extract psr.cpl */				  		\
155	extr.u r16=rCRIPSR, 32, 2;					\
156	;;								\
157	/* are we in kernel mode already? (psr.cpl==0) */ 		\
158	cmp.eq pKern, pUser=r0, r16;					\
159	/* switch from user to kernel RBS: */				\
160	;;								\
161	SAVE_IFS;							\
162	MINSTATE_START_SAVE_MIN						\
163	;;								\
164	/* initialize first base pointer */	  			\
165	mov r16=r1;							\
166	/* initialize second base pointer */	  			\
167	adds r17=8, r1;							\
168	;;								\
169	st8 [r16]=rCRIPSR, 16;	/* save cr.ipsr */			\
170	st8 [r17]=rCRIIP, 16;	/* save cr.iip */			\
171(pKern)	mov r18=r0;		/* make sure r18 isn't NaT */		\
172	;;								\
173	st8 [r16]=rCRIFS, 16;	/* save cr.ifs */			\
174	st8 [r17]=rARUNAT, 16;	/* save ar.unat */			\
175(pUser)	sub r18=r18, rKRBS;	/* r18=RSE.ndirty*8 */			\
176	;;								\
177	st8 [r16]=rARPFS, 16;	/* save ar.pfs */			\
178	st8 [r17]=rARRSC, 16;	/* save ar.rsc */			\
179	tbit.nz p15, p0=rCRIPSR, IA64_PSR_I_BIT				\
180	;;			/* avoid RAW on r16 & r17 */		\
181(pKern)	adds r16=16, r16;	/* skip over ar_rnat field */		\
182(pKern)	adds r17=16, r17;	/* skip over ar_bspstore field */	\
183(pUser)	st8 [r16]=rARRNAT, 16;	/* save ar.rnat */			\
184(pUser)	st8 [r17]=rARBSPSTORE, 16;	/* save ar.bspstore */		\
185	;;								\
186	st8 [r16]=rARPR, 16;	/* save predicates */			\
187	st8 [r17]=rB6, 16;	/* save b6 */				\
188	/* compute ar.rsc to be used for "loadrs" */			\
189	shl r18=r18, 16;						\
190	;;								\
191	st8 [r16]=r18, 16;	/* save ar.rsc value for "loadrs" */	\
192	st8.spill [r17]=rR1, 16;	/* save original r1 */		\
193	;;								\
194.mem.offset 0, 0;	st8.spill [r16]=r2, 16;				\
195.mem.offset 8, 0;	st8.spill [r17]=r3, 16;				\
196	adds r2=IA64_PT_REGS_R16_OFFSET, r1;				\
197	;;								\
198.mem.offset 0, 0;		st8.spill [r16]=r12, 16;		\
199.mem.offset 8, 0;		st8.spill [r17]=r13, 16;		\
200	/* initialize pSys=0, pNonSys=1 */			  	\
201	cmp.eq pNonSys, pSys=r0, r0					\
202	;;								\
203.mem.offset 0, 0;		st8.spill [r16]=r14, 16;		\
204.mem.offset 8, 0;		st8.spill [r17]=r15, 16;		\
205	dep r14=-1, r0, 61, 3;						\
206	;;								\
207.mem.offset 0, 0;		st8.spill [r16]=r8, 16;			\
208.mem.offset 8, 0;		st8.spill [r17]=r9, 16;			\
209	/* switch to kernel memory stack (with 16 bytes of scratch) */	\
210	adds r12=-16, r1;						\
211	;;								\
212.mem.offset 0, 0;		st8.spill [r16]=r10, 16;		\
213.mem.offset 8, 0;		st8.spill [r17]=r11, 16;		\
214	mov r13=IA64_KR(CURRENT);	/* establish `current' */	\
215	;;								\
216	EXTRA;								\
217	movl r1=__gp;		/* establish kernel global pointer */	\
218	;;								\
219	MINSTATE_END_SAVE_MIN
220
221/*
222 * SAVE_REST saves the remainder of pt_regs (with psr.ic on).  This
223 * macro guarantees to preserve all predicate registers, r8, r9, r10,
224 * r11, r14, and r15.
225 *
226 * Assumed state upon entry:
227 *	psr.ic: on
228 *	psr.dt: on
229 *	r2:	points to &pt_regs.r16
230 *	r3:	points to &pt_regs.r17
231 */
232#define SAVE_REST				\
233.mem.offset 0, 0;	st8.spill [r2]=r16, 16;	\
234.mem.offset 8, 0;	st8.spill [r3]=r17, 16;	\
235	;;					\
236.mem.offset 0, 0;	st8.spill [r2]=r18, 16;	\
237.mem.offset 8, 0;	st8.spill [r3]=r19, 16;	\
238	;;					\
239	mov r16=ar.ccv;		/* M-unit */	\
240	movl r18=FPSR_DEFAULT	/* L-unit */	\
241	;;					\
242	mov r17=ar.fpsr;	/* M-unit */	\
243	mov ar.fpsr=r18;	/* M-unit */	\
244	;;					\
245.mem.offset 0, 0;	st8.spill [r2]=r20, 16;	\
246.mem.offset 8, 0;	st8.spill [r3]=r21, 16;	\
247	mov r18=b0;				\
248	;;					\
249.mem.offset 0, 0;	st8.spill [r2]=r22, 16;	\
250.mem.offset 8, 0;	st8.spill [r3]=r23, 16;	\
251	mov r19=b7;				\
252	;;					\
253.mem.offset 0, 0;	st8.spill [r2]=r24, 16;	\
254.mem.offset 8, 0;	st8.spill [r3]=r25, 16;	\
255	;;					\
256.mem.offset 0, 0;	st8.spill [r2]=r26, 16;	\
257.mem.offset 8, 0;	st8.spill [r3]=r27, 16;	\
258	;;					\
259.mem.offset 0, 0;	st8.spill [r2]=r28, 16;	\
260.mem.offset 8, 0;	st8.spill [r3]=r29, 16;	\
261	;;					\
262.mem.offset 0, 0;	st8.spill [r2]=r30, 16;	\
263.mem.offset 8, 0;	st8.spill [r3]=r31, 16;	\
264	;;					\
265	st8 [r2]=r16, 16;	/* ar.ccv */	\
266	st8 [r3]=r17, 16;	/* ar.fpsr */	\
267	;;					\
268	st8 [r2]=r18, 16;	/* b0 */	\
269	st8 [r3]=r19, 16+8;	/* b7 */	\
270	;;					\
271	stf.spill [r2]=f6, 32;			\
272	stf.spill [r3]=f7, 32;			\
273	;;					\
274	stf.spill [r2]=f8, 32;			\
275	stf.spill [r3]=f9, 32
276
277#define SAVE_MIN_WITH_COVER	DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,)
278#define SAVE_MIN_WITH_COVER_R19	\
279	DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19)
280#define SAVE_MIN		DO_SAVE_MIN(, mov rCRIFS=r0,)
281