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