Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 <asm/asmmacro.h> |
| 17 | #include <asm/processor.h> |
Al Viro | e007c53 | 2016-01-17 01:13:41 -0500 | [diff] [blame] | 18 | #include <asm/export.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | |
| 20 | .data |
| 21 | pal_entry_point: |
| 22 | data8 ia64_pal_default_handler |
| 23 | .text |
| 24 | |
| 25 | /* |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 | * not a big deal). |
| 29 | * |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 30 | * in0 Address of the PAL entry point (text address, NOT a function |
| 31 | * descriptor). |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 32 | */ |
| 33 | GLOBAL_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 |
| 39 | END(ia64_pal_handler_init) |
| 40 | |
| 41 | /* |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 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"). |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 45 | */ |
| 46 | GLOBAL_ENTRY(ia64_pal_default_handler) |
| 47 | mov r8=-1 |
| 48 | br.cond.sptk.many rp |
| 49 | END(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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | */ |
| 57 | GLOBAL_ENTRY(ia64_pal_call_static) |
Bjorn Helgaas | c12fb18 | 2006-10-12 16:20:59 -0600 | [diff] [blame] | 58 | .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4) |
| 59 | alloc loc1 = ar.pfs,4,5,0,0 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | mov r31 = in3 |
| 78 | mov b7 = loc2 |
| 79 | |
Bjorn Helgaas | c12fb18 | 2006-10-12 16:20:59 -0600 | [diff] [blame] | 80 | rsm psr.i |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 | ;; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 | mov rp = r8 |
| 83 | br.cond.sptk.many b7 |
| 84 | 1: mov psr.l = loc3 |
| 85 | mov ar.rsc = loc4 // restore RSE configuration |
| 86 | mov ar.pfs = loc1 |
| 87 | mov rp = loc0 |
| 88 | ;; |
Bhaskar Chowdhury | 4545343 | 2021-04-29 22:53:36 -0700 | [diff] [blame] | 89 | srlz.d // serialize restoration of psr.l |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 | br.ret.sptk.many b0 |
| 91 | END(ia64_pal_call_static) |
Al Viro | e007c53 | 2016-01-17 01:13:41 -0500 | [diff] [blame] | 92 | EXPORT_SYMBOL(ia64_pal_call_static) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 93 | |
| 94 | /* |
| 95 | * Make a PAL call using the stacked registers calling convention. |
| 96 | * |
| 97 | * Inputs: |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 98 | * in0 Index of PAL service |
| 99 | * in2 - in3 Remaining PAL arguments |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | */ |
| 101 | GLOBAL_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 |
| 127 | END(ia64_pal_call_stacked) |
Al Viro | e007c53 | 2016-01-17 01:13:41 -0500 | [diff] [blame] | 128 | EXPORT_SYMBOL(ia64_pal_call_stacked) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | |
| 130 | /* |
| 131 | * Make a physical mode PAL call using the static registers calling convention. |
| 132 | * |
| 133 | * Inputs: |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 134 | * in0 Index of PAL service |
| 135 | * in2 - in3 Remaining PAL arguments |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | */ |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 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 | \ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | IA64_PSR_DFL | IA64_PSR_DFH) |
| 144 | |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 145 | #define PAL_PSR_BITS_TO_SET \ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | (IA64_PSR_BN) |
| 147 | |
| 148 | |
| 149 | GLOBAL_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 |
| 153 | 1: { |
| 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 |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 181 | mov rp = r8 // install return address (physical) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 182 | mov loc5 = r19 |
| 183 | mov loc6 = r20 |
| 184 | br.cond.sptk.many b7 |
| 185 | 1: |
| 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Bhaskar Chowdhury | 4545343 | 2021-04-29 22:53:36 -0700 | [diff] [blame] | 197 | srlz.d // serialize restoration of psr.l |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 198 | br.ret.sptk.many b0 |
| 199 | END(ia64_pal_call_phys_static) |
Al Viro | e007c53 | 2016-01-17 01:13:41 -0500 | [diff] [blame] | 200 | EXPORT_SYMBOL(ia64_pal_call_phys_static) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | |
| 202 | /* |
| 203 | * Make a PAL call using the stacked registers in physical mode. |
| 204 | * |
| 205 | * Inputs: |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 206 | * in0 Index of PAL service |
| 207 | * in2 - in3 Remaining PAL arguments |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 208 | */ |
| 209 | GLOBAL_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 |
| 213 | 1: { |
| 214 | mov r28 = in0 // copy procedure index |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 215 | mov loc0 = rp // save rp |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 216 | } |
| 217 | .body |
| 218 | ;; |
| 219 | ld8 loc2 = [loc2] // loc2 <- entry point |
Zou Nan hai | acb15c8 | 2006-07-26 07:26:51 +0800 | [diff] [blame] | 220 | mov loc3 = psr // save psr |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Zou Nan hai | acb15c8 | 2006-07-26 07:26:51 +0800 | [diff] [blame] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 239 | mov loc5 = r19 |
| 240 | mov loc6 = r20 |
Zou Nan hai | acb15c8 | 2006-07-26 07:26:51 +0800 | [diff] [blame] | 241 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 242 | br.call.sptk.many rp=b7 // now make the call |
Zou Nan hai | acb15c8 | 2006-07-26 07:26:51 +0800 | [diff] [blame] | 243 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 248 | 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] | 249 | |
Zou Nan hai | acb15c8 | 2006-07-26 07:26:51 +0800 | [diff] [blame] | 250 | mov psr.l = loc3 // restore init PSR |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 251 | mov ar.pfs = loc1 |
| 252 | mov rp = loc0 |
| 253 | ;; |
| 254 | mov ar.rsc=loc4 // restore RSE configuration |
Bhaskar Chowdhury | 4545343 | 2021-04-29 22:53:36 -0700 | [diff] [blame] | 255 | srlz.d // serialize restoration of psr.l |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 256 | br.ret.sptk.many b0 |
| 257 | END(ia64_pal_call_phys_stacked) |
Al Viro | e007c53 | 2016-01-17 01:13:41 -0500 | [diff] [blame] | 258 | EXPORT_SYMBOL(ia64_pal_call_phys_stacked) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 259 | |
| 260 | /* |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 261 | * Save scratch fp scratch regs which aren't saved in pt_regs already |
| 262 | * (fp10-fp15). |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 263 | * |
Bjorn Helgaas | 4d5a319 | 2006-10-12 16:21:17 -0600 | [diff] [blame] | 264 | * NOTE: We need to do this since firmware (SAL and PAL) may use any of the |
| 265 | * scratch regs fp-low partition. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 266 | * |
| 267 | * Inputs: |
| 268 | * in0 Address of stack storage for fp regs |
| 269 | */ |
| 270 | GLOBAL_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 |
| 283 | END(ia64_save_scratch_fpregs) |
Al Viro | e007c53 | 2016-01-17 01:13:41 -0500 | [diff] [blame] | 284 | EXPORT_SYMBOL(ia64_save_scratch_fpregs) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 285 | |
| 286 | /* |
| 287 | * Load scratch fp scratch regs (fp10-fp15) |
| 288 | * |
| 289 | * Inputs: |
| 290 | * in0 Address of stack storage for fp regs |
| 291 | */ |
| 292 | GLOBAL_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 |
| 305 | END(ia64_load_scratch_fpregs) |
Al Viro | e007c53 | 2016-01-17 01:13:41 -0500 | [diff] [blame] | 306 | EXPORT_SYMBOL(ia64_load_scratch_fpregs) |