wuf.S 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * wuf.S: Window underflow trap handler for the Sparc.
  4. *
  5. * Copyright (C) 1995 David S. Miller
  6. */
  7. #include <asm/contregs.h>
  8. #include <asm/page.h>
  9. #include <asm/ptrace.h>
  10. #include <asm/psr.h>
  11. #include <asm/smp.h>
  12. #include <asm/asi.h>
  13. #include <asm/winmacro.h>
  14. #include <asm/asmmacro.h>
  15. #include <asm/thread_info.h>
  16. /* Just like the overflow handler we define macros for registers
  17. * with fixed meanings in this routine.
  18. */
  19. #define t_psr l0
  20. #define t_pc l1
  21. #define t_npc l2
  22. #define t_wim l3
  23. /* Don't touch the above registers or else you die horribly... */
  24. /* Now macros for the available scratch registers in this routine. */
  25. #define twin_tmp1 l4
  26. #define twin_tmp2 l5
  27. #define curptr g6
  28. .text
  29. .align 4
  30. /* The trap entry point has executed the following:
  31. *
  32. * rd %psr, %l0
  33. * rd %wim, %l3
  34. * b fill_window_entry
  35. * andcc %l0, PSR_PS, %g0
  36. */
  37. /* Datum current_thread_info->uwinmask contains at all times a bitmask
  38. * where if any user windows are active, at least one bit will
  39. * be set in to mask. If no user windows are active, the bitmask
  40. * will be all zeroes.
  41. */
  42. /* To get an idea of what has just happened to cause this
  43. * trap take a look at this diagram:
  44. *
  45. * 1 2 3 4 <-- Window number
  46. * ----------
  47. * T O W I <-- Symbolic name
  48. *
  49. * O == the window that execution was in when
  50. * the restore was attempted
  51. *
  52. * T == the trap itself has save'd us into this
  53. * window
  54. *
  55. * W == this window is the one which is now invalid
  56. * and must be made valid plus loaded from the
  57. * stack
  58. *
  59. * I == this window will be the invalid one when we
  60. * are done and return from trap if successful
  61. */
  62. /* BEGINNING OF PATCH INSTRUCTIONS */
  63. /* On 7-window Sparc the boot code patches fnwin_patch1
  64. * with the following instruction.
  65. */
  66. .globl fnwin_patch1_7win, fnwin_patch2_7win
  67. fnwin_patch1_7win: srl %t_wim, 6, %twin_tmp2
  68. fnwin_patch2_7win: and %twin_tmp1, 0x7f, %twin_tmp1
  69. /* END OF PATCH INSTRUCTIONS */
  70. .globl fill_window_entry, fnwin_patch1, fnwin_patch2
  71. fill_window_entry:
  72. /* LOCATION: Window 'T' */
  73. /* Compute what the new %wim is going to be if we retrieve
  74. * the proper window off of the stack.
  75. */
  76. sll %t_wim, 1, %twin_tmp1
  77. fnwin_patch1: srl %t_wim, 7, %twin_tmp2
  78. or %twin_tmp1, %twin_tmp2, %twin_tmp1
  79. fnwin_patch2: and %twin_tmp1, 0xff, %twin_tmp1
  80. wr %twin_tmp1, 0x0, %wim /* Make window 'I' invalid */
  81. andcc %t_psr, PSR_PS, %g0
  82. be fwin_from_user
  83. restore %g0, %g0, %g0 /* Restore to window 'O' */
  84. /* Trapped from kernel, we trust that the kernel does not
  85. * 'over restore' sorta speak and just grab the window
  86. * from the stack and return. Easy enough.
  87. */
  88. fwin_from_kernel:
  89. /* LOCATION: Window 'O' */
  90. restore %g0, %g0, %g0
  91. /* LOCATION: Window 'W' */
  92. LOAD_WINDOW(sp) /* Load it up */
  93. /* Spin the wheel... */
  94. save %g0, %g0, %g0
  95. save %g0, %g0, %g0
  96. /* I'd like to buy a vowel please... */
  97. /* LOCATION: Window 'T' */
  98. /* Now preserve the condition codes in %psr, pause, and
  99. * return from trap. This is the simplest case of all.
  100. */
  101. wr %t_psr, 0x0, %psr
  102. WRITE_PAUSE
  103. jmp %t_pc
  104. rett %t_npc
  105. fwin_from_user:
  106. /* LOCATION: Window 'O' */
  107. restore %g0, %g0, %g0 /* Restore to window 'W' */
  108. /* LOCATION: Window 'W' */
  109. /* Branch to the stack validation routine */
  110. b srmmu_fwin_stackchk
  111. andcc %sp, 0x7, %g0
  112. #define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)
  113. fwin_user_stack_is_bolixed:
  114. /* LOCATION: Window 'W' */
  115. /* Place a pt_regs frame on the kernel stack, save back
  116. * to the trap window and call c-code to deal with this.
  117. */
  118. LOAD_CURRENT(l4, l5)
  119. sethi %hi(STACK_OFFSET), %l5
  120. or %l5, %lo(STACK_OFFSET), %l5
  121. add %l4, %l5, %l5
  122. /* Store globals into pt_regs frame. */
  123. STORE_PT_GLOBALS(l5)
  124. STORE_PT_YREG(l5, g3)
  125. /* Save current in a global while we change windows. */
  126. mov %l4, %curptr
  127. save %g0, %g0, %g0
  128. /* LOCATION: Window 'O' */
  129. rd %psr, %g3 /* Read %psr in live user window */
  130. mov %fp, %g4 /* Save bogus frame pointer. */
  131. save %g0, %g0, %g0
  132. /* LOCATION: Window 'T' */
  133. sethi %hi(STACK_OFFSET), %l5
  134. or %l5, %lo(STACK_OFFSET), %l5
  135. add %curptr, %l5, %sp
  136. /* Build rest of pt_regs. */
  137. STORE_PT_INS(sp)
  138. STORE_PT_PRIV(sp, t_psr, t_pc, t_npc)
  139. /* re-set trap time %wim value */
  140. wr %t_wim, 0x0, %wim
  141. /* Fix users window mask and buffer save count. */
  142. mov 0x1, %g5
  143. sll %g5, %g3, %g5
  144. st %g5, [%curptr + TI_UWINMASK] ! one live user window still
  145. st %g0, [%curptr + TI_W_SAVED] ! no windows in the buffer
  146. wr %t_psr, PSR_ET, %psr ! enable traps
  147. nop
  148. call window_underflow_fault
  149. mov %g4, %o0
  150. b ret_trap_entry
  151. clr %l6
  152. fwin_user_stack_is_ok:
  153. /* LOCATION: Window 'W' */
  154. /* The users stack area is kosher and mapped, load the
  155. * window and fall through to the finish up routine.
  156. */
  157. LOAD_WINDOW(sp)
  158. /* Round and round she goes... */
  159. save %g0, %g0, %g0 /* Save to window 'O' */
  160. save %g0, %g0, %g0 /* Save to window 'T' */
  161. /* Where she'll trap nobody knows... */
  162. /* LOCATION: Window 'T' */
  163. fwin_user_finish_up:
  164. /* LOCATION: Window 'T' */
  165. wr %t_psr, 0x0, %psr
  166. WRITE_PAUSE
  167. jmp %t_pc
  168. rett %t_npc
  169. /* Here come the architecture specific checks for stack.
  170. * mappings. Note that unlike the window overflow handler
  171. * we only need to check whether the user can read from
  172. * the appropriate addresses. Also note that we are in
  173. * an invalid window which will be loaded, and this means
  174. * that until we actually load the window up we are free
  175. * to use any of the local registers contained within.
  176. *
  177. * On success these routine branch to fwin_user_stack_is_ok
  178. * if the area at %sp is user readable and the window still
  179. * needs to be loaded, else fwin_user_finish_up if the
  180. * routine has done the loading itself. On failure (bogus
  181. * user stack) the routine shall branch to the label called
  182. * fwin_user_stack_is_bolixed.
  183. *
  184. * Contrary to the arch-specific window overflow stack
  185. * check routines in wof.S, these routines are free to use
  186. * any of the local registers they want to as this window
  187. * does not belong to anyone at this point, however the
  188. * outs and ins are still verboten as they are part of
  189. * 'someone elses' window possibly.
  190. */
  191. .globl srmmu_fwin_stackchk
  192. srmmu_fwin_stackchk:
  193. /* LOCATION: Window 'W' */
  194. /* Caller did 'andcc %sp, 0x7, %g0' */
  195. bne fwin_user_stack_is_bolixed
  196. sethi %hi(PAGE_OFFSET), %l5
  197. /* Check if the users stack is in kernel vma, then our
  198. * trial and error technique below would succeed for
  199. * the 'wrong' reason.
  200. */
  201. mov AC_M_SFSR, %l4
  202. cmp %l5, %sp
  203. bleu fwin_user_stack_is_bolixed
  204. LEON_PI( lda [%l4] ASI_LEON_MMUREGS, %g0) ! clear fault status
  205. SUN_PI_( lda [%l4] ASI_M_MMUREGS, %g0) ! clear fault status
  206. /* The technique is, turn off faults on this processor,
  207. * just let the load rip, then check the sfsr to see if
  208. * a fault did occur. Then we turn on fault traps again
  209. * and branch conditionally based upon what happened.
  210. */
  211. LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %l5) ! read mmu-ctrl reg
  212. SUN_PI_(lda [%g0] ASI_M_MMUREGS, %l5) ! read mmu-ctrl reg
  213. or %l5, 0x2, %l5 ! turn on no-fault bit
  214. LEON_PI(sta %l5, [%g0] ASI_LEON_MMUREGS) ! store it
  215. SUN_PI_(sta %l5, [%g0] ASI_M_MMUREGS) ! store it
  216. /* Cross fingers and go for it. */
  217. LOAD_WINDOW(sp)
  218. /* A penny 'saved'... */
  219. save %g0, %g0, %g0
  220. save %g0, %g0, %g0
  221. /* Is a BADTRAP earned... */
  222. /* LOCATION: Window 'T' */
  223. LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %twin_tmp1) ! load mmu-ctrl again
  224. SUN_PI_(lda [%g0] ASI_M_MMUREGS, %twin_tmp1) ! load mmu-ctrl again
  225. andn %twin_tmp1, 0x2, %twin_tmp1 ! clear no-fault bit
  226. LEON_PI(sta %twin_tmp1, [%g0] ASI_LEON_MMUREGS) ! store it
  227. SUN_PI_(sta %twin_tmp1, [%g0] ASI_M_MMUREGS) ! store it
  228. mov AC_M_SFAR, %twin_tmp2
  229. LEON_PI(lda [%twin_tmp2] ASI_LEON_MMUREGS, %g0) ! read fault address
  230. SUN_PI_(lda [%twin_tmp2] ASI_M_MMUREGS, %g0) ! read fault address
  231. mov AC_M_SFSR, %twin_tmp2
  232. LEON_PI(lda [%twin_tmp2] ASI_LEON_MMUREGS, %twin_tmp2) ! read fault status
  233. SUN_PI_(lda [%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2) ! read fault status
  234. andcc %twin_tmp2, 0x2, %g0 ! did fault occur?
  235. bne 1f ! yep, cleanup
  236. nop
  237. wr %t_psr, 0x0, %psr
  238. nop
  239. b fwin_user_finish_up + 0x4
  240. nop
  241. /* Did I ever tell you about my window lobotomy?
  242. * anyways... fwin_user_stack_is_bolixed expects
  243. * to be in window 'W' so make it happy or else
  244. * we watchdog badly.
  245. */
  246. 1:
  247. restore %g0, %g0, %g0
  248. b fwin_user_stack_is_bolixed ! oh well
  249. restore %g0, %g0, %g0