import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / ia64 / kernel / pal.S
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 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
19 pal_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 do it here
25  * 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 descriptor).
29  */
30 GLOBAL_ENTRY(ia64_pal_handler_init)
31         alloc r3=ar.pfs,1,0,0,0
32         movl r2=pal_entry_point
33         ;;
34         st8 [r2]=in0
35         br.ret.sptk.many rp
36 END(ia64_pal_handler_init)
37
38 /*
39  * Default PAL call handler.  This needs to be coded in assembly because it uses
40  * the static calling convention, i.e., the RSE may not be used and calls are
41  * done via "br.cond" (not "br.call").
42  */
43 GLOBAL_ENTRY(ia64_pal_default_handler)
44         mov r8=-1
45         br.cond.sptk.many rp
46 END(ia64_pal_default_handler)
47
48 /*
49  * Make a PAL call using the static calling convention.
50  *
51  * in0         Index of PAL service
52  * in1 - in3   Remaining PAL arguments
53  * in4         1 ==> clear psr.ic,  0 ==> don't clear psr.ic
54  *
55  */
56 GLOBAL_ENTRY(ia64_pal_call_static)
57         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)
58         alloc loc1 = ar.pfs,6,90,0,0
59         movl loc2 = pal_entry_point
60 1:      {
61           mov r28 = in0
62           mov r29 = in1
63           mov r8 = ip
64         }
65         ;;
66         ld8 loc2 = [loc2]               // loc2 <- entry point
67         tbit.nz p6,p7 = in4, 0
68         adds r8 = 1f-1b,r8
69         ;;
70         mov loc3 = psr
71         mov loc0 = rp
72         .body
73         mov r30 = in2
74
75 (p6)    rsm psr.i | psr.ic
76         mov r31 = in3
77         mov b7 = loc2
78
79 (p7)    rsm psr.i
80         ;;
81 (p6)    srlz.i
82         mov rp = r8
83         br.cond.sptk.many b7
84 1:      mov psr.l = loc3
85         mov ar.pfs = loc1
86         mov rp = loc0
87         ;;
88         srlz.d                          // seralize restoration of psr.l
89         br.ret.sptk.many b0
90 END(ia64_pal_call_static)
91
92 /*
93  * Make a PAL call using the stacked registers calling convention.
94  *
95  * Inputs:
96  *      in0         Index of PAL service
97  *      in2 - in3   Remaning PAL arguments
98  */
99 GLOBAL_ENTRY(ia64_pal_call_stacked)
100         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
101         alloc loc1 = ar.pfs,5,4,87,0
102         movl loc2 = pal_entry_point
103
104         mov r28  = in0                  // Index MUST be copied to r28
105         mov out0 = in0                  // AND in0 of PAL function
106         mov loc0 = rp
107         .body
108         ;;
109         ld8 loc2 = [loc2]               // loc2 <- entry point
110         mov out1 = in1
111         mov out2 = in2
112         mov out3 = in3
113         mov loc3 = psr
114         ;;
115         rsm psr.i
116         mov b7 = loc2
117         ;;
118         br.call.sptk.many rp=b7         // now make the call
119 .ret0:  mov psr.l  = loc3
120         mov ar.pfs = loc1
121         mov rp = loc0
122         ;;
123         srlz.d                          // serialize restoration of psr.l
124         br.ret.sptk.many b0
125 END(ia64_pal_call_stacked)
126
127 /*
128  * Make a physical mode PAL call using the static registers calling convention.
129  *
130  * Inputs:
131  *      in0         Index of PAL service
132  *      in2 - in3   Remaning PAL arguments
133  *
134  * PSR_DB, PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel.
135  * So we don't need to clear them.
136  */
137 #define PAL_PSR_BITS_TO_CLEAR                                           \
138         (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT |         \
139          IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED |        \
140          IA64_PSR_DFL | IA64_PSR_DFH)
141
142 #define PAL_PSR_BITS_TO_SET                                             \
143         (IA64_PSR_BN)
144
145
146 GLOBAL_ENTRY(ia64_pal_call_phys_static)
147         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6)
148         alloc loc1 = ar.pfs,6,90,0,0
149         movl loc2 = pal_entry_point
150 1:      {
151           mov r28  = in0                // copy procedure index
152           mov r8   = ip                 // save ip to compute branch
153           mov loc0 = rp                 // save rp
154         }
155         .body
156         ;;
157         ld8 loc2 = [loc2]               // loc2 <- entry point
158         mov r29  = in1                  // first argument
159         mov r30  = in2                  // copy arg2
160         mov r31  = in3                  // copy arg3
161         ;;
162         mov loc3 = psr                  // save psr
163         adds r8  = 1f-1b,r8             // calculate return address for call
164         ;;
165         mov loc4=ar.rsc                 // save RSE configuration
166         dep.z loc2=loc2,0,61            // convert pal entry point to physical
167         tpa r8=r8                       // convert rp to physical
168         ;;
169         mov b7 = loc2                   // install target to branch reg
170         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
171         movl r16=PAL_PSR_BITS_TO_CLEAR
172         movl r17=PAL_PSR_BITS_TO_SET
173         ;;
174         or loc3=loc3,r17                // add in psr the bits to set
175         ;;
176         andcm r16=loc3,r16              // removes bits to clear from psr
177         br.call.sptk.many rp=ia64_switch_mode_phys
178 .ret1:  mov rp = r8                     // install return address (physical)
179         br.cond.sptk.many b7
180 1:
181         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
182         mov r16=loc3                    // r16= original psr
183         br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
184 .ret2:
185         mov psr.l = loc3                // restore init PSR
186
187         mov ar.pfs = loc1
188         mov rp = loc0
189         ;;
190         mov ar.rsc=loc4                 // restore RSE configuration
191         srlz.d                          // seralize restoration of psr.l
192         br.ret.sptk.many b0
193 END(ia64_pal_call_phys_static)
194
195 /*
196  * Make a PAL call using the stacked registers in physical mode.
197  *
198  * Inputs:
199  *      in0         Index of PAL service
200  *      in2 - in3   Remaning PAL arguments
201  */
202 GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
203         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
204         alloc   loc1 = ar.pfs,5,5,86,0
205         movl    loc2 = pal_entry_point
206 1:      {
207           mov r28  = in0                // copy procedure index
208           mov loc0 = rp         // save rp
209         }
210         .body
211         ;;
212         ld8 loc2 = [loc2]               // loc2 <- entry point
213         mov out0 = in0          // first argument
214         mov out1 = in1          // copy arg2
215         mov out2 = in2          // copy arg3
216         mov out3 = in3          // copy arg3
217         ;;
218         mov loc3 = psr          // save psr
219         ;;
220         mov loc4=ar.rsc                 // save RSE configuration
221         dep.z loc2=loc2,0,61            // convert pal entry point to physical
222         ;;
223         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
224         movl r16=PAL_PSR_BITS_TO_CLEAR
225         movl r17=PAL_PSR_BITS_TO_SET
226         ;;
227         or loc3=loc3,r17                // add in psr the bits to set
228         mov b7 = loc2                   // install target to branch reg
229         ;;
230         andcm r16=loc3,r16              // removes bits to clear from psr
231         br.call.sptk.many rp=ia64_switch_mode_phys
232 .ret6:
233         br.call.sptk.many rp=b7         // now make the call
234 .ret7:
235         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
236         mov r16=loc3                    // r16= original psr
237         br.call.sptk.many rp=ia64_switch_mode_virt      // return to virtual mode
238
239 .ret8:  mov psr.l  = loc3               // restore init PSR
240         mov ar.pfs = loc1
241         mov rp = loc0
242         ;;
243         mov ar.rsc=loc4                 // restore RSE configuration
244         srlz.d                          // seralize restoration of psr.l
245         br.ret.sptk.many b0
246 END(ia64_pal_call_phys_stacked)
247
248 /*
249  * Save scratch fp scratch regs (fp10-fp15)
250  *
251  * NOTE: We need to do this since firmware (SAL or PAL) uses more
252  * scratch fp regs than the Linux kernel does.
253  *
254  * Inputs:
255  *      in0         Address of stack storage for fp regs
256  */
257
258 GLOBAL_ENTRY(ia64_save_scratch_fpregs)
259         alloc r3=ar.pfs,1,0,0,0
260         add r2=16,in0
261         ;;
262         stf.spill [in0] = f10,32
263         stf.spill [r2]  = f11,32
264         ;;
265         stf.spill [in0] = f12,32
266         stf.spill [r2]  = f13,32
267         ;;
268         stf.spill [in0] = f14,32
269         stf.spill [r2]  = f15,32
270         br.ret.sptk.many rp
271 END(ia64_save_scratch_fpregs)
272
273 /*
274  * Load scratch fp scratch regs (fp10-fp15)
275  *
276  * Inputs:
277  *      in0         Address of stack storage for fp regs
278  */
279
280 GLOBAL_ENTRY(ia64_load_scratch_fpregs)
281         alloc r3=ar.pfs,1,0,0,0
282         add r2=16,in0
283         ;;
284         ldf.fill  f10 = [in0],32
285         ldf.fill  f11 = [r2],32
286         ;;
287         ldf.fill  f12 = [in0],32
288         ldf.fill  f13 = [r2],32
289         ;;
290         ldf.fill  f14 = [in0],32
291         ldf.fill  f15 = [r2],32
292         br.ret.sptk.many rp
293 END(ia64_load_scratch_fpregs)