1/*
2 * PAL Firmware support
3 * IA-64 Processor Programmers Reference Vol 2
4 *
5 * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
6 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
7 * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co
8 *	David Mosberger <davidm@hpl.hp.com>
9 *	Stephane Eranian <eranian@hpl.hp.com>
10 *
11 * 05/22/2000 eranian Added support for stacked register calls
12 * 05/24/2000 eranian Added support for physical mode static calls
13 */
14
15#include <asm/asmmacro.h>
16#include <asm/processor.h>
17
18	.data
19pal_entry_point:
20	data8 ia64_pal_default_handler
21	.text
22
23/*
24 * Set the PAL entry point address.  This could be written in C code, but we
25 * do it here to keep it all in one module (besides, it's so trivial that it's
26 * not a big deal).
27 *
28 * in0		Address of the PAL entry point (text address, NOT a function
29 *		descriptor).
30 */
31GLOBAL_ENTRY(ia64_pal_handler_init)
32	alloc r3=ar.pfs,1,0,0,0
33	movl r2=pal_entry_point
34	;;
35	st8 [r2]=in0
36	br.ret.sptk.many rp
37END(ia64_pal_handler_init)
38
39/*
40 * Default PAL call handler.  This needs to be coded in assembly because it
41 * uses the static calling convention, i.e., the RSE may not be used and
42 * calls are done via "br.cond" (not "br.call").
43 */
44GLOBAL_ENTRY(ia64_pal_default_handler)
45	mov r8=-1
46	br.cond.sptk.many rp
47END(ia64_pal_default_handler)
48
49/*
50 * Make a PAL call using the static calling convention.
51 *
52 * in0         Index of PAL service
53 * in1 - in3   Remaining PAL arguments
54 */
55GLOBAL_ENTRY(ia64_pal_call_static)
56	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
57	alloc loc1 = ar.pfs,4,5,0,0
58	movl loc2 = pal_entry_point
591:	{
60	  mov r28 = in0
61	  mov r29 = in1
62	  mov r8 = ip
63	}
64	;;
65	ld8 loc2 = [loc2]		// loc2 <- entry point
66	adds r8 = 1f-1b,r8
67	mov loc4=ar.rsc			// save RSE configuration
68	;;
69	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
70	mov loc3 = psr
71	mov loc0 = rp
72	.body
73	mov r30 = in2
74
75	mov r31 = in3
76	mov b7 = loc2
77
78	rsm psr.i
79	;;
80	mov rp = r8
81	br.cond.sptk.many b7
821:	mov psr.l = loc3
83	mov ar.rsc = loc4		// restore RSE configuration
84	mov ar.pfs = loc1
85	mov rp = loc0
86	;;
87	srlz.d				// seralize restoration of psr.l
88	br.ret.sptk.many b0
89END(ia64_pal_call_static)
90
91/*
92 * Make a PAL call using the stacked registers calling convention.
93 *
94 * Inputs:
95 *	in0         Index of PAL service
96 *	in2 - in3   Remaining PAL arguments
97 */
98GLOBAL_ENTRY(ia64_pal_call_stacked)
99	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
100	alloc loc1 = ar.pfs,4,4,4,0
101	movl loc2 = pal_entry_point
102
103	mov r28  = in0			// Index MUST be copied to r28
104	mov out0 = in0			// AND in0 of PAL function
105	mov loc0 = rp
106	.body
107	;;
108	ld8 loc2 = [loc2]		// loc2 <- entry point
109	mov out1 = in1
110	mov out2 = in2
111	mov out3 = in3
112	mov loc3 = psr
113	;;
114	rsm psr.i
115	mov b7 = loc2
116	;;
117	br.call.sptk.many rp=b7		// now make the call
118.ret0:	mov psr.l  = loc3
119	mov ar.pfs = loc1
120	mov rp = loc0
121	;;
122	srlz.d				// serialize restoration of psr.l
123	br.ret.sptk.many b0
124END(ia64_pal_call_stacked)
125
126/*
127 * Make a physical mode PAL call using the static registers calling convention.
128 *
129 * Inputs:
130 *	in0         Index of PAL service
131 *	in2 - in3   Remaining PAL arguments
132 *
133 * PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel.
134 * So we don't need to clear them.
135 */
136#define PAL_PSR_BITS_TO_CLEAR						      \
137	(IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT  | IA64_PSR_DB | IA64_PSR_RT |\
138	 IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED |	      \
139	 IA64_PSR_DFL | IA64_PSR_DFH)
140
141#define PAL_PSR_BITS_TO_SET						      \
142	(IA64_PSR_BN)
143
144
145GLOBAL_ENTRY(ia64_pal_call_phys_static)
146	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
147	alloc loc1 = ar.pfs,4,7,0,0
148	movl loc2 = pal_entry_point
1491:	{
150	  mov r28  = in0		// copy procedure index
151	  mov r8   = ip			// save ip to compute branch
152	  mov loc0 = rp			// save rp
153	}
154	.body
155	;;
156	ld8 loc2 = [loc2]		// loc2 <- entry point
157	mov r29  = in1			// first argument
158	mov r30  = in2			// copy arg2
159	mov r31  = in3			// copy arg3
160	;;
161	mov loc3 = psr			// save psr
162	adds r8  = 1f-1b,r8		// calculate return address for call
163	;;
164	mov loc4=ar.rsc			// save RSE configuration
165	dep.z loc2=loc2,0,61		// convert pal entry point to physical
166	tpa r8=r8			// convert rp to physical
167	;;
168	mov b7 = loc2			// install target to branch reg
169	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
170	movl r16=PAL_PSR_BITS_TO_CLEAR
171	movl r17=PAL_PSR_BITS_TO_SET
172	;;
173	or loc3=loc3,r17		// add in psr the bits to set
174	;;
175	andcm r16=loc3,r16		// removes bits to clear from psr
176	br.call.sptk.many rp=ia64_switch_mode_phys
177	mov rp = r8			// install return address (physical)
178	mov loc5 = r19
179	mov loc6 = r20
180	br.cond.sptk.many b7
1811:
182	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
183	mov r16=loc3			// r16= original psr
184	mov r19=loc5
185	mov r20=loc6
186	br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
187	mov psr.l = loc3		// restore init PSR
188
189	mov ar.pfs = loc1
190	mov rp = loc0
191	;;
192	mov ar.rsc=loc4			// restore RSE configuration
193	srlz.d				// seralize restoration of psr.l
194	br.ret.sptk.many b0
195END(ia64_pal_call_phys_static)
196
197/*
198 * Make a PAL call using the stacked registers in physical mode.
199 *
200 * Inputs:
201 *	in0         Index of PAL service
202 *	in2 - in3   Remaining PAL arguments
203 */
204GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
205	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
206	alloc	loc1 = ar.pfs,5,7,4,0
207	movl	loc2 = pal_entry_point
2081:	{
209	  mov r28  = in0		// copy procedure index
210	  mov loc0 = rp			// save rp
211	}
212	.body
213	;;
214	ld8 loc2 = [loc2]		// loc2 <- entry point
215	mov loc3 = psr			// save psr
216	;;
217	mov loc4=ar.rsc			// save RSE configuration
218	dep.z loc2=loc2,0,61		// convert pal entry point to physical
219	;;
220	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
221	movl r16=PAL_PSR_BITS_TO_CLEAR
222	movl r17=PAL_PSR_BITS_TO_SET
223	;;
224	or loc3=loc3,r17		// add in psr the bits to set
225	mov b7 = loc2			// install target to branch reg
226	;;
227	andcm r16=loc3,r16		// removes bits to clear from psr
228	br.call.sptk.many rp=ia64_switch_mode_phys
229
230	mov out0 = in0			// first argument
231	mov out1 = in1			// copy arg2
232	mov out2 = in2			// copy arg3
233	mov out3 = in3			// copy arg3
234	mov loc5 = r19
235	mov loc6 = r20
236
237	br.call.sptk.many rp=b7		// now make the call
238
239	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
240	mov r16=loc3			// r16= original psr
241	mov r19=loc5
242	mov r20=loc6
243	br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
244
245	mov psr.l  = loc3		// restore init PSR
246	mov ar.pfs = loc1
247	mov rp = loc0
248	;;
249	mov ar.rsc=loc4			// restore RSE configuration
250	srlz.d				// seralize restoration of psr.l
251	br.ret.sptk.many b0
252END(ia64_pal_call_phys_stacked)
253
254/*
255 * Save scratch fp scratch regs which aren't saved in pt_regs already
256 * (fp10-fp15).
257 *
258 * NOTE: We need to do this since firmware (SAL and PAL) may use any of the
259 * scratch regs fp-low partition.
260 *
261 * Inputs:
262 *      in0	Address of stack storage for fp regs
263 */
264GLOBAL_ENTRY(ia64_save_scratch_fpregs)
265	alloc r3=ar.pfs,1,0,0,0
266	add r2=16,in0
267	;;
268	stf.spill [in0] = f10,32
269	stf.spill [r2]  = f11,32
270	;;
271	stf.spill [in0] = f12,32
272	stf.spill [r2]  = f13,32
273	;;
274	stf.spill [in0] = f14,32
275	stf.spill [r2]  = f15,32
276	br.ret.sptk.many rp
277END(ia64_save_scratch_fpregs)
278
279/*
280 * Load scratch fp scratch regs (fp10-fp15)
281 *
282 * Inputs:
283 *      in0	Address of stack storage for fp regs
284 */
285GLOBAL_ENTRY(ia64_load_scratch_fpregs)
286	alloc r3=ar.pfs,1,0,0,0
287	add r2=16,in0
288	;;
289	ldf.fill  f10 = [in0],32
290	ldf.fill  f11 = [r2],32
291	;;
292	ldf.fill  f12 = [in0],32
293	ldf.fill  f13 = [r2],32
294	;;
295	ldf.fill  f14 = [in0],32
296	ldf.fill  f15 = [r2],32
297	br.ret.sptk.many rp
298END(ia64_load_scratch_fpregs)
299