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