fedora core 6 1.2949 + vserver 2.2.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
26  * do it here 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
30  *              descriptor).
31  */
32 GLOBAL_ENTRY(ia64_pal_handler_init)
33         alloc r3=ar.pfs,1,0,0,0
34         movl r2=pal_entry_point
35         ;;
36         st8 [r2]=in0
37         br.ret.sptk.many rp
38 END(ia64_pal_handler_init)
39
40 /*
41  * Default PAL call handler.  This needs to be coded in assembly because it
42  * uses the static calling convention, i.e., the RSE may not be used and
43  * calls are done via "br.cond" (not "br.call").
44  */
45 GLOBAL_ENTRY(ia64_pal_default_handler)
46         mov r8=-1
47         br.cond.sptk.many rp
48 END(ia64_pal_default_handler)
49
50 /*
51  * Make a PAL call using the static calling convention.
52  *
53  * in0         Index of PAL service
54  * in1 - in3   Remaining PAL arguments
55  */
56 GLOBAL_ENTRY(ia64_pal_call_static)
57         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
58         alloc loc1 = ar.pfs,4,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         adds r8 = 1f-1b,r8
68         mov loc4=ar.rsc                 // save RSE configuration
69         ;;
70         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
71         mov loc3 = psr
72         mov loc0 = rp
73         .body
74         mov r30 = in2
75
76         mov r31 = in3
77         mov b7 = loc2
78
79         rsm psr.i
80         ;;
81         mov rp = r8
82         br.cond.sptk.many b7
83 1:      mov psr.l = loc3
84         mov ar.rsc = loc4               // restore RSE configuration
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   Remaining PAL arguments
98  */
99 GLOBAL_ENTRY(ia64_pal_call_stacked)
100         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
101         alloc loc1 = ar.pfs,4,4,4,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   Remaining PAL arguments
133  *
134  * 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_DB | 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(4)
148         alloc loc1 = ar.pfs,4,7,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         mov rp = r8                     // install return address (physical)
179         mov loc5 = r19
180         mov loc6 = r20
181         br.cond.sptk.many b7
182 1:
183         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
184         mov r16=loc3                    // r16= original psr
185         mov r19=loc5
186         mov r20=loc6
187         br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
188         mov psr.l = loc3                // restore init PSR
189
190         mov ar.pfs = loc1
191         mov rp = loc0
192         ;;
193         mov ar.rsc=loc4                 // restore RSE configuration
194         srlz.d                          // seralize restoration of psr.l
195         br.ret.sptk.many b0
196 END(ia64_pal_call_phys_static)
197
198 /*
199  * Make a PAL call using the stacked registers in physical mode.
200  *
201  * Inputs:
202  *      in0         Index of PAL service
203  *      in2 - in3   Remaining PAL arguments
204  */
205 GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
206         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
207         alloc   loc1 = ar.pfs,5,7,4,0
208         movl    loc2 = pal_entry_point
209 1:      {
210           mov r28  = in0                // copy procedure index
211           mov loc0 = rp                 // save rp
212         }
213         .body
214         ;;
215         ld8 loc2 = [loc2]               // loc2 <- entry point
216         mov loc3 = psr                  // save psr
217         ;;
218         mov loc4=ar.rsc                 // save RSE configuration
219         dep.z loc2=loc2,0,61            // convert pal entry point to physical
220         ;;
221         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
222         movl r16=PAL_PSR_BITS_TO_CLEAR
223         movl r17=PAL_PSR_BITS_TO_SET
224         ;;
225         or loc3=loc3,r17                // add in psr the bits to set
226         mov b7 = loc2                   // install target to branch reg
227         ;;
228         andcm r16=loc3,r16              // removes bits to clear from psr
229         br.call.sptk.many rp=ia64_switch_mode_phys
230
231         mov out0 = in0                  // first argument
232         mov out1 = in1                  // copy arg2
233         mov out2 = in2                  // copy arg3
234         mov out3 = in3                  // copy arg3
235         mov loc5 = r19
236         mov loc6 = r20
237
238         br.call.sptk.many rp=b7         // now make the call
239
240         mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
241         mov r16=loc3                    // r16= original psr
242         mov r19=loc5
243         mov r20=loc6
244         br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
245
246         mov psr.l  = loc3               // restore init PSR
247         mov ar.pfs = loc1
248         mov rp = loc0
249         ;;
250         mov ar.rsc=loc4                 // restore RSE configuration
251         srlz.d                          // seralize restoration of psr.l
252         br.ret.sptk.many b0
253 END(ia64_pal_call_phys_stacked)
254
255 /*
256  * Save scratch fp scratch regs which aren't saved in pt_regs already
257  * (fp10-fp15).
258  *
259  * NOTE: We need to do this since firmware (SAL and PAL) may use any of the
260  * scratch regs fp-low partition.
261  *
262  * Inputs:
263  *      in0     Address of stack storage for fp regs
264  */
265 GLOBAL_ENTRY(ia64_save_scratch_fpregs)
266         alloc r3=ar.pfs,1,0,0,0
267         add r2=16,in0
268         ;;
269         stf.spill [in0] = f10,32
270         stf.spill [r2]  = f11,32
271         ;;
272         stf.spill [in0] = f12,32
273         stf.spill [r2]  = f13,32
274         ;;
275         stf.spill [in0] = f14,32
276         stf.spill [r2]  = f15,32
277         br.ret.sptk.many rp
278 END(ia64_save_scratch_fpregs)
279
280 /*
281  * Load scratch fp scratch regs (fp10-fp15)
282  *
283  * Inputs:
284  *      in0     Address of stack storage for fp regs
285  */
286 GLOBAL_ENTRY(ia64_load_scratch_fpregs)
287         alloc r3=ar.pfs,1,0,0,0
288         add r2=16,in0
289         ;;
290         ldf.fill  f10 = [in0],32
291         ldf.fill  f11 = [r2],32
292         ;;
293         ldf.fill  f12 = [in0],32
294         ldf.fill  f13 = [r2],32
295         ;;
296         ldf.fill  f14 = [in0],32
297         ldf.fill  f15 = [r2],32
298         br.ret.sptk.many rp
299 END(ia64_load_scratch_fpregs)