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 <linux/export.h> 17#include <asm/asmmacro.h> 18#include <asm/processor.h> 19 20 .data 21pal_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 */ 33GLOBAL_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 39END(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 */ 46GLOBAL_ENTRY(ia64_pal_default_handler) 47 mov r8=-1 48 br.cond.sptk.many rp 49END(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 */ 57GLOBAL_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 611: { 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 841: 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 // serialize restoration of psr.l 90 br.ret.sptk.many b0 91END(ia64_pal_call_static) 92EXPORT_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 */ 101GLOBAL_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 127END(ia64_pal_call_stacked) 128EXPORT_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 149GLOBAL_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 1531: { 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 1851: 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 // serialize restoration of psr.l 198 br.ret.sptk.many b0 199END(ia64_pal_call_phys_static) 200EXPORT_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 */ 209GLOBAL_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 2131: { 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 // serialize restoration of psr.l 256 br.ret.sptk.many b0 257END(ia64_pal_call_phys_stacked) 258EXPORT_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 */ 270GLOBAL_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 283END(ia64_save_scratch_fpregs) 284EXPORT_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 */ 292GLOBAL_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 305END(ia64_load_scratch_fpregs) 306EXPORT_SYMBOL(ia64_load_scratch_fpregs) 307