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