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