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