pal.S 7.7 KB

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