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