Linux-libre 4.14.44-gnu
[librecmc/linux-libre.git] / arch / ia64 / kernel / pal.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * PAL Firmware support
4  * IA-64 Processor Programmers Reference Vol 2
5  *
6  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
7  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
8  * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co
9  *      David Mosberger <davidm@hpl.hp.com>
10  *      Stephane Eranian <eranian@hpl.hp.com>
11  *
12  * 05/22/2000 eranian Added support for stacked register calls
13  * 05/24/2000 eranian Added support for physical mode static calls
14  */
15
16 #include <asm/asmmacro.h>
17 #include <asm/processor.h>
18 #include <asm/export.h>
19
20         .data
21 pal_entry_point:
22         data8 ia64_pal_default_handler
23         .text
24
25 /*
26  * Set the PAL entry point address.  This could be written in C code, but we
27  * do it here to keep it all in one module (besides, it's so trivial that it's
28  * not a big deal).
29  *
30  * in0          Address of the PAL entry point (text address, NOT a function
31  *              descriptor).
32  */
33 GLOBAL_ENTRY(ia64_pal_handler_init)
34         alloc r3=ar.pfs,1,0,0,0
35         movl r2=pal_entry_point
36         ;;
37         st8 [r2]=in0
38         br.ret.sptk.many rp
39 END(ia64_pal_handler_init)
40
41 /*
42  * Default PAL call handler.  This needs to be coded in assembly because it
43  * uses the static calling convention, i.e., the RSE may not be used and
44  * calls are done via "br.cond" (not "br.call").
45  */
46 GLOBAL_ENTRY(ia64_pal_default_handler)
47         mov r8=-1
48         br.cond.sptk.many rp
49 END(ia64_pal_default_handler)
50
51 /*
52  * Make a PAL call using the static calling convention.
53  *
54  * in0         Index of PAL service
55  * in1 - in3   Remaining PAL arguments
56  */
57 GLOBAL_ENTRY(ia64_pal_call_static)
58         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
59         alloc loc1 = ar.pfs,4,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         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         mov r31 = in3
78         mov b7 = loc2
79
80         rsm psr.i
81         ;;
82         mov rp = r8
83         br.cond.sptk.many b7
84 1:      mov psr.l = loc3
85         mov ar.rsc = loc4               // restore RSE configuration
86         mov ar.pfs = loc1
87         mov rp = loc0
88         ;;
89         srlz.d                          // seralize restoration of psr.l
90         br.ret.sptk.many b0
91 END(ia64_pal_call_static)
92 EXPORT_SYMBOL(ia64_pal_call_static)
93
94 /*
95  * Make a PAL call using the stacked registers calling convention.
96  *
97  * Inputs:
98  *      in0         Index of PAL service
99  *      in2 - in3   Remaining PAL arguments
100  */
101 GLOBAL_ENTRY(ia64_pal_call_stacked)
102         .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
103         alloc loc1 = ar.pfs,4,4,4,0
104         movl loc2 = pal_entry_point
105
106         mov r28  = in0                  // Index MUST be copied to r28
107         mov out0 = in0                  // AND in0 of PAL function
108         mov loc0 = rp
109         .body
110         ;;
111         ld8 loc2 = [loc2]               // loc2 <- entry point
112         mov out1 = in1
113         mov out2 = in2
114         mov out3 = in3
115         mov loc3 = psr
116         ;;
117         rsm psr.i
118         mov b7 = loc2
119         ;;
120         br.call.sptk.many rp=b7         // now make the call
121 .ret0:  mov psr.l  = loc3
122         mov ar.pfs = loc1
123         mov rp = loc0
124         ;;
125         srlz.d                          // serialize restoration of psr.l
126         br.ret.sptk.many b0
127 END(ia64_pal_call_stacked)
128 EXPORT_SYMBOL(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   Remaining 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         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         mov psr.l = loc3                // restore init PSR
192
193         mov ar.pfs = loc1
194         mov rp = loc0
195         ;;
196         mov ar.rsc=loc4                 // restore RSE configuration
197         srlz.d                          // seralize restoration of psr.l
198         br.ret.sptk.many b0
199 END(ia64_pal_call_phys_static)
200 EXPORT_SYMBOL(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   Remaining 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 EXPORT_SYMBOL(ia64_pal_call_phys_stacked)
259
260 /*
261  * Save scratch fp scratch regs which aren't saved in pt_regs already
262  * (fp10-fp15).
263  *
264  * NOTE: We need to do this since firmware (SAL and PAL) may use any of the
265  * scratch regs fp-low partition.
266  *
267  * Inputs:
268  *      in0     Address of stack storage for fp regs
269  */
270 GLOBAL_ENTRY(ia64_save_scratch_fpregs)
271         alloc r3=ar.pfs,1,0,0,0
272         add r2=16,in0
273         ;;
274         stf.spill [in0] = f10,32
275         stf.spill [r2]  = f11,32
276         ;;
277         stf.spill [in0] = f12,32
278         stf.spill [r2]  = f13,32
279         ;;
280         stf.spill [in0] = f14,32
281         stf.spill [r2]  = f15,32
282         br.ret.sptk.many rp
283 END(ia64_save_scratch_fpregs)
284 EXPORT_SYMBOL(ia64_save_scratch_fpregs)
285
286 /*
287  * Load scratch fp scratch regs (fp10-fp15)
288  *
289  * Inputs:
290  *      in0     Address of stack storage for fp regs
291  */
292 GLOBAL_ENTRY(ia64_load_scratch_fpregs)
293         alloc r3=ar.pfs,1,0,0,0
294         add r2=16,in0
295         ;;
296         ldf.fill  f10 = [in0],32
297         ldf.fill  f11 = [r2],32
298         ;;
299         ldf.fill  f12 = [in0],32
300         ldf.fill  f13 = [r2],32
301         ;;
302         ldf.fill  f14 = [in0],32
303         ldf.fill  f15 = [r2],32
304         br.ret.sptk.many rp
305 END(ia64_load_scratch_fpregs)
306 EXPORT_SYMBOL(ia64_load_scratch_fpregs)