Loading...
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) |