wuf.S 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 architecture specific stack validation
  109. * routine. They can be found below...
  110. */
  111. .globl fwin_mmu_patchme
  112. fwin_mmu_patchme: b sun4c_fwin_stackchk
  113. andcc %sp, 0x7, %g0
  114. #define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)
  115. fwin_user_stack_is_bolixed:
  116. /* LOCATION: Window 'W' */
  117. /* Place a pt_regs frame on the kernel stack, save back
  118. * to the trap window and call c-code to deal with this.
  119. */
  120. LOAD_CURRENT(l4, l5)
  121. sethi %hi(STACK_OFFSET), %l5
  122. or %l5, %lo(STACK_OFFSET), %l5
  123. add %l4, %l5, %l5
  124. /* Store globals into pt_regs frame. */
  125. STORE_PT_GLOBALS(l5)
  126. STORE_PT_YREG(l5, g3)
  127. /* Save current in a global while we change windows. */
  128. mov %l4, %curptr
  129. save %g0, %g0, %g0
  130. /* LOCATION: Window 'O' */
  131. rd %psr, %g3 /* Read %psr in live user window */
  132. mov %fp, %g4 /* Save bogus frame pointer. */
  133. save %g0, %g0, %g0
  134. /* LOCATION: Window 'T' */
  135. sethi %hi(STACK_OFFSET), %l5
  136. or %l5, %lo(STACK_OFFSET), %l5
  137. add %curptr, %l5, %sp
  138. /* Build rest of pt_regs. */
  139. STORE_PT_INS(sp)
  140. STORE_PT_PRIV(sp, t_psr, t_pc, t_npc)
  141. /* re-set trap time %wim value */
  142. wr %t_wim, 0x0, %wim
  143. /* Fix users window mask and buffer save count. */
  144. mov 0x1, %g5
  145. sll %g5, %g3, %g5
  146. st %g5, [%curptr + TI_UWINMASK] ! one live user window still
  147. st %g0, [%curptr + TI_W_SAVED] ! no windows in the buffer
  148. wr %t_psr, PSR_ET, %psr ! enable traps
  149. nop
  150. call window_underflow_fault
  151. mov %g4, %o0
  152. b ret_trap_entry
  153. clr %l6
  154. fwin_user_stack_is_ok:
  155. /* LOCATION: Window 'W' */
  156. /* The users stack area is kosher and mapped, load the
  157. * window and fall through to the finish up routine.
  158. */
  159. LOAD_WINDOW(sp)
  160. /* Round and round she goes... */
  161. save %g0, %g0, %g0 /* Save to window 'O' */
  162. save %g0, %g0, %g0 /* Save to window 'T' */
  163. /* Where she'll trap nobody knows... */
  164. /* LOCATION: Window 'T' */
  165. fwin_user_finish_up:
  166. /* LOCATION: Window 'T' */
  167. wr %t_psr, 0x0, %psr
  168. WRITE_PAUSE
  169. jmp %t_pc
  170. rett %t_npc
  171. /* Here come the architecture specific checks for stack.
  172. * mappings. Note that unlike the window overflow handler
  173. * we only need to check whether the user can read from
  174. * the appropriate addresses. Also note that we are in
  175. * an invalid window which will be loaded, and this means
  176. * that until we actually load the window up we are free
  177. * to use any of the local registers contained within.
  178. *
  179. * On success these routine branch to fwin_user_stack_is_ok
  180. * if the area at %sp is user readable and the window still
  181. * needs to be loaded, else fwin_user_finish_up if the
  182. * routine has done the loading itself. On failure (bogus
  183. * user stack) the routine shall branch to the label called
  184. * fwin_user_stack_is_bolixed.
  185. *
  186. * Contrary to the arch-specific window overflow stack
  187. * check routines in wof.S, these routines are free to use
  188. * any of the local registers they want to as this window
  189. * does not belong to anyone at this point, however the
  190. * outs and ins are still verboten as they are part of
  191. * 'someone elses' window possibly.
  192. */
  193. .align 4
  194. sun4c_fwin_stackchk:
  195. /* LOCATION: Window 'W' */
  196. /* Caller did 'andcc %sp, 0x7, %g0' */
  197. be 1f
  198. and %sp, 0xfff, %l0 ! delay slot
  199. b,a fwin_user_stack_is_bolixed
  200. /* See if we have to check the sanity of one page or two */
  201. 1:
  202. add %l0, 0x38, %l0
  203. sra %sp, 29, %l5
  204. add %l5, 0x1, %l5
  205. andncc %l5, 0x1, %g0
  206. be 1f
  207. andncc %l0, 0xff8, %g0
  208. b,a fwin_user_stack_is_bolixed /* %sp is in vma hole, yuck */
  209. 1:
  210. be sun4c_fwin_onepage /* Only one page to check */
  211. lda [%sp] ASI_PTE, %l1
  212. sun4c_fwin_twopages:
  213. add %sp, 0x38, %l0
  214. sra %l0, 29, %l5
  215. add %l5, 0x1, %l5
  216. andncc %l5, 0x1, %g0
  217. be 1f
  218. lda [%l0] ASI_PTE, %l1
  219. b,a fwin_user_stack_is_bolixed /* Second page in vma hole */
  220. 1:
  221. srl %l1, 29, %l1
  222. andcc %l1, 0x4, %g0
  223. bne sun4c_fwin_onepage
  224. lda [%sp] ASI_PTE, %l1
  225. b,a fwin_user_stack_is_bolixed /* Second page has bad perms */
  226. sun4c_fwin_onepage:
  227. srl %l1, 29, %l1
  228. andcc %l1, 0x4, %g0
  229. bne fwin_user_stack_is_ok
  230. nop
  231. /* A page had bad page permissions, losing... */
  232. b,a fwin_user_stack_is_bolixed
  233. .globl srmmu_fwin_stackchk
  234. srmmu_fwin_stackchk:
  235. /* LOCATION: Window 'W' */
  236. /* Caller did 'andcc %sp, 0x7, %g0' */
  237. bne fwin_user_stack_is_bolixed
  238. sethi %hi(PAGE_OFFSET), %l5
  239. /* Check if the users stack is in kernel vma, then our
  240. * trial and error technique below would succeed for
  241. * the 'wrong' reason.
  242. */
  243. mov AC_M_SFSR, %l4
  244. cmp %l5, %sp
  245. bleu fwin_user_stack_is_bolixed
  246. lda [%l4] ASI_M_MMUREGS, %g0 ! clear fault status
  247. /* The technique is, turn off faults on this processor,
  248. * just let the load rip, then check the sfsr to see if
  249. * a fault did occur. Then we turn on fault traps again
  250. * and branch conditionally based upon what happened.
  251. */
  252. lda [%g0] ASI_M_MMUREGS, %l5 ! read mmu-ctrl reg
  253. or %l5, 0x2, %l5 ! turn on no-fault bit
  254. sta %l5, [%g0] ASI_M_MMUREGS ! store it
  255. /* Cross fingers and go for it. */
  256. LOAD_WINDOW(sp)
  257. /* A penny 'saved'... */
  258. save %g0, %g0, %g0
  259. save %g0, %g0, %g0
  260. /* Is a BADTRAP earned... */
  261. /* LOCATION: Window 'T' */
  262. lda [%g0] ASI_M_MMUREGS, %twin_tmp1 ! load mmu-ctrl again
  263. andn %twin_tmp1, 0x2, %twin_tmp1 ! clear no-fault bit
  264. sta %twin_tmp1, [%g0] ASI_M_MMUREGS ! store it
  265. mov AC_M_SFAR, %twin_tmp2
  266. lda [%twin_tmp2] ASI_M_MMUREGS, %g0 ! read fault address
  267. mov AC_M_SFSR, %twin_tmp2
  268. lda [%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2 ! read fault status
  269. andcc %twin_tmp2, 0x2, %g0 ! did fault occur?
  270. bne 1f ! yep, cleanup
  271. nop
  272. wr %t_psr, 0x0, %psr
  273. nop
  274. b fwin_user_finish_up + 0x4
  275. nop
  276. /* Did I ever tell you about my window lobotomy?
  277. * anyways... fwin_user_stack_is_bolixed expects
  278. * to be in window 'W' so make it happy or else
  279. * we watchdog badly.
  280. */
  281. 1:
  282. restore %g0, %g0, %g0
  283. b fwin_user_stack_is_bolixed ! oh well
  284. restore %g0, %g0, %g0