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