wuf.S 8.4 KB

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